Dot-Net

防止 WCF 雙工回調服務出現死鎖問題

  • June 13, 2018

我有一個自託管 wcf 雙工回調服務的問題。我收到一條InvalidOperationException消息:

此操作將死鎖,因為在目前消息完成處理之前無法接收到回复。如果要允許無序消息處理,請在 CallbackBehaviorAttribute 上指定 Reentrant 或 Multiple 的 ConcurrencyMode。

這是我的服務行為:

[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是在客戶端上呼叫回調操作時引起的,該服務已經被鎖定以處理目前操作。因此,發生了死鎖。

我嘗試將我的 ConcurrencyMode 更改為多個,並將 UseSynchronizationContext 更改為 false。

我的服務仍然存在兩個問題:

首先: 以下服務操作在GetLvssStatus()快速呼叫時凍結我的客戶端 wpf 應用程序(通過快速點擊 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 服務行為執行緒安全的最佳實踐是什麼?

非常感謝您對這些問題的任何幫助。

***第一次編輯關於創建我的雙工頻道的更多資訊。我的 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);
}

當我將方法 LvssRobotStatuschange 操作契約設置為 IsOneWay = true 時,我的記憶體回調通道會引發 CommunicationObjectAbortedException。由於某種原因,我的回調屬性被中止。

***什麼會導致回調通道中止?

我之前遇到過這個問題,這個連結應該會有所幫助,它討論了在應用程序主執行緒以外的執行緒上創建通道。

我遇到的問題:

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

出路:

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

引用自:https://stackoverflow.com/questions/14393386