使用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(interfaceType, 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(interfaceType, 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 = https://www.cnblogs.com/s0611163/archive/2020/12/18/HI.GetView Code().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]); } } } } }
如何使用:
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倍,但是多花費的時間跟資料庫查詢耗時比起來,是微不足道的
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/236847.html
標籤:.NET技术
上一篇:WPF源代碼分析系列一:剖析WPF模板機制的內部實作(五)
下一篇:Nlog的使用
