使用语句和WCF客户端存在的问题

10

我一直在使用 using 语句将调用 WCF 的所有代码包装起来,以确保对象能够正确地释放。当我搜索“Http service located at .. is too busy”异常时,我找到了这个链接:http://msdn.microsoft.com/en-us/library/aa355056.aspx,上面说在类型化代理中不应使用 using 语句。这是真的吗?我认为我需要进行大规模的代码更改(叹气)。这个问题只会出现在类型化代理中吗?

示例代码:

private ServiceClient proxy;

using(proxy = new ServiceClient("ConfigName", "http://serviceaddress//service.svc")){
    string result = proxy.Method();
}

参见:https://dev59.com/6nRB5IYBdhLWcg3wn4QL 和 http://stevesmithblog.com/blog/idisposable-and-wcf/。 - marc_s
有趣。如果您使用basichttpbinding这样的绑定并在每次调用时在服务器上创建一个实例,我认为您不会遇到任何问题。 - BennyM
@BennyM:无论你使用什么绑定方式,可能会出现相同的问题。 - marc_s
3个回答

20

问题的核心在于:在using代码块结束时(通常来说这是一个非常好的实践),WCF代理将被释放。然而,在释放WCF代理的过程中可能会出现异常,这些异常会导致应用程序运行异常。由于这个过程隐含地发生在using代码块的结尾处,你可能无法很清楚地看到错误的发生位置。

因此,通常情况下,Microsoft建议采用类似以下的模式:

private ServiceClient proxy;

try
{
    proxy = new ServiceClient("ConfigName", "http://serviceaddress//service.svc");
    string result = proxy.Method();
    proxy.Close();    
}
catch (CommunicationException e)
{
   // possibly log error, possibly clean up
   proxy.Abort();
}
catch (TimeoutException e)
{
   // possibly log error, possibly clean up
   proxy.Abort();
}
catch (Exception e)
{
   // possibly log error, possibly clean up
   proxy.Abort();
   throw;
}
你需要显式调用proxy.Close()方法并准备好处理该调用可能引发的任何异常。

我想确认一件事,如果Close()抛出异常,则连接将保持打开状态,因此经过一段时间后,服务将无法为新请求提供服务,对吗? - VJAI
@Mark:除非在发生异常后调用 proxy.Abort(),否则代理可能会继续存在..... - marc_s
但是是否适用于实现IDisposable接口的任何对象的相同情况呢? - Stacker

2

将代理操作和实例化调用封装在实现IDisposable接口的类中。在处理时,检查代理的状态属性并在关闭之前清理通道。

public void Dispose()
{
    if (this.MyProxy != null && this.MyProxy.State == CommunicationState.Faulted)
    {
        this.MyProxy.Abort();
        this.MyProxy.Close();
        this.MyProxy = null;
    }
    // ...more tidyup conditions here
} 

1

我喜欢这篇博客上“Eric”评论的方法(与另一篇文章类似:http://redcango.blogspot.com/2009/11/using-using-statement-with-wcf-proxy.htm):

“个人而言,我喜欢为客户端创建自己的部分类,并覆盖Dispose()方法。这样我就可以像平常一样使用‘using’块了。


public partial class SomeWCFServiceClient : IDisposable
{
  void IDisposable.Dispose()
  {
   if (this.State == CommunicationState.Faulted)
   {
    this.Abort();
   }
   else
   {
     this.Close();
   }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接