当前的OperationContext在WCF Windows服务中为null

我正在尝试使用WCF设置发布/订阅系统,并且WCF服务器位于Windows服务中。 绑定是net.TCP。 该服务向客户端提供“订阅”方法,以便客户端可以将回调处理程序注册到将从链接到服务器的DLL引发的事件。 在Subscribe方法中,我尝试使用OperationContext.Current.GetCallbackChannel方法获取回调通道。 当我尝试这个时,OperationContext.Current属性返回NULL。

谁能告诉我在什么情况下这个属性会返回null? 我错过了设置吗? 我将在下面包含服务代码和接口代码。 我在Visual Studio 2012和目标框架4.5中使用c#。

服务:

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

接口:

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

客户:

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

** * ** * ** *新编辑* ** * ** * ** * ** * **感谢SalientBrain的建议,我对我的项目进行了大量修改,因为我意识到服务必须长时间运行即使没有连接客户端也不断运行所以我将其更改为单例。 即便如此,我原来的问题仍然存在。 SalientBrain已经要求查看我的配置文件,因此我将在下面包含它以及所有其他相关文件。 我已经把它剥离以节省空间,但我认为我没有删除任何重要的东西。 在PulisherService类的Subscribe方法中发生错误。 我希望这是我在配置文件中做的愚蠢。 好吧,这是:

配置:

                                

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 _callbacks = new Dictionary(); 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()); // 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; } } } 

正如评论中所讨论的,如果直接创建服务类型的实例 – 而不是WCF代理/客户端通道 – 然后在其上调用方法,则没有OperationContext。 当您的操作在服务中运行时,WCF提供OperationContext实例。

在客户端代码中,代理都没有创建通道工厂。 服务类实例创建为类库。

您应该使用以下代码服务

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

当服务运行时,将创建OperationContext,您可以访问OperationContext.Current

我遇到了类似的问题:在我的情况下,当InstanceContextMode设置为Single时,WebOperationContext.Current在构造函数中为null。 但是它在服务/类方法中可用。

在我的情况下,我是愚蠢的……

我试着设定

  callback = OperationContext.Current.GetCallbackChannel(); 

在CALLBACK函数中,而不是服务器端函数…当处于回调函数时 – 显然没有当前上下文。