防止WCF双工回调服务出现死锁问题

EnL*_*cha 12 .net wcf duplex

我有一个自托管的wcf双工回调服务的问题.我得到一条InvalidOperationException消息:

此操作将死锁,因为在当前消息完成处理之前无法接收回复.如果要允许无序消息处理,请在CallbackBehaviorAttribute上指定Remediate的ConcurrencyMode或Multiple.

这是我的服务行为:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode =  ConcurrencyMode.Reentrant, UseSynchronizationContext = true)]
Run Code Online (Sandbox Code Playgroud)

这是我的服务合同:

 [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();
}
Run Code Online (Sandbox Code Playgroud)

这是我的回调界面:

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);
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这InvalidOperationException是在客户端上调用回调操作时引起的,该服务已被锁定以处理当前操作.因此,发生了死锁.

我尝试将ConcurrencyMode更改为多个,并将UseSynchronizationContext更改为false.

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

第一:GetLvssStatus()快速调用时(快速单击UI按钮),以下服务操作会冻结我的客户端wpf应用程序.此方法不是单向的,并且会将服务中的枚举类型同步返回给客户端.

    [OperationContract(IsOneWay = false)]
    LVSSStatus GetLvssStatus();
Run Code Online (Sandbox Code Playgroud)

*在这种情况下,是什么导致我的wpf应用程序冻结?*我可以做些什么来防止应用冻结?如果我使用backgroundworker线程作为异步调用,应用程序不会冻结.我真的需要这种方法同步工作.

第二:当我将回调方法LvssRobotStatusChange分配给时IsOneWay = true,我得到一个ObjectDisposedException:无法访问已处置的对象.对象名称:'System.ServiceModel.Channels.ServiceChannel'.

    [OperationContract(IsOneWay = true)]
    void LvssRobotStatusChange(LVSSStatus status);
Run Code Online (Sandbox Code Playgroud)

*导致此ObjectDisposedException的原因是什么?*在这种情况下可以省略IsOneWay分配吗?在这种情况下省略IsOneWay允许回调完成而没有任何异常.

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

对这些问题的任何帮助都非常感谢.

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

*第二次编辑我相信如果我可以通过void方法获得操作合同来设置IsOneWay = true,那么我的服务应该可以工作.对于可重入的并发性,主通道线程应该允许这些方法通过而不管任何锁定.
这是我的回调界面:

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);
}
Run Code Online (Sandbox Code Playgroud)

当我将方法LvssRobotStatuschange操作契约设置为IsOneWay = true时,我的缓存回调通道会抛出CommunicationObjectAbortedException.出于某种原因,我的回调属性正在中止.

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

Tan*_*ner 13

我之前遇到过这个问题,这个链接应该有帮助,它讨论了在应用程序主线程以外的线程上创建通道.


SAm*_*SAm 5

我遇到的问题:

CallBackHandlingMethod()
{
    requestToService();    // deadlock message.    
}
Run Code Online (Sandbox Code Playgroud)

出路:

CallBackHandlingMethod()
{
    Task.Factory.StartNew(()=>
    {
        requestToService();
    });
}
Run Code Online (Sandbox Code Playgroud)