ChannelFactory.Close与IClientChannel.Close的区别

34
考虑以下代码,它是许多ChannelFactory示例的典型代表:
WSHttpBinding myBinding = new WSHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress(
   ConfigurationSettings.AppSettings["HelloWorldServiceURL"]);  

ChannelFactory<IHelloWorldService> myChannelFactory = 
   new ChannelFactory<IHelloWorldService>(myBinding, myEndpoint);

IHelloWorldService proxy = myChannelFactory.CreateChannel();
((IClientChannel)proxy).Open();
HelloWorldDataContract dc = proxy.SayHello();
((IClientChannel)proxy).Close();
请注意,当调用proxy.Open()时,通道的状态和ChannelFactory的状态都会变为"Opened"。当调用proxy.Close()时,通道的状态变为"closed",但ChannelFactory的状态仍然是"Opened"。
是否应该关闭ChannelFactory呢?我没有在许多示例中看到这一点。此外,如果可能的话,请解释一下打开通道和打开通道工厂之间的区别。
另外,我知道IDisposable问题,所以可以忽略它对答案的直接影响。

我认为你想要使用的是ICommunicationObject.Close,而不是IClientChannel.Close。 - TamaMcGlinn
4个回答

21

我发现主要答案不准确,所以我在这里回复。

显然,微软在通道、工厂和客户端方面造成了一大混乱。文档也并没有什么帮助,因为它们似乎只是用来掩盖这个混乱的,所以我不得不求助于测试。

关于非缓存通道的性能问题,在 v3.5 中进行了实现更改以解决这些问题,并添加了缓存,但这只是让问题变得更加复杂。

重点是,在使用 ChannelFactory.CreateChannel() 创建通道时,ChannelFactory 中的通道实际上与 IClientChannel 使用的通道没有区别。它们都是同一个池子。不信?试试:

ChannelFactory<IService> factory = new ChannelFactory<IService>();
// ...
IService service = factory.CreateChannel();
factory.Close();
service.DoIt() // Throws object disposed exception

实际上,在内部,它就是同一个通道。我个人已经开始处理通道工厂而不是客户端通道,并且没有遇到任何问题。我还尝试使用创建100,000个客户端通道的循环,并仅关闭ChannelFactory


1
但是在关闭工厂后,您能否重复使用它?我认为为每个通道创建工厂会有性能损失。 - Tomas Jansson
1
关闭的通道工厂无法重复使用。创建新的通道工厂会影响性能,但如果像我一样需要使用身份验证,一旦打开它,就无法更改用户名/密码,因此每次都必须创建它。 - Aliostad
37
在内部,它不是同一个通道;ChannelFactory.Close 循环遍历它的通道并手动关闭它们。这就是为什么会出现已处理异常的原因。 - Michael Edenfield
5
@JoãoPortela 告诉我!是的,没错。正如我所解释的那样,关闭工厂将会关闭底层通道和客户端。 - Aliostad
请注意,ChannelFactory上的Close方法实际上相当于Dispose()。请查看框架设计指南,在其中指出在特殊情况下,Close()比Dispose()更受欢迎,例如StreamWrite也是如此... - Patrick Peters
显示剩余5条评论

14
正如您所知,ChannelFactory基于配置创建客户端通道。您可能希望从现有工厂创建多个客户端通道(到相同的端点,因为该端点已被锁定)。如果您已经使用工厂创建了通道,则没有理由不关闭它。
但是,为什么要保持它打开呢?这里有一篇有趣的WCF客户端文章,其中提到:

检查System.ServiceModel.ICommunicationObject.State属性的值是一种竞态条件,不建议使用它来确定是否重用或关闭通道。

与其重用通道,您可能希望使用通道工厂创建一个新的通道。这里有更多关于客户端架构的信息

1
当你说“如果你完成了使用工厂创建通道,没有理由不关闭它”,我发现你的回答是不准确的。如果这样做,它将失败 - 请看我的回复。 - Aliostad

4

2
答案已经在这里了,但是它分散在几个评论和回答中,并且不是完全清晰,因此我回答。

应该关闭ChannelFactory和Channel吗?

不需要。如果您想从每个ChannelFactory创建多个Channels,则应该处理ChannelFactory,这将处理所有为您创建的Channels。

如果您想为每个(终结点、绑定)对创建一个通道,则应使用 this static functionChannelFactory<ServiceType>.CreateChannel(binding, endpoint)(它避免了问题,因为它不会创建第二个IDisposable),并且您应该处理它返回的通道。

处理ChannelFactory和任何它创建的通道都会引发ObjectDisposed异常。


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