簡體   English   中英

WCF客戶端錯誤處理

[英]WCF client-side error-handling

我正在消耗一個笨重的WCF服務器,偶爾會拋出各種異常,並且還會將一些錯誤作為string返回。 我根本無法訪問服務器代碼。

我想覆蓋內部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子類或至少使用它的通道。
我需要的是控制內部請求調用方法。

更新

我看了這個答案 ,看起來它部分是我正在尋找的,但我想知道是否有辦法將IErrorHandler僅附加到消費者(客戶端)代碼,我想將它添加到ClientBase<TChannel>實例不知何故。

更新

這篇文章看起來很有希望,但它不起作用。 應用的屬性似乎沒有生效。 我找不到將IServiceBehavior添加到客戶端的方法。

更新

我試圖安裝一個IErrorHandler通過IEndpointBehavior.ApplyClientBehavior電話:

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

clientRuntime是一個參數),但仍然會直接跳過異常跳過MyErrorHandler
ApplyDispatchBehavior不調用ApplyDispatchBehavior

結論

我需要實現兩個方面:

  1. 包裝在BaseClient<TChannel>的生命周期內可能發生的所有異常,並決定是處理它們還是將它們拋出。 這應該照顧所有操作(我正在消耗的服務暴露幾十個)
  2. 解析所有服務器回復並為其中一些回復拋出異常,因此它們將在語句1中轉發。

您可以使用和修改異常處理WCF代理生成器 ,更具體地說,它是使用它的基類。 它的基本思想(檢查此描述 )是通過捕獲連接故障和重試失敗的操作來提供連接彈性。 可以想象,為此目的,它需要能夠捕獲拋出的異常,並且還可以檢查調用的結果。

主要功能由ExceptionHandlingProxyBase<T>基類提供,您使用它來代替ClientBase<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;
}  

你需要修改throw targetEx.InnerException; 根據需要處理異常的部分,顯然還要根據您的需要檢查resturn值。 除此之外,如果您不希望出現連接問題,您可以退出重試邏輯或將其丟棄。 Invoke for void返回方法還有另一種變體。

哦,順便說一句,它也適用於雙工通道,還有另一個基類。

如果您不想使用生成器(它甚至可能不適用於較新版本的VS),那么您可以從此處獲取基類,並從服務接口生成帶有T4的實際實現類。

如果服務未返回真正的異常,而只返回消息,則可能需要將ClientMessageInspector添加為新的客戶端行為。 請參閱: https//msdn.microsoft.com/en-us/library/ms733786.aspx

我最終根據這個問題的答案使用了一些東西。

它堅持生成的客戶端代碼,並允許一般調用操作。

代碼不完整,隨意分叉和編輯它。 如果您發現任何錯誤或進行任何更新,請通知我。

它非常笨重,所以我只是分享使用代碼:

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($@"A '{eventArgs.Exception.GetType()}' occurred 
      during operation '{eventArgs.Operation.Method.Name}'.");
    eventArgs.Handled = true;
  };
  client.Invoke(client.Client.MyOperation, "arg1", "arg2");
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM