放心,這次不是說設計模式中的代理模式,說的是C#的RealProxy的用法,主要用於:通過給class 貼標簽,讓class做更多的工作,比如判斷是否存在緩存,有則直接返回緩存object,沒有則保存為緩 存,等待下次請求是可以更快的獲取數據(當然這只是其中一種常用用途,MVC的Action就是采用這種 方式)
下面是序列圖:
.Net Object Generation interceptor屬於.NET自身行為,不需要額外寫代碼。
Code Consumer指想調用RealObject來進行調用的對象,比如控制台程序,或者WEB程序。
ProxyAttribute裡定義了具體代理類是哪個,這個代理類是自己 繼承RealProxy寫的一個代理類, 這個類中需要加入前置、後置、環繞等方法(具體根據需求)
下面我們來看具體如何在.Net中實現:
public class FollowAction { public bool StopExecute { get; set; } //用於在前置方法中,指示是否停止執行真正的方法體,比如已經找到了cache value,因此不需要繼續運行方法體的情況 public object Result { get; set; } //保存cache value的變量 } public abstract class CachableRealProxy : RealProxy { private MarshalByRefObject target; public MyAOPRealProxy(Type objType, MarshalByRefObject obj) : base(objType) { target = obj; } public override IMessage Invoke(IMessage msg) { IMessage retMsg = null; IMethodCallMessage methodCall = (IMethodCallMessage)msg; IMethodReturnMessage methodReturn = null; object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[]; methodCall.Args.CopyTo(copiedArgs, 0); if (msg is IConstructionCallMessage) { IConstructionCallMessage ccm = (IConstructionCallMessage)msg; RemotingServices.GetRealProxy(target).InitializeServerObject(ccm); ObjRef oRef = RemotingServices.Marshal(target); RemotingServices.Unmarshal(oRef); retMsg = EnterpriseServicesHelper.CreateConstructionReturnMessage(ccm, (MarshalByRefObject)this.GetTransparentProxy()); } else { bool aopAttributeExists = false; object[] attrs = methodCall.MethodBase.GetCustomAttributes(false); if (attrs != null && attrs.Count() > 0) { foreach(object o in attrs) { CachableAttribute attr = o as CachableAttribute; if (attr != null) { aopAttributeExists = true; break; } } } FollowAction follow=null; if (aopAttributeExists) follow = this.PreProcess(msg); try { object returnValue = null; if (follow != null && follow.StopExecute) returnValue = follow.Result; else returnValue = methodCall.MethodBase.Invoke(this.target, copiedArgs); methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall); if (follow == null || !follow.StopExecute) if (aopAttributeExists) this.PostProcess(msg, methodReturn); } catch (Exception ex) { if (null != ex.InnerException) { methodReturn = new ReturnMessage(ex.InnerException, methodCall); } else { methodReturn = new ReturnMessage(ex, methodCall); } } retMsg = methodReturn; } return retMsg; } public override FollowAction PreProcess(System.Runtime.Remoting.Messaging.IMessage requestMsg) //處理前置方法 { bool cacheDefinationTagExists = true; CachableAttribute cacheDefine = CheckCacheDefinationTag(requestMsg, ref cacheDefinationTagExists); if (!cacheDefinationTagExists) return null; string cacheKey = cacheDefine.GenerateCacheKey(); object o=CacheManager.Instance().GetCacheCore().Get(cacheDefine.Location, cacheKey); if (o != null) { FollowAction follow = new FollowAction(); follow.Result = o; follow.StopExecute = true; return follow; } return null; } public override void PostProcess(System.Runtime.Remoting.Messaging.IMessage requestMsg, System.Runtime.Remoting.Messaging.IMessage responseMsg)//處理後置方法 { bool cacheDefinationTagExists = true; CachableAttribute cacheDefine = CheckCacheDefinationTag(requestMsg, ref cacheDefinationTagExists); if (!cacheDefinationTagExists) return; ReturnMessage returnMsg = (ReturnMessage)responseMsg; string cacheKey = cacheDefine.GenerateCacheKey(); CacheManager.Instance().GetCacheCore().Set(cacheDefine.Location, cacheKey, returnMsg.ReturnValue); } private static CachableAttribute CheckCacheDefinationTag(System.Runtime.Remoting.Messaging.IMessage requestMsg, ref bool cacheDefinationTagExists)//Help函數 { IMethodCallMessage methodCall = (IMethodCallMessage)requestMsg; object[] attrs = methodCall.MethodBase.GetCustomAttributes(typeof(CachableAttribute), false); if (attrs == null || attrs.Count() <= 0) cacheDefinationTagExists = false; CachableAttribute cacheDefine = attrs[0] as CachableAttribute; if (cacheDefine == null) cacheDefinationTagExists = false; return cacheDefine; } }
還需要2個Attribute: 如上代碼中用到的CachableAttribute和CachableEnabledAttribute
CachableAttribute用來貼在各個函數簽名上,可以指定cache的key等信息(繼承自普通的 Attribute)
CachableEnabledAttribute用來關聯 自定義proxy以及需要被代理的class的,用法是貼在被代理的 class簽名上(繼承自ProxyAttribute)
代碼如下:
public class CachableAttribute : Attribute { public string Location { get; set; } public string Key { get; set; } public CacheAction CacheAction { get; set; } public string KeyPath { get; set; } public object CacheObject { get; set; } public TimeSpan ExpireTimeSpan { get; set; } public DateTime AbsoluteExpireTime { get; set; } public string GenerateCacheKey() { //will be changed return string.Format("{0}", this.Key); } }
public class CachableEnabledAttribute : ProxyAttribute { public override MarshalByRefObject CreateInstance(Type serverType) { MarshalByRefObject target = base.CreateInstance(serverType); CachableRealProxy rp = new CachableRealProxy(serverType, target); MarshalByRefObject obj = (MarshalByRefObject)rp.GetTransparentProxy(); return obj; } }
被代理的class需要繼承自ContextBoundObject
[CachableEnabled()] public class RealObject : ContextBoundObject { [Cachable(Location = "OrdersQuery", CacheAction = CacheAction.Read, Key = "OrderQueryService_QueryByFirstName_{0}")] public override QueryResult<QueryDto.OrderDto> QueryByFirstName(string firstName, PagingInfo pgInfo) { QueryResult<QueryDto.OrderDto> lst = new QueryResult<QueryDto.OrderDto>(); lst.List = new List<QueryDto.OrderDto>(); lst.TotalCount = 1000; for (int i = 0; i < 1;i++ ) { OrderDto o = new OrderDto(); o.BuyWhat = string.Format("Buywhat {0}", DateTime.Now.ToString()); o.FirstName = string.Format("FirstName {0}", DateTime.Now.ToString()); o.LastName = string.Format("LastName {0}", DateTime.Now.ToString()); o.Email = string.Format("Email {0}", DateTime.Now.ToString()); o.OrderID = Guid.NewGuid(); lst.List.Add(o); } return lst; } }
看下控制台測試代碼:
RealObject srv1 = new RealObject(); while (true) { Thread.Sleep(1000); //每隔1s執行調用,看看返回的時間是否相同,相同則代表已經是cachable的了 QueryResult<OrderDto> lst = srv1.QueryByFirstName("aaron", new CoreFramework.QueryService.PagingInfo() { PageIndex = 0, PageSize = 10, OrderByColumn = "FirstName", IsAscendingSort = true }); foreach (OrderDto order in lst.List) { string msg = string.Format("{0}-{1}-{2}-{3}", order.OrderID, order.FirstName, order.LastName, order.BuyWhat); Console.WriteLine(msg); } }
運行效果圖:
搞定。
查看本欄目