我试图扩展this answer on SO,使WCF客户端重新尝试瞬态网络故障并处理other situations that require a retry such as authentication expiration.
问题:
需要处理的WCF异常是什么,处理它们的正确方法是什么?
下面是我希望看到的一些示例技术,而不是proxy.abort()
,也可以是其他的
()
由于一个人不太可能知道所有的例外情况或解决这些异常的方法,所以请分享你所知道的。我将在下面的代码示例中汇总答案和方法。
// 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();
}
}
}
发布于 2012-02-28 20:48:45
编辑:关闭和多次重新打开客户端似乎存在一些效率低下的问题。我是exploring solutions here,如果找到一段代码,我会更新和展开这段代码。(或者,如果大卫·哈伊金( David )贴出一个答案,我会把它标记为接受)
在修改了几年之后,下面的代码是我处理WCF重试和处理异常的首选策略(after seeing this blog posting from the wayback machine)。
我研究了每个异常,以及我想对这个异常做什么,并注意到了一个共同的特性;每个需要从公共基类继承的“重试”的异常。我还注意到,使客户机处于无效状态的每个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 );
}
}
}
发布于 2011-06-01 00:55:46
我在Codeplex上启动了一个具有以下特性的项目
EventHandlers
。
http://smartwcfclient.codeplex.com/
这是一项正在进行的工作,并得到了高度评价。我将感谢任何关于改进它的反馈。
在实例模式下使用示例:
var reusableSW = new LC.Utils.WCF.ServiceWrapper<IProcessDataDuplex>(channelFactory);
reusableSW.Reuse(client =>
{
client.CheckIn(count.ToString());
});
reusableSW.Dispose();
发布于 2011-05-29 19:37:21
我们有一个WCF客户端,它处理服务器上几乎所有类型的故障。捕获名单很长,但不必如此。如果仔细观察,您将看到许多异常是异常类(和其他几个类)的子定义。
因此,如果你愿意的话,你可以简化很多事情。尽管如此,以下是我们捕捉到的一些典型错误:
服务器超时
服务器太忙
服务器不可用。
https://stackoverflow.com/questions/6130331
复制相似问题