如何在WCF中使用动态代理

这篇文章主要介绍“如何在WCF中使用动态代理”,在日常操作中,相信很多人在如何在WCF中使用动态代理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何在WCF中使用动态代理”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、重构前的项目代码

重构前的项目代码共7层代码,其中WCF服务端3层,WCF接口层1层,客户端3层,共7层

如何在WCF中使用动态代理

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中使用动态代理”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注恰卡编程网网站,小编会继续努力为大家带来更多实用的文章!

发布于 2021-03-13 15:41:09
收藏
分享
海报
0 条评论
164
上一篇:R语言如何实现LASSO回归 下一篇:使用Nodejs怎么编写一个定时爬虫
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码