首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何处理WCF异常(包含代码的合并列表)

如何处理WCF异常(包含代码的合并列表)
EN

Stack Overflow用户
提问于 2011-05-25 20:14:30
回答 4查看 29.7K关注 0票数 49

我试图扩展this answer on SO,使WCF客户端重新尝试瞬态网络故障并处理other situations that require a retry such as authentication expiration.

问题:

需要处理的WCF异常是什么,处理它们的正确方法是什么?

下面是我希望看到的一些示例技术,而不是proxy.abort(),也可以是其他的

  • 延迟X秒,然后重试
  • 关闭并重新创建一个

()

  • 客户端。
  • 不要重试并重抛此错误
  • 重试N次,然后抛出

由于一个人不太可能知道所有的例外情况或解决这些异常的方法,所以请分享你所知道的。我将在下面的代码示例中汇总答案和方法。

代码语言:javascript
运行
复制
    // 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();
            }
        }
    }
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-02-28 20:48:45

编辑:关闭和多次重新打开客户端似乎存在一些效率低下的问题。我是exploring solutions here,如果找到一段代码,我会更新和展开这段代码。(或者,如果大卫·哈伊金( David )贴出一个答案,我会把它标记为接受)

在修改了几年之后,下面的代码是我处理WCF重试和处理异常的首选策略(after seeing this blog posting from the wayback machine)。

我研究了每个异常,以及我想对这个异常做什么,并注意到了一个共同的特性;每个需要从公共基类继承的“重试”的异常。我还注意到,使客户机处于无效状态的每个permFail异常都来自共享基类。

下面的示例捕获客户端可以通过的每个WCF异常,并且对于您自己的自定义通道错误是可扩展的。

示例WCF客户端使用情况

一旦生成客户端代理,这就是实现它所需的全部。

代码语言:javascript
运行
复制
Service<IOrderService>.Use(orderService=>
{
  orderService.PlaceOrder(request);
}

ServiceDelegate.cs

将此文件添加到解决方案中。此文件不需要更改,除非您希望更改重试次数或要处理的异常。

代码语言:javascript
运行
复制
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 );
       }

    }
}
票数 23
EN

Stack Overflow用户

发布于 2011-06-01 00:55:46

我在Codeplex上启动了一个具有以下特性的项目

EventHandlers

  • Operates

  • 允许高效重用客户端代理

  • 清理所有资源,包括每次调用services

  • Supports配置构造函数上的双工services

  • Supports构造函数或工厂

http://smartwcfclient.codeplex.com/

这是一项正在进行的工作,并得到了高度评价。我将感谢任何关于改进它的反馈。

在实例模式下使用示例:

代码语言:javascript
运行
复制
 var reusableSW = new LC.Utils.WCF.ServiceWrapper<IProcessDataDuplex>(channelFactory);

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


 reusableSW.Dispose();
票数 4
EN

Stack Overflow用户

发布于 2011-05-29 19:37:21

我们有一个WCF客户端,它处理服务器上几乎所有类型的故障。捕获名单很长,但不必如此。如果仔细观察,您将看到许多异常是异常类(和其他几个类)的子定义。

因此,如果你愿意的话,你可以简化很多事情。尽管如此,以下是我们捕捉到的一些典型错误:

服务器超时

服务器太忙

服务器不可用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6130331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档