客户端与 WCF 服务交互的更好方法





5.00/5 (2投票s)
一个允许以健壮的方式使用 WCF 服务的组件

引言
在我看来,微软在用于连接服务的通用 ClientBase 实现方面失败了。当与服务通信期间出现问题时,客户端基本实现中包含的通道将变为无效。
缺点是这个通道无法恢复以供重用。唯一的解决方案是释放当前实例并重新创建一个新的实例。这将给开发人员带来压力,因为他们需要实现处理无效通道和重新创建实际客户端代理的代码。
可以想象,这效率不高,并且可能导致问题,因为每个客户端代理都需要以自己的方式实现。某些功能可以复制和粘贴,但这容易出错。
其他解决方案
我做了一些浏览,看看是否其他人也遇到了同样的问题。我发现的唯一有趣的解决方案是在 http://www.acorns.com.au/blog/?p=113 ,它展示了一个在运行时生成的动态代理。这几乎正是我一直在寻找的。然而,这个解决方案对于我的口味来说太复杂了,所以我开始了自己版本的开发,同时重用了一些想法和中间语言生成。
解决问题的方法是将实际的客户端代理(基于 ClientBase)封装在一个特定的类中,该类将包含在出现问题时重新创建代理的功能。然而,问题是服务接口上的调用需要扩展一种检测这些问题的方法。为了能够以通用的方式处理这个问题,我们需要在运行时生成这个功能,以防止我们仍然需要采取行动来保持实现的最新状态。这可以通过创建一个临时程序集来实现,该程序集将包含通过生成中间语言来专门实现接口的实现。
因此,提供了一个通用的 ProxyClassBuilder
,它将生成一个类型,该类型包含处理对服务实现的调用的方法。每个方法将包含捕获异常并相应地处理它们的功能。
代码生成
我将简要解释一下使用以下服务合约时会发生什么情况
[ServiceContract]
public interface ITestService
{
[OperationContract]
void DummyCall();
}
以下操作将触发特定客户端代理的创建,其中包括该方法和将处理发生的任何异常的实现。
clientProxy = ClientProxy.GetInstance("identifier", binding, endpointAddress);
返回的客户端代理派生自 ClientProxy
类,并将包含以下实现
public class TestService : ClientProxy, ITestService
{
// Methods
public TestService(Binding binding1, EndpointAddress address1) :
base(binding1, address1)
{
}
public void DummyCall()
{
try
{
base.Channel.DummyCall();
}
catch (Exception exception)
{
this.HandleException(exception);
}
}
}
它会将方法调用传递给封闭的通道,该通道最终会调用该服务。任何异常都会被捕获并传递给位于基类中的 HandleException
方法。
涉及的类
通用的 ClientProxy
是入口点,并且是要由服务的消费者使用的。它有一个 abstract
方法 GetInstance
,用于获取生成的类的实例。这个生成的类完全由 ProxyClassBuilder
构建。为了性能考虑,ClientProxy
将包含一个已生成的客户端代理的缓存。这确保了在同一客户端中与特定服务的通信是通过代理的一个实例完成的。
通用的 ProxyClassBuilder
负责生成临时类型。此类型在内部缓存,以防止需要多次生成。
通用的 InternalClientProxy
是与服务通信的实际代理。当与服务器的连接以某种方式断开时,将重新创建此代理。
封闭的解决方案
封闭的解决方案包含 3 个项目
- 包含一个简单用户界面的测试应用程序,它支持启动/停止服务、调用客户端代理上的方法以及记录有关该过程的一些信息。
- 测试服务本身,它同时包含接口和实现。这不是正确的方式,但嘿,这只是一个例子。
- 动态客户端代理的实际实现。这包含使用中间语言生成客户端代理的有趣部分。
历史
- 2010 年 11 月 8 日 - 第一个版本