如何处理WCF异常(与code综合清单) [英] How to handle WCF exceptions (consolidated list with code)

查看:270
本文介绍了如何处理WCF异常(与code综合清单)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图延长<一个href=\"http://stackoverflow.com/questions/573872/what-is-the-best-workaround-for-the-wcf-client-using-block-issue/573925#573925\">this回答SO ,以使WCF客户端重试短暂的网络故障和处理的需要重试其他情况,如认证到期。

问:

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

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


  • 延迟X秒重试前

  • 关闭并重新创建一个新的()WCF客户端。弃置旧之一。

  • 请不要重试和重新抛出这个错误

  • 重试了N次,则抛出

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

  //使用Sample
    // INT newOrderId = 0; //需要明确赋值的值
    //Service<IOrderService>.Use(orderService=>
    // {
    // newOrderId = orderService.PlaceOrder(请求);
    //}
    ///&LT;总结&gt;
    ///一个安全WCF代理适合当sessionmode = FALSE
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =codeBLOCK&GT;&LT; /参数&GT;
    公共静态无效使用(UseServiceDelegateVoid&LT; T&GT; codeBLOCK)
    {
        IClientChannel代理=(IClientChannel)_channelFactory.CreateChannel();
        布尔成功= FALSE;
        尝试
        {
            codeBLOCK((T)代理);
            proxy.Close();
            成功= TRUE;
        }
        赶上(CommunicationObjectAbortedException E)
        {
                //如果达到这个目标应该被丢弃。
                //这里调试发现以下异常:
                不能成立的连接,因为它已被中止//
            Ë扔掉;
        }
        赶上(CommunicationObjectFaultedException E)
        {
            Ë扔掉;
        }
        赶上(MessageSecurityException E)
        {
            Ë扔掉;
        }
        赶上(ChannelTerminatedException)
        {
            proxy.Abort(); //可能重试吗?
        }
        赶上(ServerTooBusyException)
        {
            proxy.Abort(); //可能重试吗?
        }
        赶上(EndpointNotFoundException)
        {
            proxy.Abort(); //可能重试吗?
        }
        赶上(FaultException异常)
        {
            proxy.Abort();
        }
        赶上(的CommunicationException)
        {
            proxy.Abort();
        }
        赶上(TimeoutException异常)
        {
         //调试过程中发现错误示例:         //邮件无法的分配超时内不得转让
         // 00:01:00。没有空间中的可靠的信道的可用
         //转会窗口。分配给该操作的时间可能是一个
         //更长的超时的部分。            proxy.Abort();
        }
        赶上(的ObjectDisposedException)
        {
            // TODO:处理这种双工回调异常。当客户端消失发生。
            // 资源: http://stackoverflow.com/questions/1427926/detecting-client-death-in-wcf-duplex-contracts/1428238#1428238
        }
        最后
        {
            如果(!成功)
            {
                proxy.Abort();
            }
        }
    }


解决方案

编辑:似乎有一些效率低下与关闭和多次重新打开客户端。我探索解决这里并不断更新和放大器;如果找到一个扩大这个code。 (或者,如果大卫Khaykin张贴一个答案,我会标记为接受的)

此修补左右了几年之后,code下面是我的preferred策略(见状后从自由之路机博客发帖)与WCF重试处理和处理异常。

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

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

