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 =0, Client =1, Server =2, ClientAndServer =3 } }
{ encoding;
转自:http://www.cnblogs.com/mazq/archive/2009/05/30/1492298.html
asp.net mvc Partial OutputCache 在SpaceBuilder中的应用实践相关推荐
- ASP.NET MVC 3: Razor视图引擎中 @: 和text 语法【转载】
ASP.NET MVC 3: Razor视图引擎中 @: 和<text> 语法[转载] (文章没翻译:建议大家读英文原文,看不懂查着看,顺便提高自己的英语水平!) In today's p ...
- ASP.NET MVC 上传图片到项目目录中的文件夹并显示
因项目需求,需要一个上传图片并显示的功能,类似于上传头像并显示出来.查阅了网上资料,写了个Demo,希望能帮助到更多的人.此Demo基于ASP.NET MVC实现. 选择图片: 点击按钮进行上传: 一 ...
- 使用asp.net mvc开发应用程序,页面中的page.IsPostback还有用处吗?
本来我对asp.net mvc也研究了一段时间了,我也使用了asp.net mvc开发了两套应用程序,虽然都不是什么大的系统. 今天也想特别提出一个疑问,不知道是我不知道呢,还是本身很难实现在asp. ...
- ASP.NET MVC 使用Log4Net记录系统运行中问题
log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介. 在NuGet程序包中下载log4Net组件, ...
- ASP.NET MVC的SNS软件Spacebuilder
SpacebuilderV4.0 展示了全新构建的微博.贴吧.群组.日志.问答.相册.积分商城等社区功能,Spacebuilder开发团队却在V4.0正式版发布之际,突然给大家带来了一份大礼!--&q ...
- 在ASP.NET MVC 模型中 选择最好的方法将多个model(数据模型)传递到视图
在ASP.NET MVC 模型中 选择最好的方法将多个model(数据模型)传递到视图 前提介绍 这个文章我们要讨论,在ASP.NET MVC模型的项目中,怎么选择一个最有效的方式来将多个数据模型(m ...
- Asp.net MVC中的ViewData与ViewBag
在Asp.net MVC 3 web应用程序中,我们会用到ViewData与ViewBag,对比一下: ViewData ViewBag 它是Key/Value字典集合 它是dynamic类型对像 从 ...
- Asp.net MVC中的ViewData与ViewBag
在Asp.net MVC 3 web应用程序中,我们会用到ViewData与ViewBag,对比一下: ViewData ViewBag 它是Key/Value字典集合 它是dynamic类型对像 从 ...
- 在IIS中部署Asp.net Mvc
概述: 最近在做一个MVC 3的项目,在部署服务器时破费了一番功夫,特将过程整理下来,希望可以帮到大家! 本文主要介绍在IIS5.1.IIS6.0.IIS7.5中安装配置MVC 3的具体办法! 正文: ...
最新文章
- Flutter开发Flutter与原生OC、Java的交互通信-1(47)
- hdu-3015 Disharmony Trees---离散化+两个树状数组
- 打印文件前,千万记得把弹窗叉掉!!!
- cmd xcopy 拷贝文件夹_在纯dos下用xcopy命令怎么复制文件夹
- es6 filter函数的用法_Python 函数式编程指北,不只是面向对象哦!超级详细!
- Docker基本使用(一)
- Django入门10--admin增强
- 年轻人不讲武德,竟然重构出这么优雅后台 API 接口
- epoll 和select/poll的区别
- 大学BBS年度十大原创淡黄笑话
- 视频码率与分辨率的参考表
- linux系统下使用uTorrent下载ipv6资源
- 团队作业8----第二次项目冲刺(Beta阶段) 第四天
- 排序(使用插入法对数组元素从小到大排序)
- 全国计算机职称考试excel2003,全国计算机职称考试excel2003题库及答案电子教案.pdf...
- Java——I/O(字符编码、内存流、打印流、System、输入流、序列化)
- 主成分分析(R语言)
- iPhone用android充电头,苹果能用安卓充电头吗
- 树模型:决策树、随机森林(RF)、AdaBoost、GBDT、XGBoost、LightGBM和CatBoost算法区别及联系
- 18.3.7给小可爱们的(NBUOJ)
热门文章
- 欧姆龙, PLC CJ2M标准程序,一共控制12个伺服电机 ,气缸若干,包含轴点动,回零,相对与绝对定位
- ruoyi 前后端分离 增加手机号登录
- 自己实现一个字符串拼接函数
- vue-amap(vue 地图)
- 微信小程序打卡活动实现PHP,微信小程序实现打卡日历功能
- 315投诉集中“轰炸”,微商离歇菜还有多远?
- web网页设计实例作业 ——茶叶文化-适应响应(12页) 学生HTML个人网页作业作品下载
- 1000以内完数c语言程序_编程找出1000以内的所有完数
- AutoCAD Lisp LSP小程序 实现面积注记
- 企微整合,钉钉进化,飞书抢占toB下半场