C# 如何处理WCF异常(带代码的合并列表)
我正在尝试扩展以使WCF客户端在暂时性网络故障时重试并处理 问题: 需要处理哪些WCF异常,正确的处理方法是什么 下面是我希望看到的一些示例技术,它们可以替代或补充C# 如何处理WCF异常(带代码的合并列表),c#,wcf,exception,using-statement,duplex,C#,Wcf,Exception,Using Statement,Duplex,我正在尝试扩展以使WCF客户端在暂时性网络故障时重试并处理 问题: 需要处理哪些WCF异常,正确的处理方法是什么 下面是我希望看到的一些示例技术,它们可以替代或补充proxy.abort(): 重试前延迟X秒 关闭并重新创建新的()WCF客户端。把旧的处理掉 不要重试并重新显示此错误 重试N次,然后抛出 因为不太可能一个人知道所有的异常或解决它们的方法,所以一定要分享你所知道的。我将在下面的代码示例中汇总答案和方法 // USAGE SAMPLE //int newOrder
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();
}
}
}
//用法示例
//int newOrderId=0;//需要确定赋值的值
//Service.Use(orderService=>
//{
//newOrderId=orderService.PlaceOrder(请求);
//}
///
///sessionmode=false时适用的安全WCF代理
///
///
公共静态无效使用(UseServiceDelegateVoid代码块)
{
IClientChannel代理=(IClientChannel)_channelFactory.CreateChannel();
布尔成功=假;
尝试
{
代码块((T)代理);
proxy.Close();
成功=真实;
}
捕获(通信对象中止异常e)
{
//如果达到此值,则应丢弃对象。
//调试在此处发现以下异常:
//“无法建立连接,因为它已被中止”
投掷e;
}
捕获(通信对象故障异常e)
{
投掷e;
}
捕获(MessageSecurityException e)
{
投掷e;
}
捕获(通道终止异常)
{
proxy.Abort();//是否可能重试?
}
捕获(ServerTooBusyException)
{
proxy.Abort();//是否可能重试?
}
捕获(EndpointNotFoundException)
{
proxy.Abort();//是否可能重试?
}
捕获(错误异常)
{
proxy.Abort();
}
捕获(通信异常)
{
proxy.Abort();
}
捕获(超时异常)
{
//调试期间发现的示例错误:
//无法在分配的超时内传输消息
//00:01:00。可靠频道的可用空间不足
//传输窗口。分配给此操作的时间可能已被更改
//较长超时的一部分。
proxy.Abort();
}
捕获(ObjectDisposedException)
{
//todo:处理此双工回调异常。在客户端消失时发生。
//资料来源:https://stackoverflow.com/questions/1427926/detecting-client-death-in-wcf-duplex-contracts/1428238#1428238
}
最后
{
如果(!成功)
{
proxy.Abort();
}
}
}
我们有一个WCF客户端,它可以处理服务器上几乎任何类型的故障。捕获列表很长,但不一定非得如此。如果仔细观察,您会发现许多异常都是异常类(以及一些其他类)的子定义
因此,如果您愿意,您可以将事情简化很多。也就是说,下面是我们发现的一些典型错误:
服务器超时服务器太忙
服务器不可用。以下链接可能有助于处理WCF异常:
我在Codeplex上启动了一个具有以下功能的项目
- 允许高效地重用客户端代理
- 清理所有资源,包括事件处理程序
- 在双工信道上运行
- 按通话次数提供服务
- 支持配置构造函数,或按工厂配置
var reusableSW = new LC.Utils.WCF.ServiceWrapper<IProcessDataDuplex>(channelFactory);
reusableSW.Reuse(client =>
{
client.CheckIn(count.ToString());
});
reusableSW.Dispose();
var reusableSW=new LC.Utils.WCF.ServiceWrapper(channelFactory);
重用(客户端=>
{
client.CheckIn(count.ToString());
});
可重用的sw.Dispose();
编辑:多次关闭和重新打开客户端似乎效率低下。如果找到此代码,我将更新并扩展此代码。(或者,如果David Khaykin发布了答案,我会将其标记为已接受)
经过几年的修改,下面的代码是我处理WCF重试和处理异常的首选策略()
我调查了每一个异常,我希望如何处理该异常,并注意到了一个共同的特征:每一个需要“重试”的异常都继承自一个公共基类。我还注意到,每一个将客户端置于无效状态的permFail异常也来自一个共享基类
下面的示例将捕获客户端可能通过的每个WCF异常,并可针对您自己的自定义通道错误进行扩展
WCF客户端使用示例
一旦生成客户端代理,这就是实现它所需的全部内容
Service<IOrderService>.Use(orderService=>
{
orderService.PlaceOrder(request);
}
Service.Use(orderService=>
{
orderService.PlaceOrder(请求);
}
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 );
}
}
}
public委托void-UseServiceDelegate(T-proxy);
公共静态类服务
{
公共静态ChannelFactory\u ChannelFactory=新ChannelFactory(“”);
公共静态无效使用(UseServiceDelegate代码块)
{
IClientChannel代理=null;
布尔成功=假;
例外多数