样品WCF客户端使用

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

 服务与LT; IOrderService&GT;。用(orderService =&GT;
{
  orderService.PlaceOrder(请求);
}

ServiceDelegate.cs

此文件添加到您的解决方案。无需更改此文件,除非你想改变你要处理什么异常或重试的次数。

 公共委托无效UseServiceDelegate&LT; T&GT;(T代理);公共静态类服务&LT; T&GT;
{
    公共静态的ChannelFactory&LT; T&GT; _channelFactory =新的ChannelFactory&LT; T&GT;();    公共静态无效使用(UseServiceDelegate&LT; T&GT; codeBLOCK)
    {
        IClientChannel代理= NULL;
        布尔成功= FALSE;
       异常mostRecentEx = NULL;
       INT millsecondsToSleep = 1000;       的for(int i = 0;我小于5;我++)//尝试最多5次
       {
           //代理水湿被重用
           代理=(IClientChannel)_channelFactory.CreateChannel();           尝试
           {
               codeBLOCK((T)代理);
               proxy.Close();
               成功= TRUE;
               打破;
           }
           赶上(FaultException异常customFaultEx)
           {
               mostRecentEx = customFaultEx;
               proxy.Abort();               //自定义分辨率为这个应用程序级的异常
               Thread.sleep代码(millsecondsToSleep *第(i + 1));
           }           //通常引发客户机上的下列当信道由于服务器关闭连接终止。
           赶上(ChannelTerminatedException CTE)
           {
              mostRecentEx = CTE;
               proxy.Abort();
               //延迟(补偿),然后重试
               Thread.sleep代码(millsecondsToSleep *第(i + 1));
           }           //下面时,远程端点无法找到或达到异常。端点可能无法找到或
           //可达因为远程端点关闭,则远程端点不可达,因为远程网络不可达。
           赶上(EndpointNotFoundException enfe)
           {
              mostRecentEx = enfe;
               proxy.Abort();
               //延迟(补偿),然后重试
               Thread.sleep代码(millsecondsToSleep *第(i + 1));
           }           //下面的异常被抛出时,服务器太忙,无法接受的消息。
           赶上(ServerTooBusyException STBE)
           {
              mostRecentEx = STBE;
               proxy.Abort();               //延迟(补偿),然后重试
               Thread.sleep代码(millsecondsToSleep *第(i + 1));
           }
           赶上(TimeoutException异常timeoutEx)
           {
               mostRecentEx = timeoutEx;
               proxy.Abort();               //延迟(补偿),然后重试
               Thread.sleep代码(millsecondsToSleep *第(i + 1));
           }
           赶上(收到COMException的CommunicationException)
           {
               mostRecentEx =收到COMException;
               proxy.Abort();               //延迟(补偿),然后重试
               Thread.sleep代码(millsecondsToSleep *第(i + 1));
           }
           赶上(例外五)
           {
                //重新抛出这里没有定义任何其他异常
                //你可能要定义一个自定义异常类来传递信息,如失败的次数,和故障类型
                proxy.Abort();
                Ë扔掉;
           }
       }
       如果(成功==假放;&安培;!mostRecentEx = NULL)
       {
           proxy.Abort();
           抛出新的异常(WCF​​调用试5次后失败了。mostRecentEx);
       }    }
}

I'm attempting to extend this answer on SO to make a WCF client retry on transient network failures and handle other situations that require a retry such as authentication expiration.

Question:

What are the WCF exceptions that need to be handled, and what is the correct way to handle them?

Here are a few sample techniques that I'm hoping to see instead of or in addition to proxy.abort():

  • Delay X seconds prior to retry
  • Close and recreate a New() WCF client. Dispose the old one.
  • Don't retry and rethrow this error
  • Retry N times, then throw

Since it's unlikely one person knows all the exceptions or ways to resolve them, do share what you know. I'll aggregate the answers and approaches in the code sample below.

    // 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: http://stackoverflow.com/questions/1427926/detecting-client-death-in-wcf-duplex-contracts/1428238#1428238
        }
        finally
        {
            if (!success)
            {
                proxy.Abort();
            }
        }
    }

解决方案

EDIT: There seems to be some inefficiencies with closing and reopening the client multiple times. I'm exploring solutions here and will update & expand this code if one is found. (or if David Khaykin posts an answer I'll mark it as accepted)

After tinkering around with this for a few years, the code below is my preferred strategy (after seeing this blog posting from the wayback machine) for dealing with WCF retries and handling exceptions.

I investigated every exception, what I would want to do with that exception, and noticed a common trait; every exception that needed a "retry" inherited from a common base class. I also noticed that every permFail exception that put the client into an invalid state also came from a shared base class.

The following example traps every WCF exception a client could through, and is extensible for your own custom channel errors.

Sample WCF Client Usage

Once you generate your client side proxy, this is all you need to implement it.

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

ServiceDelegate.cs

Add this file to your solution. No changes are needed to this file, unless you want to alter the number of retries or what exceptions you want to handle.

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 );
       }

    }
}

这篇关于如何处理WCF异常(与code综合清单)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