一起谈.NET技术,不要在using语句中调用WCF服务

  如果你调用WCF服务时,像下面的代码这样在using语句中进行调用,需要注意一个问题。


using (CnblogsWcfClient client = new CnblogsWcfClient())
{
client.Say("Hello, cnblogs.com!");
}

  上面这段代码看上去没问题,CnblogsWcfClient是一个自动生成的WCF客户端代理,继承自System.ServiceModel.ClientBase。using语句结束时,会调用ClientBase实现的System.IDisposable.Dispose接口,实际就是调用ClientBase的Close()方法。用.NET Refector打开C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.ServiceModel.dll,可以看到这样的代码,见下图:

  不仅看上去没问题,似乎就是没问题。但是...问题就出在ClientBase.Close()上,Close()要关闭的是一个网络连接,如果这时网络连接出现问题,不能正常关闭会引发异常(ClientBase的Close方法就是这样设计的,引发异常,而不是强制关闭),问题就来了。本来我们使用using的目的就是不管出现什么状况,即使天塌下来,也给我关闭掉;结果,关是关了,却没有闭,天还是塌下来了。

  也许我们可以用不可抗拒力回避这个问题,但程序员的天性是解决问题。代码中任何一个小问题都不能忽视,因为我们很难预料这个小问题会不会带来大问题。

  那如何解决这个问题呢?MSDN中有答案(去MSDN看看),代码如下:


CnblogsWcfClient client = new CnblogsWcfClient();
try
{
client.Say("Hello, cnblogs.com!");
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}

  上面的代码显得有些哆嗦,如果你不关心是什么异常,只要出现异常就关闭的话,可以用下面的代码(代码来自TIP: Closing your WCF Connections properly):


CnblogsWcfClient client = new CnblogsWcfClient();
client.Say("Hello, cnblogs.com!");
try
{
if (client.State != System.ServiceModel.CommunicationState.Faulted)
{
client.Close();
}
}
catch (Exception ex)
{
client.Abort();
}

  简化版代码:


CnblogsWcfClient client = new CnblogsWcfClient();
client.Say("Hello, cnblogs.com!");
try
{
client.Close();
}
catch
{
client.Abort();
}

  好了,博客写好了,印象更深了,理解也更深了。在收获中分享,在分享中收获。

  参考文章:

  * Avoiding Problems with the Using Statement

  * Closing your WCF Connections properly

时间: 2024-09-19 09:34:38

一起谈.NET技术,不要在using语句中调用WCF服务的相关文章

WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理

在前面一片文章(服务代理不能得到及时关闭会有什么后果?)中,我们谈到及时关闭服务代理(Service Proxy)在一个高并发环境下的重要意义,并阐明了其根本原因.但是,是否直接调用ICommunicationObject的Close方法将服务代理关闭就万事大吉了呢?事情远不会这么简单,这其中还会涉及关于异常处理的一些操作,这就是本篇文章需要讨论的话题. 一.异常的抛出与Close的失败 一般情况下,当服务端抛出异常,客户客户端的服务代理不能直接关闭,WCF在执行Close方法的过程中会抛出异常

不要在using语句中“.NET研究”调用WCF服务

如果你调用WCF服务时,像下面的代码这样在using语句中进行调用,需要注意一个问题. using (CnblogsWcfClient client = new CnblogsWcfClient()){ client.Say("Hello, cnblogs.com!");} 上面这段代码看上去没问题,CnblogsWcfClient是一个自动生成的WCF客户端代理,继承自System.ServiceModel.ClientBase.using语句结束时,会调用ClientBase实现的

一起谈.NET技术,ASP.NET MVC中对数据进行排序的方法

本系列是讲解如何在asp.net mvc中对数据进行展示.排序.分页等的系列文章.在上周的文章中,一步一步教会了大家如何使用ASP.NET MVC框架去的展示数据.在上周的文章中,我们先用Visual Studio创建了一个新的ASP.NET MVC应用程序,接着连接到了Northwind数据库,并展示了如何使用微软的LINQ-SQL的工具去访问数据库中的数据,接着指导如何去实现视图层去展示产品信息及如何设计控制器. 本文是在上一篇文章的例子基础上,展示了如何去实现数据的双向排序.如果你是已经熟

