我创建了一个使用NetTCP绑定的WCF服务。
我的服务由客户端访问,保存其回调通道,并在以后使用它来调用客户端(它是一个持久的tcp连接)。一切都很好,但如果我决定突然终止客户端,我会得到一个无法捕获的SocketException("远程主机强制关闭了现有连接")。
我已经试过什么了
-
我在每个使用回调通道的方法中都添加了try-catch子句,甚至在更高级别的WCFHost中也添加了try/catch子句,WCFHost启动了我的服务。
-
我已经尝试获得通道和回调通道,并添加了一种处理通道故障事件的方法:
var channel = OperationContext.Current.Channel; channel.Faulted += ChannelFaulted; var callbackChannel = OperationContext.Current.GetCallbackChannel<CallbackInterface>(); var comObj = callbackChannel as ICommunicationObject; comObj.Faulted += ChannelFaulted;
简而言之,我试图在服务器端处理客户端抛出的异常。
1.在hosts.config文件中将serviceDebug.includeExceptionDetailInFaults属性定义为"true"2.在服务类上将includeExceptionDetailInFaults属性定义为"true"。
示例:
配置文件解决方案:
<behaviors>
<serviceBehaviors>
<behavior name=”ServiceBehavior”>
<serviceMetadata httpGetEnabled=”true”/>
<serviceDebug includeExceptionDetailInFaults=”true”/>
</behavior>
</serviceBehaviors>
</behaviors>
属性类解决方案:
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class CustomersService : ICustomersService
{
private CustomerDetail customerDetail = null;
…etc
引发异常将includeExceptionDetailInFaults设置为true是在WCF中支持异常的第一步。
下一步是让服务抛出FaultException异常(System.ServiceModel.FaultException命名空间中的类)。请注意,当您希望将异常从WCF主机抛出到WCF客户端时,不能期望简单地使用典型的Exception类。若要在WCF绑定上引发异常,您需要使用FaultException类。
引发FaultException示例:
try
{
//Try to do stuff
}
catch
{
throw new FaultException(“Full ruckus!”);
}
捕获故障异常示例:
现在WCF客户端可以捕获FaultException…
try
{
//Client calls services off the proxy
}
catch(FaultException fa)
{
MessageBox.Show(fa.Message);
}
区分故障异常的类型FaultException类是WCF异常的泛型类。为了确定发生何种类型的FaultException,可以使用FaultCode类。在WCF服务上,FaultCode实现看起来像这样:
try
{
//Connect to a database
}
catch
{
throw new FaultException(“Full ruckus!”, new FaultCode(“DBConnection”));
}
在WCF客户端上,FaultCode实现看起来像这样:
try
{
//Call services via the proxy
}
catch(FaultException fa)
{
switch(fa.Code.Name)
{
case “DBConnection”:
MessageBox.Show(“Cannot connect to database!”);
break;
default:
MessageBox.Show(“fa.message”);
break;
}
}
有关更多信息,您可以在此处以及此处查看
经过大量调查,服务器可以使用我之前在问题中提到的Faulted事件来检测客户端抛出的异常(我在调试时应该更有耐心,等到异常"爬"到所有级别,直到到达我的代码)。
但是,请注意,事件只有在为时已晚时才会捕获异常:通道已经为null(OperationContext.Current也是如此)。即使我尝试使用IServiceBehavior和IEndpointBehavior(设置IChannelInitializer),我也无法捕获System.ServiceModel.dll引发的原始SocketException。当我的ChannelFault()方法最终被调用时,无法检测哪个客户端失败。