C# 代理应用 - Cachable
C# 代理应用 - Cachable
放心,这次不是说设计模式中的代理模式,说的是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);
}
}

运行效果图:

搞定。
心怀远大理想。
为了家庭幸福而努力。
用A2D科技,服务社会。
C# 代理应用 - Cachable的更多相关文章
- 缓存子系统如何设计(Cachable tag, Memcache/redis support, xml config support, LRU/LFU/本地缓存命中率)
大家对这段代码肯定很熟悉吧: public List<UserInfo> SearchUsers(string userName) { string cacheKey=string.For ...
- Linux实战教学笔记43:squid代理与缓存实践(二)
第6章 squid代理模式案例 6.1 squid传统正向代理生产使用案例 6.1.1 squid传统正向代理两种方案 (1)普通代理服务器 作为代理服务器,这是SQUID的最基本功能:通过在squi ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- nginx配置反向代理或跳转出现400问题处理记录
午休完上班后,同事说测试站点访问接口出现400 Bad Request Request Header Or Cookie Too Large提示,心想还好是测试服务器出现问题,影响不大,不过也赶紧上 ...
- Visual Studio Code 代理设置
Visual Studio Code (简称 VS Code)是由微软研发的一款免费.开源的跨平台文本(代码)编辑器,在十多年的编程经历中,我使用过非常多的的代码编辑器(包括 IDE),例如 Fron ...
- DynamicObject - 代理对象的种类
开箱即用,DynamicProxy提供了多种代理对象,主要分成两个大类: 基于继承(Inheritance-based) 基于继承的代理是通过继承一个代理类来实现,代理拦截对类的虚(virtual)成 ...
- SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论
异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#signalR 后台创建了一个DntHub的集线器 前台在调用的时候出现了问题(经检查是代理对象 ...
- 实现代理设置proxy
用户在哪些情况下是需要设置网络代理呢? 1. 内网上不了外网,需要连接能上外网的内网电脑做代理,就能上外网:多个电脑共享上外网,就要用代理: 2.有些网页被封,通过国外的代理就能看到这被封的网站:3. ...
- 23种设计模式--代理模式-Proxy
一.代理模式的介绍 代理模式我们脑袋里出现第一个词语就是代购,其实就是这样通过一个中间层这个中间成是属于什么都干什么都买得,俗称"百晓生",在平时得开发中我们经常会听到 ...
随机推荐
- EasyUI combox实现联动
多的时间将被用于combox联动效应.一个选择combox的值自己主动出这值有关相应的其他信息,例如省市联动.最近,我刚刚会见了班似要求,随着EasyUI combobox 控制完成.假设ASP.N ...
- [Unity3D]Unity3D连衣裙实现游戏开发系统
大家好,我是秦培.欢迎关注我的博客,我的博客地址">blog.csdn.net/qinyuanpei. 不知从什么时候開始,国产RPG单机游戏開始出现换装,仙剑系列中第一部实现了换装的 ...
- 第3章3节《MonkeyRunner源码剖析》脚本编写示例: MonkeyImage API使用示例(原创)
天地会珠海分舵注:本来这一系列是准备出一本书的,详情请见早前博文“寻求合作伙伴编写<深入理解 MonkeyRunner>书籍“.但因为诸多原因,没有如愿.所以这里把草稿分享出来,所以错误在 ...
- Java导出页面数据或数据库数据至Excel文件并下载,采用JXL技术,小demo(servlet实现)
public class ExportExcelServlet extends HttpServlet { /** * */ private static final long serialVersi ...
- canvas绘制自定义的曲线,以椭圆为例,通俗易懂,童叟无欺
本篇文章,将讲述如何通过自定义的曲线函数,使用canvas的方式进行曲线的绘制. 为了通俗易懂,将以大家熟悉的椭圆曲线为例,进行椭圆的绘制.至于其他比较复杂的曲线,用户只需通过数学方式建立起曲线函数, ...
- Python 2.7 Exception格式化工具
首先说一个发现: try: 抛错误,抛异常 except Exception as e: 都被这里抓住了 except Error as e: 这里啥事都没了 然后,说说Exception as e的 ...
- php soap调用asp.net webservice
原文:php soap调用asp.net webservice 首先做一下准备工作,找到安装环境里的php.ini把;extension=php_soap.dll去掉前面的;.我这里使用的是wamp, ...
- D3D 光照和材料 小样例
1.实现一个旋转的圆柱体,体现d3d光照效果 2.程序实现 #pragma once #pragma comment(lib,"winmm.lib") #pragma commen ...
- Redis源代码分析(二十四)--- tool工具类(2)
在上篇文章中初步的分析了一下,Redis工具类文件里的一些使用方法,包含2个随机算法和循环冗余校验算法,今天,继续学习Redis中的其它的一些辅助工具类的使用方法.包含里面的大小端转换算法,sha算法 ...
- Retrofit相关资料
高速Android开发系列网络篇之Retrofithttp://www.w3c.com.cn/%E5%BF%AB%E9%80%9Fandroid%E5%BC%80%E5%8F%91%E7%B3%BB% ...