动态代理在WCF服务中的应用

状态保持的应用程序中使用WCF服务时,可能会遇到服务出现故障状态或需要关闭的情况。本文将探讨一种可能的解决方案,即使用动态代理方法来处理这些问题,而不会破坏原有的服务契约。这样,视图模型(ViewModel)就可以依赖于服务接口,而不需要知道它实际上是在使用WCF。

考虑一个视图模型,它将WCF服务注入到其中。这里有几个需要注意的问题:

  • 当服务出现故障时,如何处理,而用户仍在使用窗口?
  • 如何确保服务被正确清理?
  • 如何在不破坏服务接口的情况下,实现上述两点?

为了扩展第三点,希望利用服务暴露的接口(无论是生成的文件还是共享的DLL),并且希望提供方便的单元测试(一些模拟框架可能无法与具体类一起工作)。本文将探讨使用动态代理的解决方案。

如何使用

如果想直接使用这个解决方案,以下是需要做的:

  1. 添加对Castle.Core的引用。
  2. 下载WcfChannelProxy.zip项目,并将两个文件复制到项目中。
  3. 在应用程序中创建视图时,创建所需的服务依赖项(直接通过WcfClientFactory或使用IoC容器),并将实例注入到视图模型中。
_service1 = new WcfProxy.WcfClientFactory().CreateClient<IService1>(); MainViewModel vm = new MainViewModel(_service1); MainWindow window = new MainWindow(vm);

要处理服务的释放,也很简单:

// 确保释放通道,这通常会被IoC容器处理 ((IDisposable) _service1).Dispose();

本文的其余部分讨论了解决方案的工作原理,并提供了一些更多的上下文。

VS示例解决方案概述

提供了一个示例VS解决方案,以演示解决方案的使用,并突出显示了约束的应用。解决方案由五个项目组成,如下所示:

  • WCF主机 - 托管WCF服务的Web应用程序(这是一个新建的WCF服务项目,增加了一个客户端策略,以允许Silverlight客户端访问)。
  • WPF客户端 - 一个简单的WPF客户端。
  • Sl客户端 - 使用版本5的简单Silverlight客户端。
  • Sl主机 - 托管Silverlight XAP项目的Web应用程序。
  • 测试 - 测试动态项目的拦截器。

两个客户端解决方案都使用动态代理(WcfProxy)来处理调用Web服务。它们都使用生成的服务引用,但解决方案也可以与共享DLL方法一起工作(其中单独的DLL包含服务接口和DTO)。

解决方案概述

解决方案使用Castle的动态代理(WcfProxy)来提供服务接口的实现,并保护视图模型免受通道维护的影响。

服务的目标是让客户端注入服务的接口,这样视图模型就只需要知道它们的操作。以下是一个示例服务:

[ServiceContract] public interface IService1 { [OperationContract] string GetData(int value); [OperationContract] CompositeType GetDataUsingDataContract(CompositeType composite); }

没有Close、Abort或Dispose方法。Close和Abort可以通过生成ServiceClient类(这不是一个接口,更难模拟和测试)或直接使用通道(然而,消费类将直接知道WCF)。

视图模型

视图模型依赖于关键点;依赖接口将定义视图模型可用的操作。鉴于已经将Service1(上面定义的)注入到视图模型中,这意味着视图模型无法调节通道。

以下是一个依赖于Service1的视图模型,通过构造函数注入:

public class MainViewModel : INotifyPropertyChanged { private readonly IService1 _service1; private string _result; public MainViewModel(IService1 service1) { _service1 = service1; GetDataCmd = new DelegateCommand<object>(GetData); PropertyChanged += delegate { }; } public string Result { get { return _result; } set { _result = value; PropertyChanged(this, new PropertyChangedEventArgs("Result")); } } public ICommand GetDataCmd { get; private set; } private void GetData(object o) { Result = _service1.GetData(123); } public event PropertyChangedEventHandler PropertyChanged; }

代理和通道工厂管理器

使用稍微修改过的ChannelFactoryManager类。这个类用于创建和维护通道工厂,并创建新的通道实例。

解决方案构建了一个动态代理,实现了服务接口,在这种情况下是IService1。代理实例有一个WCF通道用于服务,它维护该通道。当通道出现故障时,代理将清理故障通道,并从ChannelFactoryManager请求一个新的通道。

public class WcfClientFactory { private static readonly ProxyGenerator Generator = new ProxyGenerator(); private readonly IChannelFactoryManager _manager = new ChannelFactoryManager(); public T CreateClient<T>() where T : class { var service = _manager.CreateChannel<T>(); var proxy = Generator.CreateInterfaceProxyWithTargetInterface( typeof(T), new[] { typeof(IDisposable) }, service, new WcfClientInterceptor<T>(service)); return (T)proxy; } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485