2015-11-16 18 views
8

時々、さまざまな例外をスローし、さらにいくつかのエラーをstringとして返す、厄介なWCFサーバーを使用しています。私はサーバーコードにアクセスできません。WCFクライアント側のエラー処理

私は擬似、インナーWCFクライアント要求の呼び出しメソッドをオーバーライドして、サーバによって返されたすべての内部例外とハードコーディングされたエラーを処理し、エラーが発生した場合Faultイベントを発生させたい:だから

class MyClient : MyServiceSoapClient 
{ 
    protected override OnInvoke() 
    { 
     object result; 
     try 
     { 
      result = base.OnInvoke(); 
      if(result == "Error") 
      { 
       //raise fault event 
      } 
     catch 
     { 
      //raise fault event 
     } 
    }   
} 

私がmyClient.GetHelloWorld()と呼ぶとき、それは私のオーバーライドされた方法を通ります。

これはどのように達成できますか?
私は生成されたクライアントを使用する必要はありませんが、すべてのコントラクトを再実装する必要はなく、生成されたClientBaseサブクラスまたは少なくともそのチャネルを使用したいと考えています。
私が必要とするのは、内部要求呼び出しメソッドの制御です。

更新

私は、このanswerを読んで、それは部分的に私が探しているものだように見えますが、唯一の消費者(クライアント)のコードへIErrorHandlerを添付する方法がある場合、私は思ったんだけど何とかそれをClientBase<TChannel>インスタンスに追加したいと思います。

更新

This記事はまた、非常に有望に見えるが、それは動作しません。適用された属性は有効には見えません。 IServiceBehaviorをクライアント側に追加する方法が見つかりません。

アップデートは私がIErrorHandlerIEndpointBehavior.ApplyClientBehaviorを経由して通話付けてみました:

public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
{ 
    clientRuntime.CallbackDispatchRuntime.ChannelDispatcher.ErrorHandlers 
      .Add(new ErrorHandler()); 
} 

を(clientRuntimeがパラメータである)が、例外は、まだ直接MyErrorHandlerをスキップスローされます。
ApplyDispatchBehaviorはまったく呼び出されません。

私は二つの側面を達成する必要が

結論:

  1. ラップBaseClient<TChannel>の存続期間中に発生し、それらを処理するか、それらをスローするかどうかを決定する可能性があるすべての例外を。これは、(私が消費してるサービスが数十を公開する)すべての操作の
  2. 解析すべてのサーバーの応答を世話をし、そのうちのいくつかのために例外をスローので、彼らは声明1.
+0

あなたがサービスのapp.configファイルまたはweb.configファイルへのアクセス権を持っていますか? –

+0

@DavidP私はサーバーコードにアクセスできません。また、アプリの設定やアプリの設定を使用するのではなく、設定をプログラムで設定することをおすすめします。 – Shimmy

+0

オクラホマ - あなたが今やっていることを理解していると思います。サービスが例外を返すか、文字列メッセージで正常に返されますか? @DavidPともに –

答えて

1

私はthis質問の答えに基づいて何かを使ってしまった。

これは生成されたクライアントコードに付着、及び一般的動作の呼び出しを可能にします。

codeは不完全であり、自由にフォークして編集できます。バグが見つかった場合や更新があった場合は、お知らせください。

私はちょうど使用コードを共有しますので、それはかなりかさばるです:

using (var proxy = new ClientProxy<MyServiceSoapClientChannel, MyServiceSoapChannel>()) 
{ 
    client.Exception += (sender, eventArgs) => 
    { 
    //All the exceptions will get here, can be customized by overriding ClientProxy. 
    Console.WriteLine([email protected]"A '{eventArgs.Exception.GetType()}' occurred 
     during operation '{eventArgs.Operation.Method.Name}'."); 
    eventArgs.Handled = true; 
    }; 
    client.Invoke(client.Client.MyOperation, "arg1", "arg2"); 
} 
1

のように転送されている必要がありますサービスが真の例外を返すのではなくメッセージだけを返す場合は、新しいクライアントの振る舞いとしてClientMessageInspectorを追加することをお勧めします。参照してください:https://msdn.microsoft.com/en-us/library/ms733786.aspx

+0

サーバーはエラーメッセージを返していますが、通常の例外を返します。私は、サービスを要求している間に発生する可能性があるすべての例外を処理するための集中化された方法、未処理のサーバー例外、またはサーバーがダウンしているかどうかなどを必要とします。 'FaultException'をすべて置き換える場所が必要なので、チャンネルの' Fault'イベントまでトンネリングされます。 – Shimmy

+0

私は質問に賞金を追加しました。私は両方のことが必要で、メッセージを傍受し、すべてのタイプの例外を処理します。 – Shimmy

5

Exception Handling WCF Proxy Generator、具体的にはそれが使用する基本クラスを使用して修正することができます。基本的な考え方(this descriptionのチェックも)は、接続障害をキャッチして失敗した操作を再試行することによって接続の復元力を提供することです。あなたが想像することができるように、この目的のためには、スローされた例外をキャッチする必要があり、呼び出しの結果を検査することもできます。

主な機能は、ClientBase<T>の代わりに使用するExceptionHandlingProxyBase<T>ベースクラスです。この基本クラスは、次のようにInvokeメソッドを持っています。それを修正する必要があります。簡体Invoke

protected TResult Invoke<TResult>(string operationName, params object[] parameters)        
{               
    this.Open();        
    MethodInfo methodInfo = GetMethod(operationName);        
    TResult result = default(TResult);        
    try        
    {        
    this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait); 
    result = (TResult)methodInfo.Invoke(m_channel, parameters);        
    }        
    catch (TargetInvocationException targetEx) // Invoke() always throws this type        
    {        
    CommunicationException commEx = targetEx.InnerException as CommunicationException;        
    if (commEx == null)        
    {        
     throw targetEx.InnerException; // not a communication exception, throw it        
    }        
    FaultException faultEx = commEx as FaultException;        
    if (faultEx != null)        
    {        
     throw targetEx.InnerException; // the service threw a fault, throw it        
    }        

    //... Retry logic 

    } 
    return result; 
} 

あなたが必要とする、と明らかにresturn値も、ニーズのために検査することがshoudlとしてあなたが例外を処理するためにthrow targetEx.InnerException;一部を変更する必要があります。それ以外の場合は、接続の問題が予想されない場合は、再試行ロジックを終了するか、放棄することができます。 voidの返品方法にはInvokeの別の変形があります。

ああ、ちなみに、これはデュプレックスチャンネルでも動作しますが、それらには別の基本クラスがあります。

ジェネレータを使用したくない場合(新しいバージョンのVSでも動作しない場合があります)、基本クラスを例えばhereから取得し、実際の実装クラスをT4から生成することができますサービスインタフェース。

+0

あなたの努力に感謝します。 'BaseClient .Invoke'は仮想ではありません。されていると私の質問はここにはないだろう。 – Shimmy

+0

私はそれが 'virtual'ではないことを知っています。クライアントプロキシベースクラスとして' ClientBase 'の代わりに' ExceptionHandlingProxyBase 'を使うことを提案しています。実際の実装クラスはジェネレータで生成することもできますし、自分で生成することもできます) – Tamas

+0

ああ、私はそれが外部ツールだとは気付きませんでした。 **あなたはこのツールを個人的に**使用しましたか?私は時間が迫っており、テストに長時間を費やして失望するだけで新しいソフトウェアをインストールする余裕はない。さらに、私はVS 2015を使用していますが、そのツールは2009年のようです。これも機能しますか? – Shimmy

関連する問題