Current OperationContext is null in Windows WCF Service

I am trying to set up a publish / subscribe system using WCF and where the WCF server is located in the windows service. Binding is net.TCP. The service provides the client with the Subscribe method so that the client can register a callback handler for an event that will be generated from the DLL associated with the server. In the Subscribe method, I try to get the callback channel using the OperationContext.Current.GetCallbackChannel method. When I try this, the OperationContext.Current property returns NULL.

Can someone tell me under what circumstances this property will return null? Did I miss something? I will include the service code and interface code below. I am using C # in Visual Studio 2012 and targeting Framework 4.5.

Services:

namespace WService { [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] public class WcfPublisherService : IWcfPublisherContract { IOALogic logic = new OAControlExample(); IWcfSubscriberContract _callback = null; public void Subscribe() { _callback = OperationContext.Current.GetCallbackChannel<IWcfSubscriberContract>(); logic.BarriersChanged += logic_BarriersChanged; } public void UnSubscribe() { logic.BarriersChanged -= logic_BarriersChanged; } void logic_BarriersChanged(object sender, BarriersChangedEventArgs e) { _callback.BarriersChanged(e.BarrierLines); } } } 

Interface:

 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); } } 

Client:

 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 > 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; } } } 

********* New editing *************** Thanks to the proposals of SalientBrain, I made significant changes to my project because I realized that the service should be long and uninterrupted even if none of the clients are connected, so I changed it to a singleton. However, my original problem still persists. SalientBrain asked me to see my configuration file, so I will include it below along with all other relevant files. I stripped it to save space, but I don't think I deleted anything important. An error occurs in the subscription method of the PulisherService class. Hope this is something stupid that I did in the configuration file. Well, here:

Config:

  <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="WService.WCFPublisherServiceBehavior"> <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="WService.WCFPublisherServiceBehavior" name="WService.WcfPublisherService"> <endpoint address="" binding="netTcpBinding" bindingConfiguration="" name="NetTcpBindingEndpoint" contract="WService.IWcfPublisherContract"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" name="MexTcpBindingEndpoint" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="net.tcp://localhost:8523/Publisher" /> </baseAddresses> </host> </service> </services> </system.serviceModel> </configuration> 

WcfContracts:

  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); } } 

WcfService:

  namespace WService { [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] public class WcfPublisherService : IWcfPublisherContract { private static WcfPublisherService _instance = null; private IOALogic _logic = null; private Dictionary<string, IWcfSubscriberContract> _callbacks = new Dictionary<string, IWcfSubscriberContract>(); 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<IWcfSubscriberContract>()); // 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(); } } } } } 

WindowsService:

  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; } } } } 

TestForm:

  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 > 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(); } } } 

TestCallbackClass:

  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; } } } 
+6
source share
5 answers

As discussed in the comments, if you directly create an instance of the service type - unlike the WCF / clientchannel proxy - and then you call the method on it, there is no OperationContext. WCF provides an instance of OperationContext when your operation is performed inside a service.

+18
source

In the client code, no proxies created the factory channel. A service class instance is created as a class library.

You must use the service as shown below.

  ServiceCallback serviceCallback = new ServiceCallback(); InstanceContext instanceContext = new InstanceContext(serviceCallback); var pubsubProxy = new PubSubProxy.WcfPublisherContractClient(instanceContext); pubsubProxy.Subscribe(); 

And when the service is started, an OperationContext is created, and you can access OperationContext.Current

+4
source

I had a similar problem: in my case, when the InstanceContextMode instance was set to Single, WebOperationContext.Current was null in the constructor. However, it was available as part of the services / classes methods.

0
source

In my case, it was me stupid ...

I tried to install

  callback = OperationContext.Current.GetCallbackChannel<IWcfSubscriberContract>(); 

In the CALLBACK function instead of the server-side function ... When in the callback function, it is obvious that there is no current context.

0
source

I ran into this problem and none of the solutions worked, and most importantly, if you use

 async await OperationContext.Current; will be null 

I use to get Ip, so I used it like this before any expected call

 var clientIpAddress = System.Web.HttpContext.Current?.Request?.UserHostAddress; 

After the first await statement in your asynchronous operation, the OperationContext.Current service may be null, because the rest of the method body can be executed on another thread (and the OperationContext is not passed between threads.

So, to get it, you can write your code before any expected action

Maybe this will help someone :)

0
source

All Articles