在改善页面性能的同时,可能会采用静态化的策略,对于不能实时静态化的内容,则采用缓存。本文主要讨论如何实现cshtml的静态化(实际上还不是完全的html文件,因为还有一些无法实时静态化的内容需要再嵌入C#代码,此处暂不讨论),以及静态化所带来的一些问题。
对于一个搜索页面,如租房,有几个地区、价格、户型的分类搜索,这些分类搜索是允许叠加使用的,并且,一个组合的搜索结果中可能还有好几页的内容,所以,我们要做的静态化,就是要穷尽所有的组合,并生成相应静态文件(一般来说,用户输入的自定义关键词并不作静态化处理,因为难以穷尽,除非针对一些搜索频率比较大的关键词)。
1 首先估计生成规模
一般就是使用数学中的组合方法,即地区有n个,价格区间有m个,户型有k个,分页有s个,那么,生成的静态页面就有total=n*m*k*s个。还有一个问题就是生成的频率,是每天生成一次,还是多长时间生成一次。并且生成的过程是需要时间的,在未生成时,如果有请求,此时应该如何处理等等也需要考虑。
2 其次如何生成cshtml文件
调用一般的var tt = View("Index","Test");并不能在变量tt中如愿的得到最终的html代码,还是需要作一定的处理的。可以参考以下代码:
protected static string RenderViewToString(Controller controller, string viewName, string masterName) {
HttpContextBase wrapper;
if (System.Web.HttpContext.Current != null)
wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
else
throw new InvalidOperationException(
"Can't create Controller Context if no "+
"active HttpContext instance is available.");
if (routeData == null)
routeData = new RouteData();
// add the controller routing if not existing
if (!routeData.Values.ContainsKey("controller") &&
!routeData.Values.ContainsKey("Controller"))
routeData.Values.Add("controller",
controller.GetType()
.Name.ToLower() .Replace("controller", ""));
controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
IView view = ViewEngines.Engines.FindView(controller.ControllerContext, viewName, masterName).View; using (StringWriter writer = new StringWriter()) { ViewContext viewContext = new ViewContext(controller.ControllerContext, view, controller.ViewData, controller.TempData, writer); viewContext.View.Render(viewContext, writer); return writer.ToString(); } }
这段代码仅供参考,因为总是会提示controller.ControllerContext为空而报错,所以,可以粗略地加上上面一段来给controller.ControllerContext赋值。上面的代码,并不是最终实现了的版本,还需要改进,并且最好实现成Controller的扩展方法的形式比较方便。
调用时,如下:
var controller = new TestController();
var tt = RenderViewToString(controller,"Index",null);
不出错的话,就可以如愿得到相应的html代码,接着就是将代码保存在相应的目录下。
3 出现的一些问题。
当一个搜索页面需要生成成百上千个cshtml代码时,则网站这个静态化过的页面,第一次打开时,会经历一个比较长的搜索时间,有时是几秒钟,有时是几十秒上分钟,第二次打开时,则不会再出现这种情况。此时,可以做的事情主要有如下几个:
(1)把生成的cshtml代码以文件夹分开,因为第一次打开时间较长主要适用的单位是文件夹,如有两个文件夹A,B,并且两个文件夹内均有1000个cshtml文件,则第一次访问A中的任何文件时,会比较慢,之后再访问A中的任何文件则不会,而打开A中文件,其实是不影响B中文件夹的,所以,要使B中文件访问速度加快,则也要至少访问B中的一个文件。
(2)访问文件的操作可以使用HttpGet的方法模拟进行,并且最好使用异步进行,不然可能会导致请求超时。异步的方法主要有ajax和多线程。
(3)曾经查找过多cshtml文件第一次加载时慢的问题,但没有找到相关机制,最理想的方式,是通过代码主动去更新相关信息(如缓存)等,而不是模拟用户的点击行为。可能的途径是去查看asp.net mvc源代码。
注:对于cshtml静态化,可以完全的静态化,生成最终的html代码,也可以部分静态化,即还允许Layout的正常加载。对于第一种形式,还需要考虑相应的_Layout.cshtml以及_Layout.cshtml中的分部视图。