13

自己ホスト型の 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 に変更しようとしました。

サービスにはまだ 2 つの問題があります。

最初:GetLvssStatus()次のサービス操作は、 (UI ボタン​​をすばやくクリックすることによって) が急速に呼び出されると 、クライアント wpf アプリケーションをフリーズします。このメソッドは一方向ではなく、列挙型をサービスからクライアントに同期的に返します。

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

* この場合、wpf アプリケーションがフリーズする原因は何ですか? *アプリケーションがフリーズしないようにするにはどうすればよいですか? バックグラウンド ワーカー スレッドを非同期呼び出しとして使用すると、アプリケーションはフリーズしません。同期的に機能するには、このメソッドが本当に必要です。

2 番目:コールバック メソッド LvssRobotStatusChange を に割り当てるとIsOneWay = true、ObjectDisposedException が発生します。破棄されたオブジェクトにアクセスできません。オブジェクト名: 'System.ServiceModel.Channels.ServiceChannel'

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

* この ObjectDisposedException の原因は? ※この場合 IsOneWay の代入は省略してもよろしいでしょうか?この場合 IsOneWay を省略すると、例外なくコールバックを完了できます。

* これらの問題は、スレッド セーフ コードの欠如の結果でしょうか?
*
もしそうなら、ConcurrencyMode.Multiple サービス動作をスレッド セーフにするためのベスト プラクティスは何ですか?

これらの質問に対するヘルプは大歓迎です。

*最初の編集 デュプレックス チャネルの作成に関する詳細情報。私の wpf ビュー モデルは、チャネルの作成を処理するプロキシ オブジェクトを作成します。クライアント側の新しいスレッドにチャネルを設定しようとすると、サービスがコールバック オブジェクトを使用しようとすると ObjectDisposedException が発生します。

* 2 番目の編集IsOneWay = true を設定する void メソッドを使用して操作コントラクトを取得できれば、サービスが機能するはずです。再入可能の並行性により、メイン チャネル スレッドは、ロックに関係なくこれらのメソッドを通過させる必要があります。
これが私のコールバックインターフェースです:

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 をスローします。何らかの理由で、コールバック プロパティが中止されています。

***コールバック チャネルが異常終了する原因は何ですか?

4

5 に答える 5

14

アプリケーションのメインスレッド以外のスレッドでのチャネルの作成について説明しているこのリンクが役立つはずです

于 2013-01-18T09:51:22.817 に答える
6

私が遭遇した問題:

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

出口:

CallBackHandlingMethod()
{
    Task.Factory.StartNew(()=>
    {
        requestToService();
    });
}
于 2014-03-20T08:52:47.967 に答える
0
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServiceCallbackHandler : IServiceCallback
{
 ...
}
于 2017-01-23T12:46:52.277 に答える