WCF如何使用动态代理精简代码架构
使用Castle.Core.dll实现,核心代码是使用Castle.DynamicProxy.ProxyGenerator类的CreateInterfaceProxyWithoutTarget方法动态创建代理对象
NuGet上面Castle.Core的下载量1.78亿之多
一、重构前的项目代码
重构前的项目代码共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 { //////WCF服务工厂 ///PF是ProxyFactory的简写 /// publicclassPF { //////拦截器缓存 /// privatestaticConcurrentDictionary_interceptors=newConcurrentDictionary (); /// ///代理对象缓存 /// privatestaticConcurrentDictionary_objs=newConcurrentDictionary (); privatestaticProxyGenerator_proxyGenerator=newProxyGenerator(); /// ///获取WCF服务 /// ///WCF接口 publicstaticTGet () { TypeinterfaceType=typeof(T); IInterceptorinterceptor=_interceptors.GetOrAdd(interfaceType,type=> { stringserviceName=interfaceType.Name.Substring(1);//服务名称 ChannelFactory channelFactory=newChannelFactory (serviceName); returnnewProxyInterceptor (channelFactory); }); return(T)_objs.GetOrAdd(interfaceType,type=>_proxyGenerator.CreateInterfaceProxyWithoutTarget(interfaceType,interceptor));//根据接口类型动态创建代理对象,接口没有实现类 } } }
客户端拦截器类ProxyInterceptor
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 { //////拦截器 /// ///接口 publicclassProxyInterceptor :IInterceptor { privatestaticILog_log=LogManager.GetLogger(typeof(ProxyInterceptor )); privateChannelFactory _channelFactory; publicProxyInterceptor(ChannelFactory channelFactory) { _channelFactory=channelFactory; } /// ///拦截方法 /// publicvoidIntercept(IInvocationinvocation) { //准备参数 ParameterInfo[]parameterInfoArr=invocation.Method.GetParameters(); object[]valArr=newobject[parameterInfoArr.Length]; for(inti=0;i().AddTicket(); invocation.ReturnValue=invocation.Method.Invoke(server,valArr); varvalue=HI.Get ().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 如何使用:
Listlist=PF.Get ().GetEscortTaskList(); 这里不用再写trycatch,异常在拦截器中处理
三、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 { //////动态代理工厂 /// publicclassProxyFactory { //////拦截器缓存 /// privatestaticConcurrentDictionary_interceptors=newConcurrentDictionary (); /// ///代理对象缓存 /// privatestaticConcurrentDictionary_objs=newConcurrentDictionary (); 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); } /// ///动态创建代理 /// 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));//根据接口类型动态创建代理对象,接口没有实现类 } //////保存动态代理dll /// 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
代码: 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 { //////拦截器 /// publicclassProxyInterceptor:IInterceptor { privatestaticILog_log=LogManager.GetLogger(typeof(ProxyInterceptor)); privateobject_impl; publicProxyInterceptor(objectimpl) { _impl=impl; } //////拦截方法 /// publicvoidIntercept(IInvocationinvocation) { //准备参数 ParameterInfo[]parameterInfoArr=invocation.Method.GetParameters(); object[]valArr=newobject[parameterInfoArr.Length]; for(inti=0;i().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 服务端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(); ListhostList=newList (); 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.客户端调用:varorgList=PF.Get
().GetOrgList(); 重构前,需要在7层添加代码,虽然每层代码都差不多,可以复制粘贴,但是复制粘贴也很麻烦啊,重构后省事多了,从此再也不怕写增删改查了
五、性能损失
主要是invocation.Method.Invoke比直接调用慢,耗时是直接调用的2、3倍,但是多花费的时间跟数据库查询耗时比起来,是微不足道的
以上就是WCF如何使用动态代理精简代码架构的详细内容,更多关于WCF使用动态代理精简代码架构的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。