在与服务进行通信时,经常会遇到ClientBase实现的通道失效的问题。当通信过程中出现问题时,这个通道就会变得无效,而且无法恢复,只能通过销毁当前实例并重新创建一个新的实例来解决。这种做法对开发者来说是一个负担,因为他们需要实现代码来处理无效的通道,并重新创建实际的客户端代理。这种方法不仅效率低下,而且由于每个客户端代理都需要以自己的方式实现,可能会导致错误。
为了解决这个问题,进行了一些研究,发现了一个有趣的解决方案,它通过在运行时生成动态代理来实现。虽然这个解决方案几乎完全符合需求,但对来说过于复杂,所以开始创建自己的版本,同时借鉴了一些想法和中间语言生成。
解决方案的核心是将基于ClientBase的实际客户端代理封装在一个特定的类中,这个类包含了在出现问题时重新创建代理的功能。然而,服务接口上的调用需要扩展一种检测问题的方法。为了以通用的方式处理这个问题,需要在运行时生成这个功能,以防止仍然需要更新实现。这可以通过创建一个临时程序集来实现,该程序集将包含通过生成中间语言来实现接口的具体实现。
当使用以下服务合同时:
C#
[
ServiceContract
]
public
interface
ITestService
{
[OperationContract]
void
DummyCall();
}
上述代码将触发创建特定的客户端代理,包括方法和处理任何异常的实现。
C#
clientProxy = ClientProxy<itestservice />.GetInstance(
"
identifier"
, binding, endpointAddress);
返回的客户端代理是从ClientProxy类派生的,并将包含以下实现:
C#
public
class
TestService : ClientProxy<itestservice />, 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是入口点,也是服务的消费者要使用的类。它有一个抽象方法GetInstance,用于获取生成类的实例。这个生成的类完全由ProxyClassBuilder构建。为了性能问题,ClientProxy将包含一个已经生成的客户端代理的缓存,以确保与某个服务的通信在同一客户端代理的一个实例中进行。
通用的ProxyClassBuilder负责生成一个临时类型。这个类型在内部被缓存,以防止它需要被生成多次。
通用的InternalClientProxy是实际与服务通信的代理。当与服务器的连接以某种方式被切断时,这个代理会被重新创建。