Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WCF Windows服务中的当前OperationContext为空_C#_Wcf_Callback_Operationcontext - Fatal编程技术网

C# WCF Windows服务中的当前OperationContext为空

C# WCF Windows服务中的当前OperationContext为空,c#,wcf,callback,operationcontext,C#,Wcf,Callback,Operationcontext,我正在尝试使用WCF设置发布/订阅系统,其中WCF服务器位于Windows服务中。绑定为net.TCP。该服务向客户机提供了一个“Subscribe”方法,以便客户机可以注册一个回调处理程序来处理将从链接到服务器的DLL引发的事件。在Subscribe方法中,我尝试使用OperationContext.Current.GetCallbackChannel方法获取回调通道。尝试此操作时,OperationContext.Current属性返回NULL 谁能告诉我在什么情况下这个属性会返回null?

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

谁能告诉我在什么情况下这个属性会返回null??我错过了什么安排了吗?我将在下面包括服务代码和接口代码。我正在Visual Studio 2012中使用c#,目标是framework 4.5

服务:

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);
    }
}
}
客户:

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的建议,我对我的项目做了相当大的修改,因为我意识到即使没有连接任何客户端,服务也必须长期运行并持续运行,所以我将其改为singleton。即便如此,我最初的问题仍然存在。SalientBrain要求查看我的配置文件,因此我将在下面包括它以及所有其他相关文件。为了节省空间,我把它去掉了,但我认为我没有去掉任何重要的东西。PulisherService类的Subscribe方法中发生错误。我希望这是我在配置文件中做的蠢事。好的,给你:

配置:

    <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>
WCF服务:

    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();
                }
            }
        }
    }
}
测试表格:

    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 proxy/clientchannel相反),然后对其调用方法,则不存在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<IWcfSubscriberContract>();
callback=OperationContext.Current.GetCallbackChannel();

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

我遇到过这个问题,并且没有任何解决方案有效,最重要的是如果您正在使用

async await 
OperationContext.Current; will be null
我的用法是在任何等待的呼叫之前获得这样的Ip

var clientIpAddress = System.Web.HttpContext.Current?.Request?.UserHostAddress;
在异步服务操作中的第一个WAIT语句之后,OperationContext.Current可能为null,因为方法体的其余部分可能在不同的线程上运行(并且OperationContext不会在线程之间流动)

因此,为了获得它,您可以在任何等待的操作之前编写代码


可能会对某人有所帮助:)

您正在使用nettcpbinding?是否尝试使用其他InstanceContextMode?我一直使用InstanceContextMode.Single和ConcurrencyMode=ConcurrencyMode.Multiple,没有问题。我正在并发字典中存储回调。它允许我将其他客户端引发的事件通知客户端。从上面的代码中我不太清楚-您是否正在客户端中创建服务类型的实例?还是WCF代理/客户端通道?如果您直接创建服务类型的实例,然后对其调用一个方法,那么就不会有OperationContext。Ian,您搞定了!!!我记得写这封信时感觉不对。我一回头看,这是显而易见的。现在我要去和新的龙战斗。如果你要加上这个作为答案,我会把它标为“已回答”。这是正确的答案。当我在客户机中创建服务实例而不是代理实例时,我兴高采烈地在我的服务上调用方法,没有意识到它是错误的服务实例。唯一阻止我的是缺少OperationContext。再次感谢。米兰-你说得对。不幸的是,伊恩在昨天对问题的评论中发现了这一点,我只能将一个答案标记为“已回答”。
 callback = OperationContext.Current.GetCallbackChannel<IWcfSubscriberContract>();
async await 
OperationContext.Current; will be null
var clientIpAddress = System.Web.HttpContext.Current?.Request?.UserHostAddress;