如何处理WCF异常(综合清单有代码)如何处理WCF异常(综合清单有代码)(How to handle

2019-05-12 19:31发布

我试图扩大对SO这个答案 ,使瞬态网络故障WCF客户端重试和处理需要重试其他情况,如认证到期。

题:

什么是需要处理的WCF例外,什么是处理他们的正确方法?

下面是我希望看到的,而不是或除了几样技术proxy.abort()

  • 延迟X秒重试之前
  • 关闭并重新创建一个新的()WCF客户端。 处理旧的。
  • 不要重试,重新抛出这个错误
  • 重试了N次,再扔

由于这是不可能一个人知道所有的异常或解决这些问题的方式,也分享你知道是什么。 我将汇总的答案,下面的代码示例中的方法。

    // USAGE SAMPLE
    //int newOrderId = 0; // need a value for definite assignment
    //Service<IOrderService>.Use(orderService=>
    //{
    //  newOrderId = orderService.PlaceOrder(request);
    //}




    /// <summary>
    /// A safe WCF Proxy suitable when sessionmode=false
    /// </summary>
    /// <param name="codeBlock"></param>
    public static void Use(UseServiceDelegateVoid<T> codeBlock)
    {
        IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
        bool success = false;
        try
        {
            codeBlock((T)proxy);
            proxy.Close();
            success = true;
        }
        catch (CommunicationObjectAbortedException e)
        {
                // Object should be discarded if this is reached.  
                // Debugging discovered the following exception here:
                // "Connection can not be established because it has been aborted" 
            throw e;
        }
        catch (CommunicationObjectFaultedException e)
        {
            throw e;
        }
        catch (MessageSecurityException e)
        {
            throw e;
        }
        catch (ChannelTerminatedException)
        {
            proxy.Abort(); // Possibly retry?
        }
        catch (ServerTooBusyException)
        {
            proxy.Abort(); // Possibly retry?
        }
        catch (EndpointNotFoundException)
        {
            proxy.Abort(); // Possibly retry?
        }
        catch (FaultException)
        {
            proxy.Abort();
        }
        catch (CommunicationException)
        {
            proxy.Abort();
        }
        catch (TimeoutException)
        {
         // Sample error found during debug: 

         // The message could not be transferred within the allotted timeout of 
         //  00:01:00. There was no space available in the reliable channel's 
         //  transfer window. The time allotted to this operation may have been a 
         //  portion of a longer timeout.

            proxy.Abort();
        }
        catch (ObjectDisposedException )
        {
            //todo:  handle this duplex callback exception.  Occurs when client disappears.  
            // Source: https://stackoverflow.com/questions/1427926/detecting-client-death-in-wcf-duplex-contracts/1428238#1428238
        }
        finally
        {
            if (!success)
            {
                proxy.Abort();
            }
        }
    }

Answer 1:

编辑:好像有一些低效率的关闭和多次重新打开客户端。 我在这里探讨解决方案 ,并会更新及如果找到一个扩大这个代码。 (或者,如果大卫Khaykin张贴一个答案,我会标记为接受)

与此修补左右了几年之后,下面的代码是我的首选策略( 看到从自由之路机本博客发布后的处理WCF重试和处理异常)。

我调查了每一个例外,我想,除此之外的事,并发现一个共同的特点; 每一个需要“重试”,从一个公共基类继承的异常。 我还注意到,这把客户变成无效状态,每permFail例外也从一个共享的基类来了。

下面的例子捕捉每一个WCF异常的客户端可以通过,并可扩展为您的自定义频道的错误。

样品WCF客户端使用

一旦你生成客户端代理,这是所有你需要实现它。

Service<IOrderService>.Use(orderService=>
{
  orderService.PlaceOrder(request);
}

ServiceDelegate.cs

这个文件添加到您的解决方案。 任何更改都需要这个文件,除非你想改变重试,或者你要处理什么异常的数目。

public delegate void UseServiceDelegate<T>(T proxy);

public static class Service<T>
{
    public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(""); 

    public static void Use(UseServiceDelegate<T> codeBlock)
    {
        IClientChannel proxy = null;
        bool success = false;


       Exception mostRecentEx = null;
       int millsecondsToSleep = 1000;

       for(int i=0; i<5; i++)  // Attempt a maximum of 5 times 
       {
           // Proxy cann't be reused
           proxy = (IClientChannel)_channelFactory.CreateChannel();

           try
           {
               codeBlock((T)proxy);
               proxy.Close();
               success = true; 
               break;
           }
           catch (FaultException customFaultEx)
           {
               mostRecentEx = customFaultEx;
               proxy.Abort();

               //  Custom resolution for this app-level exception
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }

           // The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
           catch (ChannelTerminatedException cte)
           {
              mostRecentEx = cte;
               proxy.Abort();
               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep  * (i + 1)); 
           }

           // The following is thrown when a remote endpoint could not be found or reached.  The endpoint may not be found or 
           // reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
           catch (EndpointNotFoundException enfe)
           {
              mostRecentEx = enfe;
               proxy.Abort();
               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }

           // The following exception that is thrown when a server is too busy to accept a message.
           catch (ServerTooBusyException stbe)
           {
              mostRecentEx = stbe;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }
           catch (TimeoutException timeoutEx)
           {
               mostRecentEx = timeoutEx;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           } 
           catch (CommunicationException comException)
           {
               mostRecentEx = comException;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }


           catch(Exception e)
           {
                // rethrow any other exception not defined here
                // You may want to define a custom Exception class to pass information such as failure count, and failure type
                proxy.Abort();
                throw e;  
           }
       }
       if (success == false && mostRecentEx != null) 
       { 
           proxy.Abort();
           throw new Exception("WCF call failed after 5 retries.", mostRecentEx );
       }

    }
}


Answer 2:

我开始Codeplex上的一个项目,它具有以下特点

  • 允许客户端代理的高效再利用
  • 清除所有资源,包括事件处理
  • 运行在全双工通道
  • 运行在每呼叫服务
  • 支持配置构造,或由工厂

http://smartwcfclient.codeplex.com/

这是一项正在进行的工作,而且是非常详细的注释。 我会感激关于改进它的任何反馈。

样品在使用实例方式时:

 var reusableSW = new LC.Utils.WCF.ServiceWrapper<IProcessDataDuplex>(channelFactory);

 reusableSW.Reuse(client =>
                      {
                          client.CheckIn(count.ToString());
                      });


 reusableSW.Dispose();


Answer 3:

我们有一个WCF客户端与服务器几乎任何类型的故障处理。 捕获列表很长,但并不一定如此。 如果你仔细观察,你会看到很多的例外是异常类的子定义(和其他几个班)。

因此,您可以简化事情很多,如果你想。 这就是说,这里是我们捕捉一些典型的错误:

服务器超时
服务器太繁忙
服务器无法使用。



Answer 4:

下面的链接可以帮助处理WCF异常:

http://www.codeproject.com/KB/WCF/WCFErrorHandling.aspx

http://msdn.microsoft.com/en-us/library/cc949036.aspx



文章来源: How to handle WCF exceptions (consolidated list with code)