WCF 动态代理与拦截器

  • A+
所属分类:.NET技术
摘要

使用Castle.Core.dll实现,核心代码是使用Castle.DynamicProxy.ProxyGenerator类的CreateInterfaceProxyWithoutTarget方法动态创建代理对象

使用Castle.Core.dll实现,核心代码是使用Castle.DynamicProxy.ProxyGenerator类的CreateInterfaceProxyWithoutTarget方法动态创建代理对象

NuGet上面Castle.Core的下载量1.78亿之多

1.WCF服务端通过动态代理,在拦截器中校验Ticket、处理异常

服务端动态代理工厂类ProxyFactory代码:

WCF 动态代理与拦截器WCF 动态代理与拦截器

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>代码:

WCF 动态代理与拦截器WCF 动态代理与拦截器

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

如何使用:

WCF 动态代理与拦截器WCF 动态代理与拦截器

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代码:

WCF 动态代理与拦截器WCF 动态代理与拦截器

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>代码:

WCF 动态代理与拦截器WCF 动态代理与拦截器

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

如何使用:

WCF 动态代理与拦截器WCF 动态代理与拦截器

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倍,但是多花费的时间跟数据库查询耗时比起来,是微不足道的