asp.net mvc Partial OutputCache 在SpaceBuilder中的应用实践
最近给SpaceBuilder增加OutputCache 时发现了一些问题,贴在这做个备忘,也方便遇到类似问题的朋友查阅。
目前SpaceBuilder表现层使用是asp.net mvc v1.0,使用了很多RenderAction(关于asp.net mvc的Partial Requests参见Partial Requests in ASP.NET MVC)。希望对于实时性要求不高的内容区域采用客户端缓存来提升性能同时也弥补一下RenderAction对性能的损失。
使用asp.net mvc自带的OutputCache Filter时发现了一个可怕的bug,在View中任何一个RenderAction设置OutputCache却影响了整个View。搜索发现确实是asp.net mvc目前已知的一个bug ,关于该问题的解决也有很多人提出了自己的方法。
关于asp.net mvc的缓存,Haacked写了两篇文章:
Donut Caching in ASP.NET MVC 介绍的是缓存整个页面,对于一部分内容禁用缓存,是在mvc中实现的WebForm的Substitution功能。存在以下弊端:当前一个View中有多个区域需要禁用缓存时使用比较麻烦,另外不能实现对页面的不同的区域使用不同的过期策略。
Donut Hole Caching in ASP.NET MVC介 绍的是我想要的功能,即只缓存页面的部分区域。但是弊端也非常明显:只能通过WebForm中的声明方式来使用用户控件(:),现在已经有点不适应这种方 式了,而且必须使用WebFormViewEngine),无法直接使用RenderPartial,而且还必须设置强类型的ViewPage,确保在用 户控件中的Model与View中的Model相同。使用太麻烦,限制也多。
Maarten Balliauw在 Creating an ASP.NET MVC OutputCache ActionFilterAttribute 和Extending ASP.NET MVC OutputCache ActionFilterAttribute - Adding substitution 也提出了一个完整的OutputCache解决方案。但是经测试启用客户端缓存时同样会产生与RenderAction同样的问题,还没有时间彻查这个问题,先把客户端缓存禁用,暂时使用服务器端缓存应付一阵。
以Maarten Balliauw的代码为原型,编写了SpaceBuilder的ActionOutputCacheAttribute:
publicclass ActionOutputCacheAttribute : ActionFilterAttribute { privatestatic MethodInfo _switchWriterMethod =typeof(HttpResponse).GetMethod("SwitchWriter", BindingFlags.Instance | BindingFlags.NonPublic); public ActionOutputCacheAttribute(int cacheDuration) { _cacheDuration = cacheDuration; } //目前还不能设置为Client缓存,会与OutputCache同样的问题 private CachePolicy _cachePolicy = CachePolicy.Server; privateint _cacheDuration; private TextWriter _originalWriter; privatestring _cacheKey; publicoverridevoid OnActionExecuting(ActionExecutingContext filterContext) { // Server-side caching? if (_cachePolicy == CachePolicy.Server || _cachePolicy == CachePolicy.ClientAndServer) { _cacheKey = GenerateCacheKey(filterContext); CacheContainer cachedOutput = (CacheContainer)filterContext.HttpContext.Cache[_cacheKey]; if (cachedOutput !=null) { filterContext.HttpContext.Response.ContentType = cachedOutput.ContentType; filterContext.Result =new ContentResult { Content = cachedOutput.Output }; } else { StringWriter stringWriter =new StringWriterWithEncoding(filterContext.HttpContext.Response.ContentEncoding); HtmlTextWriter newWriter =new HtmlTextWriter(stringWriter); _originalWriter = (TextWriter)_switchWriterMethod.Invoke(HttpContext.Current.Response, newobject[] { newWriter }); } } } publicoverridevoid OnResultExecuted(ResultExecutedContext filterContext) { // Server-side caching? if (_cachePolicy == CachePolicy.Server || _cachePolicy == CachePolicy.ClientAndServer) { if (_originalWriter !=null) // Must complete the caching { HtmlTextWriter cacheWriter = (HtmlTextWriter)_switchWriterMethod.Invoke(HttpContext.Current.Response, newobject[] { _originalWriter }); string textWritten = ((StringWriter)cacheWriter.InnerWriter).ToString(); filterContext.HttpContext.Response.Write(textWritten); CacheContainer container =new CacheContainer(textWritten, filterContext.HttpContext.Response.ContentType); filterContext.HttpContext.Cache.Add(_cacheKey, container, null, DateTime.Now.AddSeconds(_cacheDuration), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null); } } } privatestring GenerateCacheKey(ActionExecutingContext filterContext) { StringBuilder cacheKey =new StringBuilder("OutputCacheKey:"); // Controller + action cacheKey.Append(filterContext.Controller.GetType().FullName.GetHashCode()); if (filterContext.RouteData.Values.ContainsKey("action")) { cacheKey.Append("_"); cacheKey.Append(filterContext.RouteData.Values["action"].ToString()); } foreach (KeyValuePair<string, object> pair in filterContext.ActionParameters) { cacheKey.Append("_"); cacheKey.Append(pair.Key); cacheKey.Append("="); if (pair.Value !=null) cacheKey.Append(pair.Value.ToString()); else cacheKey.Append(string.Empty); } return cacheKey.ToString(); } privateclass CacheContainer { publicstring Output; publicstring ContentType; public CacheContainer(string data, string contentType) { Output = data; ContentType = contentType; } } publicenum CachePolicy { NoCache =, Client =, Server =, ClientAndServer = } }
{ encoding;
StringWriterWithEncoding publicclass StringWriterWithEncoding : StringWriter { Encoding encoding; public StringWriterWithEncoding(Encoding encoding) { this.encoding = encoding; } publicoverride Encoding Encoding { get{ return encoding; } } }
转自:http://www.cnblogs.com/mazq/archive/2009/05/30/1492298.html
asp.net mvc Partial OutputCache 在SpaceBuilder中的应用实践的更多相关文章
- Asp.net mvc web api 在项目中的实际应用
Asp.net mvc web api 在项目中的实际应用 前言:以下只是记录本人在项目中的应用,而web api在数据传输方面有多种实现方式,具体可根据实际情况而定! 1:数据传输前的加密,以下用到 ...
- 在Asp.net MVC 3 web应用程序中,我们会用到ViewData与ViewBag,对比一下:
Asp.net MVC中的ViewData与ViewBag ViewData ViewBag 它是Key/Value字典集合 它是dynamic类型对像 从Asp.net MVC 1 就有了 ASP. ...
- ASP.NET MVC 学习8、Controller中的Detail和Delete方法
参考:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/examining-the-details-and ...
- ASP.NET MVC 学习4、Controller中添加SearchIndex页面,实现简单的查询功能
参考:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/examining-the-edit-method ...
- [小技巧][ASP.Net MVC Hack] 使用 HTTP 报文中的 Header 字段进行身份验证
在一些 Web 系统中,身份验证是依靠硬件证书进行的:在电脑上插入 USB 证书,浏览器插件读取证书的相关信息,然后在发送 HTTP 登录请求时顺便在 Header 字段附加上身份信息.服务器端处理这 ...
- [转]Load ASP.NET MVC Partial Views Dynamically Using jQuery
本文转自:http://www.binaryintellect.net/articles/218ca630-ba50-48fe-af6e-6f754b5894aa.aspx Most of the t ...
- ASP.NET MVC Partial页输出JS
很多情况Partial是需要引用到JS的,通常做法是吧JS在引用Partial的页面中加入JS文件或者JS代码. 前阵子网上看到一段代码可以在Partial页面中添加JS,输出道引用页面. publi ...
- ASP.NET MVC系列:web.config中ConnectionString aspnet_iis加密与AppSettings独立文件
1. web.config中ConnectionString aspnet_iis加密 web.config路径:E:\Projects\Libing.Web\web.config <conne ...
- ASP.NET MVC做的微信WEBAPP中调用微信JSSDK扫一扫
今天做一个项目,是在微信上用的,微信WEB APP,里面用到了调用手机摄像头扫一扫二维码的功能,记得以前某个项目里写有的,但是找不到之前那个项目源码了,想复制粘贴也复制不了了,只好对着微信的那个开发文 ...
随机推荐
- 用NODEJS处理EXCEL文件导入导出,文件上传
參考文章 http://librajt.github.io/2013/08/04/handle-excel-file-with-nodejs/ 对照了 ExcelJS ,https://github. ...
- PHP网站在Linux服务器上面的安全配置
本文详细总结了PHP网站在Linux服务器上面的安全配置,包含PHP安全.mysql数据库安全.web服务器安全.木马查杀和防范等,很好很强大很安全. PHP安全配置 1. 确保运行php的用户为一般 ...
- SAP basis 二
使用事务 SMW0 可以在数据库中创建自己的图像.选择选项"二进制数据". 可以按.GIF 格式保存图像. 使用表 SSM_CUST 中的关键字 "START_IMAGE ...
- sqlalchemy——多表操作
一对多:一对一 # one -- many class Students(Base): __tablename__ = "students" sid = Column(Intege ...
- Vim 命令记录与回放
步骤如下: q+(a..z)寄存器名: 执行你要执行的操作: q 结束操作: 调用为@+寄存器: 列子如下: 在写PHP 程序时用的比较多的是创建函数: 如 function add_in(){ } ...
- sqoop job 增量导入
使用sqoop job做增量导入 在执行导入模式为 incremental 的sqoop job 时,sqoop会获取上次导入操作的 –check-column的value值,也就是说使用sqoop ...
- 超快的maven setting文件
<?xml version="1.0"?> <settings> <localRepository>/home/yizhen/.m2/repos ...
- MySQL- 常用的MySQL函数,指令等
MySQL查看版本: status: 或者 select version(); //select @@version MySQL昨天, 一周前 ,一月前 ,一年前的数据 这里主要用到了 DATE_SU ...
- java_面试_01_一个月的面试总结(java)
重点知识 由于我面试的JAVA开发工程师,针对于JAVA,需要理解的重点内容有: JVM内存管理机制和垃圾回收机制(基本每次面试都会问,一定要搞得透彻) JVM内存调优(了解是怎么回事,一般做项目过程 ...
- Spring源码分析_01_ idea搭建spring源码阅读环境
二.参考资料 1.Intellij Idea如何导入spring源码