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);//服务名称
ChannelFactorychannelFactory=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(ChannelFactorychannelFactory)
{
_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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
          