WCF 服务无法捕获客户端的崩溃

WCF service Cannot catch a client's crash

我创建了一个使用 NetTCP 绑定的 WCF 服务。

我的服务被一个客户端访问,保存它的回调通道并在以后使用它来调用客户端(它是一个持久的 tcp 连接)。一切正常,但如果我决定突然终止客户端 - 我会收到一个我无法捕获的 SocketException ("An existing connection was forcibly closed by the remote host").

我已经尝试了什么?

  1. 我在使用回调通道的每个方法中添加了 try-catch 子句,甚至在上层 - 启动我的服务的 WCFHost。

  2. 我已经尝试获取通道和回调通道并添加一个处理通道故障事件的方法:

    var channel = OperationContext.Current.Channel; 
    channel.Faulted += ChannelFaulted;
    var callbackChannel = OperationContext.Current.GetCallbackChannel<CallbackInterface>();
    var comObj = callbackChannel as ICommunicationObject;
    comObj.Faulted += ChannelFaulted;
    

简而言之,我正在尝试处理客户端抛出的异常 - 在服务器端。

WCF 服务支持异常处理的方式有两种:

1.Defining 主机 .config 文件中的 serviceDebug.includeExceptionDetailInFaults 属性为“true” 2. 在服务 class.

上将 includeExceptionDetailInFaults 属性定义为“true”

示例:

配置文件解决方案:

<behaviors>
<serviceBehaviors>
<behavior name=”ServiceBehavior”>
<serviceMetadata httpGetEnabled=”true”/>
<serviceDebug includeExceptionDetailInFaults=”true”/>
</behavior>
</serviceBehaviors>
</behaviors>

归因Class解决方案:

[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class CustomersService : ICustomersService
{
private CustomerDetail customerDetail = null;

…等等

抛出异常 将 includeExceptionDetailInFaults 设置为 true 是在 WCF 中支持异常的第一步。

下一步是让您的服务抛出 FaultException 异常(System.ServiceModel.FaultException 命名空间中的 class)。 请注意,当您希望从 WCF 主机向 WCF 客户端抛出异常时,您不能期望简单地使用典型的异常 class。 要通过 WCF 绑定引发异常,您需要使用 FaultException class.

抛出 FaultException 示例

try
{
//Try to do stuff
}
catch
{
throw new FaultException(“Full ruckus!”);
}

捕获 FaultException 示例:

现在 WCF 客户端可以捕获 FaultException…

try
{
//Client calls services off the proxy
}
catch(FaultException fa)
{
MessageBox.Show(fa.Message);
}

区分故障异常类型 FaultException class 是 WCF 异常的通用 class。为了确定发生什么类型的 FaultExceptions,您使用 FaultCode class。 在 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;
        }
    }

更多信息你可以看看here and also here

经过大量调查后发现,服务器 可以 检测到客户端使用我之前在问题中提到的 Faulted 事件抛出的异常(调试时我应该更有耐心,并等待异常 "climbed" 所有级别直到到达我的代码)。

但是请注意,事件仅在为时已晚时才捕获异常:通道已经为空(OperationContext.Current 也是如此)。即使我尝试使用 IServiceBehavior 和 IEndpointBehavior(设置了 IChannelInitializer),我也无法捕获 System.ServiceModel.dll 抛出的原始 SocketException。当我的 ChannelFaulted() 方法最终被调用时,无法检测 哪个 客户端失败。