WCF 通道的正确使用和处置(或 CommunicationObjectFaultedException?!*#*$)






4.85/5 (12投票s)
在这篇文章中,我将探讨期望 'using' 块清理你的 WCF 通道所带来的微妙但灾难性的后果。
在这篇文章中,我将探讨期望 using
块清理你的 WCF 通道所带来的微妙但灾难性的后果。
注意:示例展示了生成代理的使用,但该问题和解决方案适用于所有 ICommunicationObject
,包括生成的代理(ClientBase<T>
)以及 ChannelFactory
和 ChannelFactory<T>
。
许多不眠之夜都花在了思考为什么,无论进行何种异常处理,以下代码在 .HelloWorld()
抛出异常时都会抛出 CommunicationObjectFaultedException
,即使该异常已被捕获。
典型的 'using' 处置模式
using (WCFServiceClient c = new WCFServiceClient())
{
try
{
c.HelloWorld();
}
catch (Exception ex)
{
// handle the exception
}
}
请考虑,当在使用通道时发生异常时,它会进入 Faulted
状态,并且在这种 Faulted
状态下,调用 .Close()
将会抛出 CommunicationObjectFaultedException
。
如你所知,using
语句确保在退出 using 块之前调用 .Dispose()
。对于通道,通常具有 private
.Dispose()
方法,.Dispose()
只是简单地调用 .Close()
。啊哈!你明白我的意思了吗?
典型的 using
处置模式陷阱说明
using (WCFServiceClient c = new WCFServiceClient())
{
try
{
c.HelloWorld();
}
catch (Exception ex)
{
// You don't know it yet but your mellow has just been harshed.
// If you handle this exception and fall through you will
// still be cheerfully greeted with an unhandled
// CommunicationObjectFaultedException when 'using' tries to .Close() the client.
// If you throw or re-throw from here you will never see that exception,
// it is gone forever.
// buh bye.
// All you will get is an unhandled CommunicationObjectFaultedException
}
} // <-- here is where the CommunicationObjectFaultedException is thrown
解决此问题的办法是确保通道在关闭 using
块时能够成功过渡到 Closed
状态。这可以通过在你的 catch
块中调用 .Abort()
来确认 Faulted
状态,从而实际关闭通道,尽管方式比较突然。任何后续的 .Close()
调用都将无效。
正确的 using
处置模式
using (WCFServiceClient client = new WCFServiceClient())
{
try
{
client.ThrowException();
}
catch (Exception ex)
{
// acknowledge the Faulted state and transition to Closed
client.Abort();
// handle the exception or rethrow, makes no nevermind to me, my
// yob is done ;-D
}
}
在某些情况下,你的周围代码的结构并不适合使用 using
块。
虽然 using
块具有其优点,例如块提供的作用域,但在通道的上下文中,它所做的只是调用 .Close()
,而我们可以很容易地做到这一点。
不使用 using
的通道的正确使用
WCFServiceClient c = new WCFServiceClient();
try
{
c.HelloWorld();
}
catch
{
// acknowledge the Faulted state and transition to Closed
c.Abort();
// handle or throw
throw;
}
finally
{
c.Close();
}
这就是我对 WCF 通道的正确使用和处置的看法。