C# WCF服务回调类字段为空

C# WCF服务回调类字段为空,c#,web-services,wcf,callback,C#,Web Services,Wcf,Callback,在过去的一年里,我学到了很多关于WCF的知识,但由于我不是每天都使用它,我仍然知道它会很危险。我的例子太复杂了,无法说明我的全部问题,我很乐意展示我所拥有的那些你会觉得有用的东西。我有一个双工服务,并构建了一个名为HostedTransactionServiceProcess的类,该类封装了服务调用,因此使用该类的任何客户端级别的类都不必理解使用WCF服务的复杂性。它封装其调用的服务也可以通过回调事件进行通信。问题往往是服务操作和接收回调事件之间的协调。每当服务调用回调事件时,HostedTra

在过去的一年里,我学到了很多关于WCF的知识,但由于我不是每天都使用它,我仍然知道它会很危险。我的例子太复杂了,无法说明我的全部问题,我很乐意展示我所拥有的那些你会觉得有用的东西。我有一个双工服务,并构建了一个名为HostedTransactionServiceProcess的类,该类封装了服务调用,因此使用该类的任何客户端级别的类都不必理解使用WCF服务的复杂性。它封装其调用的服务也可以通过回调事件进行通信。问题往往是服务操作和接收回调事件之间的协调。每当服务调用回调事件时,HostedTransactionServiceProcess的类级别属性/字段值为null。我认为这是有意义的,因为创建从服务到客户端的通道/代理是由服务来完成的,在创建从客户端到服务的通道/代理通信时,我们没有那么多的控制权。因此,如果它实例化其回调代理,那么所有内容都将默认,并且它的值也将保持不变,就好像这些值从未被修改过一样

首先,这是正确的吗? 第二,我如何解决这个问题

我可以通过创建一个可在进程间工作的命名句柄来解决利用EventWaitHandle的需要,但我仍然需要在操作调用和回调事件调用之间查看类中的其他属性/字段数据

同样,我可以根据需要提供更多信息,请告诉我

编辑:我试图把事情简化成一个不可行的类,至少可以说明我的问题。也许这会有帮助

 [CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults = true)]
public class HostedTransactionServiceProcess : ServiceProcess<IHostedTransactionService, HostedTransactionServiceInvoker, ConfigurationDuplexChannelFactory<IHostedTransactionService>>, IHostedTransactionServiceProcess, IHostedTransactionCallbackService
{
    #region Properties

    private ICADSession _cadSession;

    public ICADSession CADSession
    {
        get { return _cadSession; }
        set { _cadSession = value; }
    }


    #endregion
    #region Operations

    public void Commit(ICADSession cadSession, IEnumerable<IDTOEntity> dtoEntityCollection, IDTODocument dtoDocument, IDTOOperationLock operationLock)
    {

        lock (_serviceInvokerLock)
        {
            //Since the callback session will be instantiated by the WCF Service, any fields/properties in this class will be instantiated to null.
            //This is because the Service is instantiating its own instance, creating its own proxy, based on the applied callback interface contract
            //To work around this so that a call to the CAD System can wait until the CAD System responds back through the WCF Service, a named, inter-process
            //EventWaitHandle will be used
            using (EventWaitHandle waitHandle = ServiceWaitHandleHelper.StartNew(false, EventResetMode.AutoReset, cadSession, "Commit"))
            {
                //Set a local value... the issue is that this will end up null when the callback event is called!!!!!
                //This seems to be because this instance making the Commit() call is different from the callback instance created to make the OnCommitted() call!!!
                this.CADSession = cadSession;

                //Make the proxy operation call
                this.ServiceInvoker.Execute(serviceProxy => serviceProxy.Commit(cadSession, dtoEntityCollection, dtoDocument, operationLock));

                //The lock will not be released for the next Commit() operation call until the entire commit process is completed or the operation times out.
                waitHandle.WaitOne(TimeSpan.FromMilliseconds(MAX_OPERATION_TIMEOUT));

            }
        }
    }

    //The WCF Service Callback will call this
    public void OnCommitted(ICADSession cadSession, IEnumerable<IDTOEntity> entityCollection, IDTODocument dtoDocument, IDTOOperationLock operationLock)
    {
        //First allow the Commit() operation to continue
        EventWaitHandle waitHandle = ServiceWaitHandleHelper.GetExisting(cadSession, "Commit");
        if (waitHandle != null && this.CADSession == cadSession)  //!!!!!! Here is the issue!!!  Even though this.CADSession was set to a value, the callback instance says it is null!!!
            waitHandle.Set();
        else
            return;
    }

    #endregion
}
[CallbackBehavior(UseSynchronizationContext=false,ConcurrencyMode=ConcurrencyMode.Multiple,IncludeExceptionDetailInFaults=true)]
公共类HostedTransactionServiceProcess:ServiceProcess、IHostedTransactionServiceProcess、IHostedTransactionCallbackService
{
#区域属性
私人ICAD会议(CADU会议);
公共ICAD会议
{
获取{return\u cadSession;}
设置{u cadSession=value;}
}
#端区
#区域业务
公共无效提交(ICADSession cadSession、IEnumerable dtoEntityCollection、IDTODocument dtoDocument、IDTOOperationLock operationLock)
{
锁(_serviceInvokerLock)
{
//由于回调会话将由WCF服务实例化,因此此类中的任何字段/属性都将实例化为null。
//这是因为服务正在实例化自己的实例,根据应用的回调接口契约创建自己的代理
//解决此问题,以便对CAD系统的调用可以等待,直到CAD系统通过WCF服务(一个命名的跨进程)作出响应
//将使用EventWaitHandle
使用(EventWaitHandle waitHandle=ServiceWaitHandleHelper.StartNew(false,EventResetMode.AutoReset,cadSession,“Commit”))
{
//设置一个本地值…问题是,当调用回调事件时,这将以null结尾!!!!!
//这似乎是因为进行Commit()调用的实例与为进行OnCommitted()调用而创建的回调实例不同!!!
this.CADSession=CADSession;
//进行代理操作调用
执行(serviceProxy=>serviceProxy.Commit(cadSession、dtoEntityCollection、dtoDocument、operationLock));
//在整个提交过程完成或操作超时之前,不会释放下一个Commit()操作调用的锁。
waitHandle.WaitOne(TimeSpan.From毫秒(最大操作超时));
}
}
}
//WCF服务回调将调用此
提交的公共作废(ICAD会话cadSession、IEnumerable entityCollection、IDTODocument数据文档、IDTOOperationLock操作锁)
{
//首先允许Commit()操作继续
EventWaitHandle waitHandle=ServiceWaitHandleHelper.GetExisting(cadSession,“提交”);
如果(waitHandle!=null&&this.CADSession==CADSession)//!!!!!问题就在这里!!!即使this.CADSession被设置为一个值,回调实例也会说它为null!!!
waitHandle.Set();
其他的
返回;
}
#端区
}

我想我已经回答了我自己的问题。我基本上有服务和两个客户。回调事件似乎被调用,但字段值为null。调试时,我验证了它订阅了回调,因此它让我发疯。然后我发现一个客户机的回调被调用了,而另一个客户机没有被调用。结果表明,虽然它捕获了回调通道,但它在前一个方法完成之前进行了回调,而在同一个线程上。。。僵局因此,我在一个单独的线程上开始连接和注册事件,而不是启动此过程的操作调用,现在它似乎可以工作了