如何在WCF中使用动态代理
这篇文章主要介绍“如何在WCF中使用动态代理”,在日常操作中,相信很多人在如何在WCF中使用动态代理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何在WCF中使用动态代理”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
一、重构前的项目代码
重构前的项目代码共7层代码,其中WCF服务端3层,WCF接口层1层,客户端3层,共7层
1.服务端WCF服务层SunCreate.InfoPlatform.Server.Service
2.服务端数据库访问接口层SunCreate.InfoPlatform.Server.Bussiness
3.服务端数据库访问实现层SunCreate.InfoPlatform.Server.Bussiness.Impl
4.WCF接口层SunCreate.InfoPlatform.Contract
5.客户端代理层SunCreate.InfoPlatform.Client.Proxy
6.客户端业务接口层SunCreate.InfoPlatform.Client.Bussiness
7.客户端业务实现层SunCreate.InfoPlatform.Client.Bussiness.Impl
二、客户端通过动态代理重构
1.实现在拦截器中添加Ticket、处理异常、Close对象
2.客户端不需要再写代理层代码,而使用动态代理层
3.对于简单的增删改查业务功能,也不需要再写业务接口层和业务实现层,直接调用动态代理;对于复杂的业务功能以及缓存,才需要写业务接口层和业务实现层
客户端动态代理工厂类ProxyFactory代码(该代码目前写在客户端业务实现层):
usingCastle.DynamicProxy; usingSystem; usingSystem.Collections.Concurrent; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.ServiceModel; usingSystem.Text; usingSystem.Threading.Tasks; namespaceSunCreate.InfoPlatform.Client.Bussiness.Imp { ///<summary> ///WCF服务工厂 ///PF是ProxyFactory的简写 ///</summary> publicclassPF { ///<summary> ///拦截器缓存 ///</summary> privatestaticConcurrentDictionary<Type,IInterceptor>_interceptors=newConcurrentDictionary<Type,IInterceptor>(); ///<summary> ///代理对象缓存 ///</summary> privatestaticConcurrentDictionary<Type,object>_objs=newConcurrentDictionary<Type,object>(); privatestaticProxyGenerator_proxyGenerator=newProxyGenerator(); ///<summary> ///获取WCF服务 ///</summary> ///<typeparamname="T">WCF接口</typeparam> publicstaticTGet<T>() { TypeinterfaceType=typeof(T); IInterceptorinterceptor=_interceptors.GetOrAdd(interfaceType,type=> { stringserviceName=interfaceType.Name.Substring(1);//服务名称 ChannelFactory<T>channelFactory=newChannelFactory<T>(serviceName); returnnewProxyInterceptor<T>(channelFactory); }); return(T)_objs.GetOrAdd(interfaceType,type=>_proxyGenerator.CreateInterfaceProxyWithoutTarget(interfaceType,interceptor));//根据接口类型动态创建代理对象,接口没有实现类 } } }
客户端拦截器类ProxyInterceptor<T>代码(该代码目前写在客户端业务实现层):
usingCastle.DynamicProxy; usinglog4net; usingSunCreate.Common.Base; usingSunCreate.InfoPlatform.Client.Bussiness; usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Reflection; usingSystem.ServiceModel; usingSystem.ServiceModel.Channels; usingSystem.Text; usingSystem.Threading.Tasks; namespaceSunCreate.InfoPlatform.Client.Bussiness.Imp { ///<summary> ///拦截器 ///</summary> ///<typeparamname="T">接口</typeparam> publicclassProxyInterceptor<T>:IInterceptor { privatestaticILog_log=LogManager.GetLogger(typeof(ProxyInterceptor<T>)); privateChannelFactory<T>_channelFactory; publicProxyInterceptor(ChannelFactory<T>channelFactory) { _channelFactory=channelFactory; } ///<summary> ///拦截方法 ///</summary> publicvoidIntercept(IInvocationinvocation) { //准备参数 ParameterInfo[]parameterInfoArr=invocation.Method.GetParameters(); object[]valArr=newobject[parameterInfoArr.Length]; for(inti=0;i<parameterInfoArr.Length;i++) { valArr[i]=invocation.GetArgumentValue(i); } //执行方法 Tserver=_channelFactory.CreateChannel(); using(OperationContextScopescope=newOperationContextScope(serverasIContextChannel)) { try { HI.Get<ISecurityBussiness>().AddTicket(); invocation.ReturnValue=invocation.Method.Invoke(server,valArr); varvalue=HI.Get<ISecurityBussiness>().GetValue(); ((IChannel)server).Close(); } catch(Exceptionex) { _log.Error("ProxyInterceptor"+typeof(T).Name+""+invocation.Method.Name+"异常",ex); ((IChannel)server).Abort(); } } //out和ref参数处理 for(inti=0;i<parameterInfoArr.Length;i++) { ParameterInfoparamInfo=parameterInfoArr[i]; if(paramInfo.IsOut||paramInfo.ParameterType.IsByRef) { invocation.SetArgumentValue(i,valArr[i]); } } } } }
如何使用:
List<EscortTask>list=PF.Get<IBussDataService>().GetEscortTaskList();
这里不用再写try catch,异常在拦截器中处理
三、WCF服务端通过动态代理,在拦截器中校验Ticket、处理异常
服务端动态代理工厂类ProxyFactory代码(代码中保存动态代理dll不是必需的):
usingAutofac; usingCastle.DynamicProxy; usingCastle.DynamicProxy.Generators; usingSunCreate.Common.Base; usingSystem; usingSystem.Collections.Concurrent; usingSystem.Collections.Generic; usingSystem.IO; usingSystem.Linq; usingSystem.Reflection; usingSystem.ServiceModel; usingSystem.ServiceModel.Activation; usingSystem.Text; usingSystem.Threading.Tasks; namespaceSunCreate.InfoPlatform.WinService { ///<summary> ///动态代理工厂 ///</summary> publicclassProxyFactory { ///<summary> ///拦截器缓存 ///</summary> privatestaticConcurrentDictionary<Type,IInterceptor>_interceptors=newConcurrentDictionary<Type,IInterceptor>(); ///<summary> ///代理对象缓存 ///</summary> privatestaticConcurrentDictionary<Type,object>_objs=newConcurrentDictionary<Type,object>(); privatestaticProxyGenerator_proxyGenerator; privatestaticModuleScope_scope; privatestaticProxyGenerationOptions_options; staticProxyFactory() { AttributesToAvoidReplicating.Add(typeof(ServiceContractAttribute));//动态代理类不继承接口的ServiceContractAttribute Stringpath=AppDomain.CurrentDomain.BaseDirectory; _scope=newModuleScope(true,false, ModuleScope.DEFAULT_ASSEMBLY_NAME, Path.Combine(path,ModuleScope.DEFAULT_FILE_NAME), "MyDynamicProxy.Proxies", Path.Combine(path,"MyDymamicProxy.Proxies.dll")); varbuilder=newDefaultProxyBuilder(_scope); _options=newProxyGenerationOptions(); //给动态代理类添加AspNetCompatibilityRequirementsAttribute属性 PropertyInfoproInfoAspNet=typeof(AspNetCompatibilityRequirementsAttribute).GetProperty("RequirementsMode"); CustomAttributeInfocustomAttributeInfo=newCustomAttributeInfo(typeof(AspNetCompatibilityRequirementsAttribute).GetConstructor(newType[0]),newobject[0],newPropertyInfo[]{proInfoAspNet},newobject[]{AspNetCompatibilityRequirementsMode.Allowed}); _options.AdditionalAttributes.Add(customAttributeInfo); //给动态代理类添加ServiceBehaviorAttribute属性 PropertyInfoproInfoInstanceContextMode=typeof(ServiceBehaviorAttribute).GetProperty("InstanceContextMode"); PropertyInfoproInfoConcurrencyMode=typeof(ServiceBehaviorAttribute).GetProperty("ConcurrencyMode"); customAttributeInfo=newCustomAttributeInfo(typeof(ServiceBehaviorAttribute).GetConstructor(newType[0]),newobject[0],newPropertyInfo[]{proInfoInstanceContextMode,proInfoConcurrencyMode},newobject[]{InstanceContextMode.Single,ConcurrencyMode.Multiple}); _options.AdditionalAttributes.Add(customAttributeInfo); _proxyGenerator=newProxyGenerator(builder); } ///<summary> ///动态创建代理 ///</summary> publicstaticobjectCreateProxy(TypecontractInterfaceType,TypeimpInterfaceType) { IInterceptorinterceptor=_interceptors.GetOrAdd(impInterfaceType,type=> { object_impl=HI.Provider.GetService(impInterfaceType); returnnewProxyInterceptor(_impl); }); return_objs.GetOrAdd(contractInterfaceType,type=>_proxyGenerator.CreateInterfaceProxyWithoutTarget(contractInterfaceType,_options,interceptor));//根据接口类型动态创建代理对象,接口没有实现类 } ///<summary> ///保存动态代理dll ///</summary> publicstaticvoidSave() { stringfilePath=Path.Combine(_scope.WeakNamedModuleDirectory,_scope.WeakNamedModuleName); if(File.Exists(filePath)) { File.Delete(filePath); } _scope.SaveAssembly(false); } } }
说明:object _impl = HI.Provider.GetService(impInterfaceType); 这句代码用于创建数据库访问层对象,HI是项目中的一个工具类,类似Autofac框架的功能
服务端拦截器类ProxyInterceptor<T>代码:
usingCastle.DynamicProxy; usinglog4net; usingSunCreate.Common.Base; usingSunCreate.InfoPlatform.Server.Bussiness; usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Reflection; usingSystem.ServiceModel; usingSystem.ServiceModel.Channels; usingSystem.Text; usingSystem.Threading.Tasks; namespaceSunCreate.InfoPlatform.WinService { ///<summary> ///拦截器 ///</summary> publicclassProxyInterceptor:IInterceptor { privatestaticILog_log=LogManager.GetLogger(typeof(ProxyInterceptor)); privateobject_impl; publicProxyInterceptor(objectimpl) { _impl=impl; } ///<summary> ///拦截方法 ///</summary> publicvoidIntercept(IInvocationinvocation) { //准备参数 ParameterInfo[]parameterInfoArr=invocation.Method.GetParameters(); object[]valArr=newobject[parameterInfoArr.Length]; for(inti=0;i<parameterInfoArr.Length;i++) { valArr[i]=invocation.GetArgumentValue(i); } //执行方法 try { if(HI.Get<ISecurityImp>().CheckTicket()) { TypeimplType=_impl.GetType(); MethodInfomethodInfo=implType.GetMethod(invocation.Method.Name); invocation.ReturnValue=methodInfo.Invoke(_impl,valArr); } } catch(Exceptionex) { _log.Error("ProxyInterceptor"+invocation.TargetType.Name+""+invocation.Method.Name+"异常",ex); } //out和ref参数处理 for(inti=0;i<parameterInfoArr.Length;i++) { ParameterInfoparamInfo=parameterInfoArr[i]; if(paramInfo.IsOut||paramInfo.ParameterType.IsByRef) { invocation.SetArgumentValue(i,valArr[i]); } } } } }
服务端WCF的ServiceHost工厂类:
usingSpring.ServiceModel.Activation; usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Reflection; usingSystem.ServiceModel; usingSystem.Text; usingSystem.Threading.Tasks; namespaceSunCreate.InfoPlatform.WinService { publicclassMyServiceHostFactory:ServiceHostFactory { publicMyServiceHostFactory(){} publicoverrideServiceHostBaseCreateServiceHost(stringreference,Uri[]baseAddresses) { AssemblycontractAssembly=Assembly.GetAssembly(typeof(SunCreate.InfoPlatform.Contract.IBaseDataService)); AssemblyimpAssembly=Assembly.GetAssembly(typeof(SunCreate.InfoPlatform.Server.Bussiness.IBaseDataImp)); TypecontractInterfaceType=contractAssembly.GetType("SunCreate.InfoPlatform.Contract.I"+reference); TypeimpInterfaceType=impAssembly.GetType("SunCreate.InfoPlatform.Server.Bussiness.I"+reference.Replace("Service","Imp")); if(contractInterfaceType!=null&&impInterfaceType!=null) { varproxy=ProxyFactory.CreateProxy(contractInterfaceType,impInterfaceType); ServiceHostBasehost=newServiceHost(proxy,baseAddresses); returnhost; } else { returnnull; } } } }
svc文件配置ServiceHost工厂类:
<%@ServiceHostLanguage="C#"Debug="true"Service="BaseDataService"Factory="SunCreate.InfoPlatform.WinService.MyServiceHostFactory"%>
如何使用自定义的ServiceHost工厂类启动WCF服务,下面是部分代码:
MyServiceHostFactoryfactory=newMyServiceHostFactory(); List<ServiceHostBase>hostList=newList<ServiceHostBase>(); foreach(varoFileindirInfo.GetFiles()) { try { stringstrSerName=oFile.Name.Replace(oFile.Extension,""); stringstrUrl=string.Format(m_strBaseUrl,m_serverPort,oFile.Name); varhost=factory.CreateServiceHost(strSerName,newUri[]{newUri(strUrl)}); if(host!=null) { hostList.Add(host); } } catch(Exceptionex) { Console.WriteLine("出现异常:"+ex.Message); m_log.ErrorFormat(ex.Message+ex.StackTrace); } } ProxyFactory.Save(); foreach(varhostinhostList) { try { foreach(varendpointinhost.Description.Endpoints) { endpoint.EndpointBehaviors.Add(newMyEndPointBehavior());//用于添加消息拦截器、全局异常拦截器 } host.Open(); m_lsHost.TryAdd(host); } catch(Exceptionex) { Console.WriteLine("出现异常:"+ex.Message); m_log.ErrorFormat(ex.Message+ex.StackTrace); } }
WCF服务端再也不用写Service层了
四、当我需要添加一个WCF接口,以实现一个查询功能,比如查询所有组织机构,重构前,我需要在7层添加代码,然后客户端调用,重构后,我只需要在3层添加代码,然后客户端调用
1.在WCF接口层添加接口
2.在服务端数据访问接口层添加接口
3.在服务端数据访问实现层添加实现方法
4.客户端调用:var orgList = PF.Get<IBaseDataService>().GetOrgList();
重构前,需要在7层添加代码,虽然每层代码都差不多,可以复制粘贴,但是复制粘贴也很麻烦啊,重构后省事多了,从此再也不怕写增删改查了
到此,关于“如何在WCF中使用动态代理”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注恰卡编程网网站,小编会继续努力为大家带来更多实用的文章!