- A+
所属分类:.NET技术
使用Castle.Core.dll实现,核心代码是使用Castle.DynamicProxy.ProxyGenerator类的CreateInterfaceProxyWithoutTarget方法动态创建代理对象
NuGet上面Castle.Core的下载量1.78亿之多
1.WCF服务端通过动态代理,在拦截器中校验Ticket、处理异常
服务端动态代理工厂类ProxyFactory代码:
using Castle.DynamicProxy; using SunCreate.Common.Base; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.ServiceModel; using System.Text; using System.Threading.Tasks; namespace SunCreate.InfoPlatform.Server.Service { /// <summary> /// 动态代理工厂 /// </summary> public class ProxyFactory { /// <summary> /// 拦截器缓存 /// </summary> private static ConcurrentDictionary<Type, IInterceptor> _interceptors = new ConcurrentDictionary<Type, IInterceptor>(); /// <summary> /// 代理对象缓存 /// </summary> private static ConcurrentDictionary<Type, object> _objs = new ConcurrentDictionary<Type, object>(); private static ProxyGenerator _proxyGenerator = new ProxyGenerator(); /// <summary> /// 动态创建代理 /// </summary> /// <typeparam name="T">接口</typeparam> public static T CreateProxy<T>() { Type interfaceType = typeof(T); IInterceptor interceptor = _interceptors.GetOrAdd(interfaceType, type => { string serviceName = interfaceType.Name.Substring(1); //服务名称 T _impl = HI.Get<T>(); return new ProxyInterceptor<T>(_impl); }); return (T)_objs.GetOrAdd(interfaceType, type => _proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof(T), interceptor)); //根据接口类型动态创建代理对象,接口没有实现类 } } }
View Code
服务端拦截器类ProxyInterceptor<T>代码:
using Castle.DynamicProxy; using log4net; using SunCreate.Common.Base; using SunCreate.InfoPlatform.Server.Bussiness; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.ServiceModel; using System.ServiceModel.Channels; using System.Text; using System.Threading.Tasks; namespace SunCreate.InfoPlatform.Server.Service { /// <summary> /// 拦截器 /// </summary> /// <typeparam name="T">接口</typeparam> public class ProxyInterceptor<T> : IInterceptor { private static ILog _log = LogManager.GetLogger(typeof(ProxyInterceptor<T>)); private T _impl; public ProxyInterceptor(T impl) { _impl = impl; } /// <summary> /// 拦截方法 /// </summary> public void Intercept(IInvocation invocation) { //准备参数 ParameterInfo[] parameterInfoArr = invocation.Method.GetParameters(); object[] valArr = new object[parameterInfoArr.Length]; for (int i = 0; i < parameterInfoArr.Length; i++) { valArr[i] = invocation.GetArgumentValue(i); } //执行方法 try { if (HI.Get<ISecurityImp>().CheckTicket()) { invocation.ReturnValue = invocation.Method.Invoke(_impl, valArr); } } catch (Exception ex) { _log.Error("ProxyInterceptor " + typeof(T).Name + " " + invocation.Method.Name + " 异常", ex); } //out和ref参数处理 for (int i = 0; i < parameterInfoArr.Length; i++) { ParameterInfo paramInfo = parameterInfoArr[i]; if (paramInfo.IsOut || paramInfo.ParameterType.IsByRef) { invocation.SetArgumentValue(i, valArr[i]); } } } } }
View Code
如何使用:
public List<EscortTask> GetEscortTaskList() { var impl = ProxyFactory.CreateProxy<SunCreate.InfoPlatform.Server.Bussiness.IBussDataImp>(); return impl.GetEscortTaskList(); }
View Code
这里不用再写try catch
2.WCF客户端通过动态代理,在拦截器中添加Ticket、处理异常、Close对象
客户端动态代理工厂类ProxyFactory代码:
using Castle.DynamicProxy; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.ServiceModel; using System.Text; using System.Threading.Tasks; namespace SunCreate.InfoPlatform.Client.Bussiness.Imp { /// <summary> /// 动态代理工厂 /// </summary> public class ProxyFactory { /// <summary> /// 拦截器缓存 /// </summary> private static ConcurrentDictionary<Type, IInterceptor> _interceptors = new ConcurrentDictionary<Type, IInterceptor>(); /// <summary> /// 代理对象缓存 /// </summary> private static ConcurrentDictionary<Type, object> _objs = new ConcurrentDictionary<Type, object>(); private static ProxyGenerator _proxyGenerator = new ProxyGenerator(); /// <summary> /// 动态创建代理 /// </summary> /// <typeparam name="T">接口</typeparam> public static T CreateProxy<T>() { Type interfaceType = typeof(T); IInterceptor interceptor = _interceptors.GetOrAdd(interfaceType, type => { string serviceName = interfaceType.Name.Substring(1); //服务名称 ChannelFactory<T> channelFactory = new ChannelFactory<T>(serviceName); return new ProxyInterceptor<T>(channelFactory); }); return (T)_objs.GetOrAdd(interfaceType, type => _proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof(T), interceptor)); //根据接口类型动态创建代理对象,接口没有实现类 } } }
View Code
客户端拦截器类ProxyInterceptor<T>代码:
using Castle.DynamicProxy; using log4net; using SunCreate.Common.Base; using SunCreate.InfoPlatform.Client.Bussiness; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.ServiceModel; using System.ServiceModel.Channels; using System.Text; using System.Threading.Tasks; namespace SunCreate.InfoPlatform.Client.Bussiness.Imp { /// <summary> /// 拦截器 /// </summary> /// <typeparam name="T">接口</typeparam> public class ProxyInterceptor<T> : IInterceptor { private static ILog _log = LogManager.GetLogger(typeof(ProxyInterceptor<T>)); private ChannelFactory<T> _channelFactory; public ProxyInterceptor(ChannelFactory<T> channelFactory) { _channelFactory = channelFactory; } /// <summary> /// 拦截方法 /// </summary> public void Intercept(IInvocation invocation) { //准备参数 ParameterInfo[] parameterInfoArr = invocation.Method.GetParameters(); object[] valArr = new object[parameterInfoArr.Length]; for (int i = 0; i < parameterInfoArr.Length; i++) { valArr[i] = invocation.GetArgumentValue(i); } //执行方法 T server = _channelFactory.CreateChannel(); using (OperationContextScope scope = new OperationContextScope(server as IContextChannel)) { try { HI.Get<ISecurityBussiness>().AddTicket(); invocation.ReturnValue = invocation.Method.Invoke(server, valArr); var value = HI.Get<ISecurityBussiness>().GetValue(); ((IChannel)server).Close(); } catch (Exception ex) { _log.Error("ProxyInterceptor " + typeof(T).Name + " " + invocation.Method.Name + " 异常", ex); ((IChannel)server).Abort(); } } //out和ref参数处理 for (int i = 0; i < parameterInfoArr.Length; i++) { ParameterInfo paramInfo = parameterInfoArr[i]; if (paramInfo.IsOut || paramInfo.ParameterType.IsByRef) { invocation.SetArgumentValue(i, valArr[i]); } } } } }
View Code
如何使用:
public List<EscortTask> GetEscortTaskList() { var service = ProxyFactory.CreateProxy<SunCreate.InfoPlatform.Contract.IBussDataService>(); return service.GetEscortTaskList(); }
View Code
这里不用再写try catch
3.性能损失
主要是invocation.Method.Invoke比直接调用慢,耗时是直接调用的2、3倍,但是多花费的时间跟数据库查询耗时比起来,是微不足道的