Note that there are some explanatory texts on larger screens.

plurals
  1. POcurrent OperationContext is null in WCF Windows Service
    primarykey
    data
    text
    <p>I am trying to set up a Publish/Subscribe system using WCF and where the WCF server is in a Windows service. The binding is net.TCP. The service is providing a "Subscribe" method to the client so the client can register a callback handler to an event that will be raised from a DLL linked to the server. In the Subscribe method I attempt to get the callback channel using the OperationContext.Current.GetCallbackChannel method. When I attempt this the OperationContext.Current property returns NULL.</p> <p>Can anyone tell me under what circumstances this property would return null?? Have I missed setting something up? I will include the service code and the interface code below. I am using c# in Visual Studio 2012 and targeting framework 4.5.</p> <p>Service:</p> <pre><code>namespace WService { [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] public class WcfPublisherService : IWcfPublisherContract { IOALogic logic = new OAControlExample(); IWcfSubscriberContract _callback = null; public void Subscribe() { _callback = OperationContext.Current.GetCallbackChannel&lt;IWcfSubscriberContract&gt;(); logic.BarriersChanged += logic_BarriersChanged; } public void UnSubscribe() { logic.BarriersChanged -= logic_BarriersChanged; } void logic_BarriersChanged(object sender, BarriersChangedEventArgs e) { _callback.BarriersChanged(e.BarrierLines); } } } </code></pre> <p>Interface:</p> <pre><code>namespace WService { [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IWcfSubscriberContract))] public interface IWcfPublisherContract { [OperationContract(IsOneWay=false, IsInitiating=true)] void Subscribe(); [OperationContract(IsOneWay = false, IsTerminating=true)] void UnSubscribe(); } public interface IWcfSubscriberContract { [OperationContract(IsOneWay = true)] void BarriersChanged(BarrierLines barrierLines); } } </code></pre> <p>Client:</p> <pre><code>namespace TestClient { public partial class Form1 : Form { WcfPublisherService myService = new WcfPublisherService(); ServiceCallback serviceCallback = new ServiceCallback(); public Form1() { InitializeComponent(); serviceCallback.NewMessage += serviceCallback_NewMessage; } private delegate void serviceCallback_NewMessageDelegate(object sender, NewMessageEventArgs e); void serviceCallback_NewMessage(object sender, NewMessageEventArgs e) { if (textBox1.InvokeRequired) { textBox1.Invoke(new serviceCallback_NewMessageDelegate(serviceCallback_NewMessage), new object[] {sender, e}); } else { if (textBox1.Text.Trim().Length &gt; 1) { textBox1.Text += Environment.NewLine; } textBox1.Text += e.Msg; } } private void button1_Click(object sender, EventArgs e) { myService.Subscribe(); } private void button2_Click(object sender, EventArgs e) { myService.UnSubscribe(); } } [CallbackBehaviorAttribute(UseSynchronizationContext = false)] class ServiceCallback : IWcfSubscriberContract { public delegate void NewMessageEventHandler(object sender, NewMessageEventArgs e); public event NewMessageEventHandler NewMessage; protected virtual void OnNewMessage(string msg) { if (NewMessage != null) { NewMessage(this, new NewMessageEventArgs(msg)); } } public void BarriersChanged(OA.BarrierLines barrierLines) { OnNewMessage("new barrier lines"); } } public class NewMessageEventArgs : EventArgs { public NewMessageEventArgs(string msg) { this.Msg = msg; } public string Msg { get; set; } } } </code></pre> <p><em><strong></em>**<em>*</em>**<em>*</em>**<em>*</em></strong> New Edit <strong><em>*</em>**<em>*</em>**<em>*</em>**<em>*</em>**<em>*</em>**</strong> Thanks to SalientBrain's suggestions, I have made considerable changes to my project because I realized the service had to be long running and continually running even if no clients are connected so I changed it to a singleton. Even so, my original problem still persists. SalientBrain has asked to see my config file so I will include it below along with all the other pertinent files. I've stripped it out to conserve space, but I don't think I removed anything important. The error occurs in Subscribe method of the PulisherService class. I hope it is something stupid I did in the config file. Well, here it is:</p> <p>Config:</p> <pre><code> &lt;configuration&gt; &lt;startup&gt; &lt;supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /&gt; &lt;/startup&gt; &lt;system.serviceModel&gt; &lt;behaviors&gt; &lt;serviceBehaviors&gt; &lt;behavior name="WService.WCFPublisherServiceBehavior"&gt; &lt;serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" /&gt; &lt;serviceDebug includeExceptionDetailInFaults="false" /&gt; &lt;/behavior&gt; &lt;/serviceBehaviors&gt; &lt;/behaviors&gt; &lt;services&gt; &lt;service behaviorConfiguration="WService.WCFPublisherServiceBehavior" name="WService.WcfPublisherService"&gt; &lt;endpoint address="" binding="netTcpBinding" bindingConfiguration="" name="NetTcpBindingEndpoint" contract="WService.IWcfPublisherContract"&gt; &lt;identity&gt; &lt;dns value="localhost" /&gt; &lt;/identity&gt; &lt;/endpoint&gt; &lt;endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" name="MexTcpBindingEndpoint" contract="IMetadataExchange" /&gt; &lt;host&gt; &lt;baseAddresses&gt; &lt;add baseAddress="net.tcp://localhost:8523/Publisher" /&gt; &lt;/baseAddresses&gt; &lt;/host&gt; &lt;/service&gt; &lt;/services&gt; &lt;/system.serviceModel&gt; &lt;/configuration&gt; </code></pre> <p>WcfContracts:</p> <pre><code> namespace WService { [ServiceContract(SessionMode = SessionMode.Allowed, CallbackContract = typeof(IWcfSubscriberContract))] public interface IWcfPublisherContract { [OperationContract(IsOneWay=false)] void Subscribe(string key); [OperationContract(IsOneWay = false)] void UnSubscribe(string key); } public interface IWcfSubscriberContract { [OperationContract(IsOneWay = true)] void BarriersChanged(BarrierLines barrierLines); } } </code></pre> <p>WcfService:</p> <pre><code> namespace WService { [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] public class WcfPublisherService : IWcfPublisherContract { private static WcfPublisherService _instance = null; private IOALogic _logic = null; private Dictionary&lt;string, IWcfSubscriberContract&gt; _callbacks = new Dictionary&lt;string, IWcfSubscriberContract&gt;(); private ReaderWriterLock _callbacksLock = new ReaderWriterLock(); private WcfPublisherService() { } public static WcfPublisherService TheInstance() { if (_instance == null) { _instance = new WcfPublisherService(); } return _instance; } public void StopWcf() { _logic.StopRequest(); } public void StartWcf(IOALogic logic) { _logic = logic; _logic.BarriersChanged += logic_BarriersChanged; ThreadPool.QueueUserWorkItem(new WaitCallback(StartWork), null); } public void StartWork(object state) { _logic.Run(); } public void Subscribe(string key) { OperationContext context = OperationContext.Current; // The above line returns null *********************************************** _callbacksLock.AcquireWriterLock(2000); if (_callbacksLock.IsWriterLockHeld) { _callbacks.Add(key, context.GetCallbackChannel&lt;IWcfSubscriberContract&gt;()); // The above line throws a null execption because context is null ******** _callbacksLock.ReleaseWriterLock(); } } public void UnSubscribe(string key) { _callbacksLock.AcquireWriterLock(2000); if (_callbacksLock.IsWriterLockHeld) { _callbacks.Remove(key); _callbacksLock.ReleaseWriterLock(); } } void logic_BarriersChanged(object sender, BarriersChangedEventArgs e) { _callbacksLock.AcquireReaderLock(1000); if (_callbacksLock.IsReaderLockHeld) { try { foreach (IWcfSubscriberContract callback in _callbacks.Values) { callback.BarriersChanged(e.BarrierLines); } } finally { _callbacksLock.ReleaseReaderLock(); } } } } } </code></pre> <p>WindowsService:</p> <pre><code> namespace WService { public partial class WService : ServiceBase { internal static ServiceHost _serviceHost = null; internal static IOALogic _logic = new OAControlExample(); public WService() { InitializeComponent(); } protected override void OnStart(string[] args) { if (_serviceHost != null) { _serviceHost.Close(); } _serviceHost = new ServiceHost(WcfPublisherService.TheInstance()); WcfPublisherService.TheInstance().StartWcf(_logic); _serviceHost.Open(); } protected override void OnStop() { if (WcfPublisherService.TheInstance() != null) { WcfPublisherService.TheInstance().StopWcf(); } if (_serviceHost != null) { _serviceHost.Close(); _serviceHost = null; } } } } </code></pre> <p>TestForm:</p> <pre><code> namespace TestClient { public partial class Form1 : Form { ServiceCallback serviceCallback = new ServiceCallback(); public Form1() { InitializeComponent(); serviceCallback.NewMessage += serviceCallback_NewMessage; } private delegate void serviceCallback_NewMessageDelegate(object sender, NewMessageEventArgs e); void serviceCallback_NewMessage(object sender, NewMessageEventArgs e) { if (textBox1.InvokeRequired) { textBox1.Invoke(new serviceCallback_NewMessageDelegate(serviceCallback_NewMessage), new object[] {sender, e}); } else { if (textBox1.Text.Trim().Length &gt; 1) { textBox1.Text += Environment.NewLine; } textBox1.Text += e.Msg; } } private void button1_Click(object sender, EventArgs e) { serviceCallback.Subscribe(); } private void button2_Click(object sender, EventArgs e) { serviceCallback.Unsubscribe(); } } } </code></pre> <p>TestCallbackClass:</p> <pre><code> namespace TestClient { [CallbackBehaviorAttribute(UseSynchronizationContext = true)] class ServiceCallback : IWcfSubscriberContract { WcfPublisherService myService = WcfPublisherService.TheInstance(); string callbackKey = Guid.NewGuid().ToString(); public delegate void NewMessageEventHandler(object sender, NewMessageEventArgs e); public event NewMessageEventHandler NewMessage; protected virtual void OnNewMessage(string msg) { if (NewMessage != null) { NewMessage(this, new NewMessageEventArgs(msg)); } } public void Subscribe() { try { myService.Subscribe(callbackKey); } catch (Exception ex) { OnNewMessage("exception: " + ex.Message); } } public void Unsubscribe() { try { myService.UnSubscribe(callbackKey); } catch (Exception ex) { OnNewMessage("exception: " + ex.Message); } } public void BarriersChanged(OAInterface.BarrierLines barrierLines) { OnNewMessage("new barrier lines"); } } public class NewMessageEventArgs : EventArgs { public NewMessageEventArgs(string msg) { this.Msg = msg; } public string Msg { get; set; } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload