【问题标题】:Reuse a client class in WCF after it is faulted出现故障后在 WCF 中重用客户端类
【发布时间】:2010-10-23 02:33:52
【问题描述】:

我将 WCF 用于客户端服务器系统。 当我在服务器上添加对 IService 的服务引用时,会生成一个代理类 ServiceClient。 我的代码如下所示:

ServiceClient client = new ServiceClient();
try
{
    client.Operation1();
}
catch(Exception ex)
{
    // Handle Exception
}
try
{
    client.Operation2();
}
catch(Exception ex)
{
    // Handle Exception
}

问题是,如果第一次调用出现通信异常,客户端的状态就变成了Faulted,不知道怎么重新打开才能进行第二次调用。有没有办法重新打开它?还是我应该创建一个新实例并替换实例(这似乎不是一种优雅的方式)?

【问题讨论】:

    标签: wcf


    【解决方案1】:

    一旦 ICommunicationObject(您的 WCF 客户端对象)处于故障状态,“重新打开”它的唯一方法就是创建一个新的。

    ServiceClient client = new ServiceClient();
    try
    {
        client.Operation1();
    }
    catch(Exception ex)
    {
        if (client.State == CommunicationState.Faulted)
        {
                client.Abort();
                client = new ServiceClient();
        }
    }
    try
    {
        client.Operation2();
    }
    catch(Exception ex)
    {
       // Handle Exception
    }
    

    【讨论】:

    • 问题是我们有一个内部函数,它获取服务代理上函数的委托,并重复执行该函数,直到没有抛出通信异常(我们的实现自动重新连接)。所以在这个解决方案中,函数将为每次执行尝试创建一个代理实例,并且必须向调用者返回一个更新的实例,所以他不会持有一个封闭的代理......有点丑陋:-/
    【解决方案2】:

    如果在第一次调用时出现导致故障状态的通信异常,则基本上必须“重新创建”WCF 客户端代理。在您的示例中,我可能会执行以下操作:

    if (client.State == CommunicationState.Faulted)
        client = new ServiceClient();
    

    这将允许您在连接出现故障时“重新打开”连接。这可能看起来有点矫枉过正,但如果您在客户端遇到通信异常,则可能还有其他事情发生(即:服务器死机?服务器没有响应?)

    祝你好运

    【讨论】:

      【解决方案3】:

      同意最后一个答案,一旦失败,需要中止。我们使用 lambdas 和如下方法的组合来做到这一点:

        public static void Use<TServiceInterface>(TServiceInterface proxy, Action handler)
        {
           Type proxyType = typeof(TServiceInterface);
           IClientChannel channel = (IClientChannel)proxy;
      
           try
           {
              handler();
      
              _logSource.Log(LogLevel.Debug, string.Format("Closing client channel for '{0}' ...", proxyType.Name));
      
              channel.Close();
      
              _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' closed.", proxyType.Name));
           }
           catch
           {
              if (channel.State == CommunicationState.Faulted)
              {
                 _logSource.Log(LogLevel.Debug, string.Format("Aborting client channel for '{0}' ...", proxyType.Name));
      
                 channel.Abort();
      
                 _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' aborted.", proxyType.Name));
              }
              else
              {
                 _logSource.Log(LogLevel.Debug, string.Format("Closing client channel for '{0}' ...", proxyType.Name));
      
                 channel.Close();
      
                 _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' closed.", proxyType.Name));
              }
      
              throw;
           }
        }
      

      这是对 .net 上已有解决方案的轻微修改,但它非常适合处理代理。然后,您可以将多个服务调用放在同一个 lambda 表达式中,并将其传递给方法。

      【讨论】:

      • 在您提供的解决方案中,您总是在第一次使用后关闭通道,并且在使用会话时可能会导致性能不佳甚至功能错误.. 一个函数也有点奇怪没有创建通道,正在关闭它。
      • 上述方法的作用类似于 C# 中的 using 语句。您是正确的,它在处理程序操作执行后调用 close ,但我认为您缺少的是处理程序操作中可能有无限数量的语句。如果您愿意,可以对服务接口进行 15 次调用。另外,我不认为该功能不能完成所有工作并不奇怪。将对象的构造和销毁分成单独的方法或单独的代码段是很常见的。工厂通常不负责清理他们创建的对象
      【解决方案4】:

      这很可能是由服务器端未处理的异常引起的。默认情况下,WCF 运行时会终止您的服务实例并将通道置于故障状态以防出现未处理的异常并且您无法再通过该通道进行通信。因此,您将需要与该服务建立一个新会话。您应该在服务器端捕获异常并通过引发 FaultException 或定义 FaultContract 来发送肥皂故障。您还可以使用 returnUnknownExceptionsAsFaults 服务行为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-22
        • 2023-03-22
        相关资源
        最近更新 更多