如何处理WCFexception(带有代码的统一列表)

我试图延长这个答案,以使WCF客户端重试暂时networking故障,并处理其他情况下需要重试,如​​身份validation到期。

题:

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

以下是我希望看到的一些示例技术,以代替proxy.abort()或除此之外:

  • 重试前延迟X秒
  • closures并重新创build一个新()WCF客户端。 configuration旧的。
  • 不要重试并重新抛出这个错误
  • 重试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(); } } } 

编辑:似乎有closures和重新打开客户端多次低效率。 我在这里探索解决scheme ,如果find了 ,将更新和扩展这段代码。 (或者如果David Khaykin发表了一个答案,我会将其标记为已接受)

经过几年的修改之后,下面的代码是我首选的策略( 在看了这个来自wayback机器的博客文章 ),用于处理WCF重试和处理exception。

我调查了每一个exception,我想用这个exception做什么,并注意到一个共同的特点; 每个需要从共同基类inheritance的“重试”的exception。 我也注意到,每个将客户端置于无效状态的permFailexception也来自共享基类。

以下示例会捕获客户端可能通过的每个WCFexception,并且可以针对您自己的自定义通道错误进行扩展。

示例WCF客户端使用情况

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

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

ServiceDelegate.cs

将此文件添加到您的解决scheme。 除非要更改重试次数或要处理的exception,否则不需要更改此文件。

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

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

  • 允许有效地重用客户端代理
  • 清理所有资源,包括EventHandlers
  • 在双工频道上运行
  • 按通话服务运行
  • 支持configuration构造函数,或者通过工厂

http://smartwcfclient.codeplex.com/

这是一项正在进行的工作,并受到很多评论。 我将不胜感激有关改进它的任何反馈。

在实例模式下的示例使用情况:

  var reusableSW = new LC.Utils.WCF.ServiceWrapper<IProcessDataDuplex>(channelFactory); reusableSW.Reuse(client => { client.CheckIn(count.ToString()); }); reusableSW.Dispose(); 

我们有一个WCF客户端,可以处理服务器上几乎任何types的故障。 Catch清单非常长,但不一定非要。 如果仔细观察,您会看到许多例外情况是Exception Class(以及其他一些类)的子定义。

因此,如果你愿意,你可以简化很多事情。 这就是说,这里有一些典型的错误:

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