Asp.net 服务端缓存引发的一点思考
2012-09-03 22:30
435 查看
我们知道asp.net要经历以下事件
BeginRequest
AuthenticateRequest
PostAuthenticateRequest
AuthorizeRequest
PostAuthorizeRequest
ResolveRequestCache
PostResolveRequestCache
PostMapRequestHandler
AcquireRequestState
PostAcquireRequestState
PreRequestHandlerExecute
....IHttpHandler 类的 ProcessRequest 方法,真正处理请求的地方时一个比较耗时的处理
PostRequestHandlerExecute
eleaseRequestState
PostReleaseRequestState 事件。
UpdateRequestCache
PostUpdateRequestCache
EndRequest
而在服务端我们缓存经常会用到OutputCache,之所以能用它只要是因为OutputCacheModule中有如下代码:
在本例中只是提出这种缓存的思想,在项目中运用需要注意的事情还很多。
首先我们需要实现缓存机制,这里我们用字典来存储数据永不过期。
代码很简单吧,同样需要截获输出流的代码
那么如何运用了?在Global.asax.cs文件中:
这种处理方式和OutputCache一样不用区分你的程序是否是mvc模式。在实际项目中我们可以用Memcached、Redis、AppFabric 来做分布式缓存。比如像凡客、京东某些页面就可以采用这种思想来实现,比你在页面或action任何地方读取缓存的效率要高出很多,当然效率高的代价就是它的适用范围比较窄,实际中往往不是缓存一个完整的整个页面内容,而只是缓存一部分。
欢迎大家拍砖
BeginRequest
AuthenticateRequest
PostAuthenticateRequest
AuthorizeRequest
PostAuthorizeRequest
ResolveRequestCache
PostResolveRequestCache
PostMapRequestHandler
AcquireRequestState
PostAcquireRequestState
PreRequestHandlerExecute
....IHttpHandler 类的 ProcessRequest 方法,真正处理请求的地方时一个比较耗时的处理
PostRequestHandlerExecute
eleaseRequestState
PostReleaseRequestState 事件。
UpdateRequestCache
PostUpdateRequestCache
EndRequest
而在服务端我们缓存经常会用到OutputCache,之所以能用它只要是因为OutputCacheModule中有如下代码:
void IHttpModule.Init(HttpApplication app) { if (RuntimeConfig.GetAppConfig().OutputCache.EnableOutputCache) { app.ResolveRequestCache += new EventHandler(this.OnEnter); app.UpdateRequestCache += new EventHandler(this.OnLeave); } }同样只要看过OutputCacheModule源码的人都知道这里面面的代码比较难懂,为了提高性能,我们能否把读取缓存的时间往前推推到BeginRequest,一旦有缓存这个时候我们就返回数据结束输出流。那么什么时候设置缓存了?我们可以选着在ReleaseRequestState事件中处理,在这个处理中我们需要截获输出流的内容。
在本例中只是提出这种缓存的思想,在项目中运用需要注意的事情还很多。
首先我们需要实现缓存机制,这里我们用字典来存储数据永不过期。
public class Cache { static ConcurrentDictionary<string, string> dict = new ConcurrentDictionary<string, string>(); public static void Add(string key, string value) { if (dict.ContainsKey(key)) { dict[key] = value; } else { dict.TryAdd(key, value); } } public static string Get(string key) { string result = string.Empty; dict.TryGetValue(key, out result); return result; } }
代码很简单吧,同样需要截获输出流的代码
public class PageFilter : Stream { Stream responseStream; long position; StringBuilder responseHtml; public PageFilter(Stream inputStream) { responseStream = inputStream; responseHtml = new StringBuilder(); } #region Filter overrides public override bool CanRead { get { return true; } } public override bool CanSeek { get { return true; } } public override bool CanWrite { get { return true; } } public override void Close() { responseStream.Close(); } public override void Flush() { responseStream.Flush(); } public override long Length { get { return 0; } } public override long Position { get { return position; } set { position = value; } } public override long Seek(long offset, SeekOrigin origin) { return responseStream.Seek(offset, origin); } public override void SetLength(long length) { responseStream.SetLength(length); } public override int Read(byte[] buffer, int offset, int count) { return responseStream.Read(buffer, offset, count); } #endregion #region Dirty work public override void Write(byte[] buffer, int offset, int count) { HttpResponse response = HttpContext.Current.Response; string charset = response.Charset ?? "utf-8"; string finalHtml = Encoding.GetEncoding(charset).GetString(buffer, offset, count); int index = finalHtml.IndexOf("</html>"); if (index<1) { responseHtml.Append(finalHtml); } else { responseHtml.Append(finalHtml); finalHtml = responseHtml.ToString(); byte[] data = Encoding.GetEncoding(charset).GetBytes(finalHtml); /*缓存处理*/ string key = HttpContext.Current.Request.Url.ToString(); Cache.Add(key, finalHtml); /*缓存处理*/ responseStream.Write(data, 0, data.Length); } } #endregion }
那么如何运用了?在Global.asax.cs文件中:
public override void Init() { base.Init(); this.BeginRequest += new EventHandler(MvcApplication_BeginRequest); this.ReleaseRequestState += new EventHandler(MvcApplication_ReleaseRequestState); } void MvcApplication_BeginRequest(object sender, EventArgs e) { string key = HttpContext.Current.Request.Url.ToString(); HttpResponse response = HttpContext.Current.Response; string result = Cache.Get(key); if (!string.IsNullOrEmpty(result)) { response.Write(result); ((HttpApplication)sender).CompleteRequest(); } } void MvcApplication_ReleaseRequestState(object sender, EventArgs e) { HttpResponse response = HttpContext.Current.Response; if (response.ContentType == "text/html") { response.Filter = new PageFilter(response.Filter); } }运行结果,无论你运行多少次结果都如下
这种处理方式和OutputCache一样不用区分你的程序是否是mvc模式。在实际项目中我们可以用Memcached、Redis、AppFabric 来做分布式缓存。比如像凡客、京东某些页面就可以采用这种思想来实现,比你在页面或action任何地方读取缓存的效率要高出很多,当然效率高的代价就是它的适用范围比较窄,实际中往往不是缓存一个完整的整个页面内容,而只是缓存一部分。
欢迎大家拍砖
相关文章推荐
- ASP.NET:TextBox失去焦点引发服务端事件
- 细说ASP.NET Cache 及其高级用法--服务端缓存
- 勤于思考: ASP.NET MVC 注销后 使用浏览器 【后退】 不使用缓存页面
- 【Asp.net之旅】--因自己定义控件注冊而引发的思考
- 【Asp.net之旅】--因自定义控件注册而引发的思考
- 关于html、asp、php模板引擎、aspnet mvc、REST的一点思考
- ASP.NET简单实现服务端图片缓存
- 关于EnableViewState以及页面中选择asp.net服务端控件和HTML控件的思考
- asp.net 服务端与客户端 缓存
- 一个bug引发的思考 --- ASP.NET页面加载顺序讨论
- 一个bug引发的思考 --- ASP.NET页面加载顺序讨论
- 演练:将 ASP.NET 输出缓存与 SQL Server 结合使用
- Asp.Net Mvc 页面缓存
- ASP.NET 2.0数据缓存功能简介 (转贴)
- ASP.NET 2.0学习3--缓存性能
- ASP.NET缓存数据添加方法一览
- asp.net缓存使用总结
- ASP.NET中在线用户统计的一点细节
- ASP.NET缓存
- Asp.net中使用javascrip的模态窗体的一点体会。(转)