WCF技术剖析之四:基于IIS的WCF服务寄宿(Hosting)实现揭秘

通过<再谈IIS与ASP.NET管道>的介绍,相信读者已经对IIS和ASP.NET的请求处理管道有了一个大致的了解,在此基础上去理解基于IIS服务寄宿的实现机制就显得相对容易了.概括地说,基于IIS的服务寄宿依赖于两个重要的对象:System.ServiceModel.Activation.HttpModule和System. ServiceModel.Activation.HttpHandler. 一.通过HttpModule实现服务寄宿 在默认的情况下,基于IIS的服务寄宿是通过一个特殊的

一起谈.NET技术,了解 C# 4 中的 Dynamic 关键字

dynamic 关键字和动态语言运行时 (DLR) 是 C# 4 和 Microsoft .NET Framework 4 中的重大新增功能. 这些功能在宣布时就引起了人们的极大兴趣,并伴随着许多疑问. 同时人们也给出了很多答案,但这些答案现在已散布于各种文档以及各种技术博客和文章之中. 这样,人们在各种论坛和会议上总是一遍又一遍地提出相同的问题. 本文全面概述了 C# 4 中新增的动态功能,并且深入探讨了这些功能如何同其他语言和框架功能(例如反射或隐式类型化变量)一起使用. 鉴于已有大量信息可

一起谈.NET技术,Silverlight同步(Synchronous)调用WCF服务

Silverlight的RIA应用中访问远端的WebService或WCF服务,都是通过异步线程模式调用的.在某些情况下我们的调用是需要同步进行,虽然Silverlight没有内置同步线程模式调用远端服务接口,但是我们可以通过多线程的处理来伪装出同步调用的实现.在.NET Framework的多线程编程中提供了丰富的线程接口,其中AutoResetEvent和ManualResetEvent在多线程编码中最为常用,本文将介绍如何通过AutoResetEvent的线程等待特性实现Silverlig

一起谈.NET技术,在 Linux 操作系统中运行 ASP.NET 4 (中)

在 Linux 操作系统中运行 ASP.NET 4(上)已经讲解了如果在 Oracle VM VirtualBox 4.0 中安装 openSUSE 11.3 操作系统.现在让我们对刚刚安装好的 openSUSE 11.3 操作系统进行必要的配置吧. 如上图所示,点击计算机 –> YaST,然后: 输入 root 口令后,点击继续,进入YaST2 Control Center: 如上图所示,点击安全和用户中的Sudo项目,进入Sudo 配置: sudo 规则: 如上图所示,点击添加按钮,进入新的

一起谈.NET技术,在 Linux 操作系统中运行 ASP.NET 4(上)

目前最流行的 Linux 操作系统发行版是 Ubuntu.但是我们这次是要在 Linux 操作系统中运行 ASP.NET 的,所以选择了 openSUSE.我准备在 Oracle VM VirtualBox 中安装 openSUSE 11.3 操作系统. 首先到 openSUSE 官方网站下载 openSUSE-11.3-DVD-x86_64.iso 文件. 然后运行 Oracle VM VirtualBox 4.0,新建一个 openSuse 虚拟机并按下图进行设置: 为了使宿主机能够从网络上

一起谈.NET技术,在 Linux 操作系统中运行 ASP.NET 4 (下)

"在 Linux 操作系统中运行 ASP.NET 4 (中)"中已经配置好了 openSUSE 11.3 操作系统. 现在,我们进入"GNOME 终端",使用 ifconfig 命令验证一下本虚拟的 IP 地址就是一开始我们在宽带路由器中为它分配的静态地址. ben@linux-nyhn:~> /sbin/ifconfigeth0 Link encap:Ethernet HWaddr 08:00:27:51:5B:0B inet addr:192.168.1.