2013-01-18 41 views
10

我自我托管的wcf双工回拨服务存在问题。我得到一个InvalidOperationException与消息:防止WCF双工回拨服务造成死锁问题

此操作会死锁,因为答复不能接收 直到当前消息完成处理。如果您希望允许 乱序消息处理,请指定Reentrant的并发模式 或Multiple on CallbackBehaviorAttribute。

这里是我的服务行为:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = true)] 

这里是我的服务合同:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientCallback))] 

[ServiceContract] 
public interface IClientToService 
{ 
    [OperationContract(IsOneWay = false)] 
    LVSSStatus GetLvssStatus(); 

    [OperationContract(IsOneWay = true)] 
    void PickSpecimen(long trackingNumber, int destCode); 

    [OperationContract(IsOneWay = true)] 
    void CancelCurrentPickTransaction(); 
} 

这里是我的回调接口:

public interface ILvssClientCallback 
{ 
    [OperationContract(IsOneWay = true)] 
    void SendClientCallback(LvssCallbackMessage callbackMessage); 

    [OperationContract(IsOneWay = false)] 
    List<SpecimenTemplateDescriptor> GetTemplateDescriptorList(DrawerLayout drawerLayout); 

    [OperationContract(IsOneWay = false)] 
    SpecimenTemplate SelectSpecimenTemplate(string templateName, int version); 

    [OperationContract] 
    void SpecimenStoredInContainer(string containerID, bool isValidRackID, int rackRow, int rackCol, int deckRow, int deckCol, 
    int drawerRow, int drawerCol, long trackingNumber, RobotErrors robotError); 

    [OperationContract] 
    void LvssRobotStatusChange(LVSSStatus status); 
} 

我明白InvalidOperationException是回调操作时引起的on在客户端上调用时,该服务已被锁定以处理当前操作。所以发生死锁。

我已经尝试将我的ConcurrencyMode更改为多个,并将UseSynchronizationContext更改为false。

我仍然看到两个问题,我的服务:

第一:以下服务操作冻结我的客户端的WPF应用程序时GetLvssStatus()迅速调用(通过点击UI按钮,迅速地)。这种方法不是一种方法,并且从服务中同步返回一个枚举类型返回给客户端。

[OperationContract(IsOneWay = false)] 
    LVSSStatus GetLvssStatus(); 

*这是什么导致我的wpf应用程序冻结? *如何防止应用程序冻结? 如果我使用backgroundworker线程作为异步调用,则应用程序不会冻结。我真的需要这种方法同步工作。

二:当我指定回调方法LvssRobotStatusChange到IsOneWay = true,我得到一个的ObjectDisposedException:无法访问已释放的对象。对象名称:'System.ServiceModel.Channels.ServiceChannel'

[OperationContract(IsOneWay = true)] 
    void LvssRobotStatusChange(LVSSStatus status); 

*什么原因导致此ObjectDisposedException? *在这种情况下可以忽略IsOneWay作业吗?在这种情况下省略IsOneWay允许回调在没有任何例外的情况下完成。

*这些问题可能是缺少线程安全代码的结果吗?
*
如果是这样,那么使ConcurrencyMode.Multiple服务行为线程安全的最佳做法是什么?

这些问题的任何帮助,非常感谢。

* FIRST EDIT 有关创建我的双工信道的更多信息。我的wpf视图模型创建了一个负责处理我的频道创建的代理对象。在服务尝试使用回调对象时,到目前为止在我的通道上设置客户端上新线程的任何尝试都会导致ObjectDisposedException。

*第二个编辑 我相信我的服务应该工作,如果我能得到与无效的方法操作合同设置IsOneWay =真。在重入并发的情况下,主通道线程应该允许这些方法通过,而不管任何锁定。
这是我的回调接口:

public interface ILvssClientCallback 
{ 
    [OperationContract(IsOneWay = true)] 
    void SendClientCallback(LvssCallbackMessage callbackMessage); 

    [OperationContract] 
    List<SpecimenTemplateDescriptor> GetTemplateDescriptorList(DrawerLayout drawerLayout); 

    [OperationContract] 
    SpecimenTemplate SelectSpecimenTemplate(string templateName, int version); 

    [OperationContract(IsOneWay = true)] 
    void SpecimenStoredInContainer(string containerID, bool isValidRackID, int rackRow, int rackCol, int deckRow, int deckCol, 
    int drawerRow, int drawerCol, long trackingNumber, RobotErrors robotError); 

    [OperationContract(IsOneWay = true)] 
    void LvssRobotStatusChange(LVSSStatus status); 
} 

当我设置方法LvssRobotStatuschange操作合同IsOneWay =真,我的缓存回调通道抛出一个CommunicationObjectAbortedException。出于某种原因,我的回调属性正在中止。

***什么会导致回调通道中止?

+0

什么是您的应用程序托管(服务或回调接口)? –

+0

我的应用程序正在托管回调接口。从我的wpf视图模型中,我创建了一个负责创建代理和双工通道的代理类。然后我调用该类上的Connect()来创建双工通道。代理类负责为我的客户端实现回调接口。在我的情况下,总会有一个服务和一个客户。 – EnLaCucha

回答

11

我已经运行到此之前,this link应该帮助,它讨论了在应用程序主线程以外的线程上创建通道。

+1

伟大的链接,谢谢!在我的情况下,我没有在wpf视图模型中创建双工通道。该通道是在助手代理类中创建的。当我尝试在该类中创建新线程时,由于某种原因,该通道保持为空。请参阅上面的编辑号码。 – EnLaCucha

+0

我标记了你的答案,因为它帮助我理解了如何启动一个新线程来防止我的GUI被锁定。我只为我的方法启动了一个新的线程,窒息了应用程序,而不是整个双工通道。我还在我的ServiceContract中的一些无效方法上丢失了一些IsOneWay任务,这些方法正在导致我的InvalidOperationExceptions。所以,我使用InstanceContextMode.Single和UseSynchronizationContext = true的重入并发模式工作得很好。时刻谨防在您的ServiceContract中丢失IsOneWay作业! – EnLaCucha

5

问题我遇到:

CallBackHandlingMethod() 
{ 
    requestToService(); // deadlock message.  
} 

出路:

CallBackHandlingMethod() 
{ 
    Task.Factory.StartNew(()=> 
    { 
     requestToService(); 
    }); 
} 
+0

Downvoter可以提供理由吗? THKS。 – SAm

+0

对我而言,谢谢。 我在WPF中使用WCF event = S – egyware

1

我有我加入

[CallbackBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]

我的回调实现根本解决类似的问题。

0
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] 
public class ServiceCallbackHandler : IServiceCallback 
{ 
... 
} 
+2

这段代码做了什么以及它如何解决这个问题? – JJJ

+0

将这些行添加到实现IServiceCallback的类。它今天解决了我的问题! –