WCF服务回调类字段为空

时间:2014-09-10 11:25:50

标签: c# web-services wcf callback

在过去的一年里,我学到了很多关于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
}

1 个答案:

答案 0 :(得分:1)

我想我已经回答了我自己的问题。我基本上有这个服务和两个客户。回调事件似乎被调用,但字段值为空。调试时我确认它正在订阅回调,所以它让我疯了。然后我发现一个客户端的回调被调用,而不是另一个,但事实证明它捕获了回调通道,它在前一个方法完成之前在同一个线程上进行回调...死锁..所以我在一个单独的线程上开始我的连接并注册到事件,而不是启动这个过程的操作调用,现在它似乎有效。