程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C# 代理應用:Cachable

C# 代理應用:Cachable

編輯:關於C#

放心,這次不是說設計模式中的代理模式,說的是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);
                }
            }

運行效果圖:

搞定。

查看本欄目

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved