阅读目录:css
这篇文章将简单的分析一下有关静态文件捆绑的ASP.NET组件System.Web.Optimization的运行原理及基本的缓存问题;浏览器
在咱们的项目里面充斥着不少静态文件,为了追求模块化、插件化不少静态文件都被设计成模块的方式或者被分解,在须要的时候在经过组合的方式在UI层上使用;这就带来一个问题,文件多了会影响浏览器加载页面的速度,并且因为浏览器的并发限制,对于并行的请求不是无限制的,因此捆绑静态文件的功能就产生;其实在之前,IIS尚未集成管道模型的时候咱们只能经过动态资源的方式进行输出,也就是咱们常常在*aspx页面里看见不少*.axd结尾的请求,固然多数状况下是配合ASP.NETAJAX用来输出动态JS、HTMDOM、CSS用的;缓存
最新的IIS已经很好的集成了ASP.NET管道模型,也就是说咱们彻底能够经过ASP.NET自己的扩展来控制全部通过IIS的请求,包括静态文件,因此让捆绑静态文件成为了可能;服务器
下面咱们将分析一下System.Web.Optimization组件的基本运行原理,它是如何动态加载的,如何控制缓存的;并发
每当咱们新建一个ASP.NETMVC4站点的时候都会在~/App_Start目录下有一个BundleConfig.cs的启动文件,固然建立其余的ASP.NET4.0及4.0以上的项目也会有;ide
我第一次看见这个文件实在让我困惑,因此我打算简单的分析一下,知道其基本原理;模块化
代码是一个静态方法,而后传入一个BundleCollection集合对象,其实就是Bundle对象的集合,而后经过向集合内部注册多个Bundle;每一个Bundle对应着多个静态文件,能够想象成就是键值对集合;经过后面的Include方法包含N多个静态文件,这里的静态文件路径能够是符合特定规则的字符串,由它内部去计算;工具
这是注册阶段,而后就是使用阶段,使用阶段很简单只要咱们经过咱们注册的Key字符串就能直接引用这些静态文件列表;测试
咱们只要关注Styles.Render、Scripts.Render两个方法,这两个方法是想页面注入以前在后台配置的静态文件列表;这样咱们在客户端看见的就是被捆绑事后的文件集合了;spa
文件的链接地址已是被捆绑事后的地址了,这个地址就是咱们在以前注册的时候用的key,后面它须要这个key去获取value 静态文件列表;要想你的捆绑起效果须要在注册的时候加上一段:BundleTable.EnableOptimizations = true;代码,意思是说开启捆绑,若是不开启捆绑则默认在调试环境里将不起效果,由于System.Web.Optimization使用了默认捆绑策略,若是是在Debug模式下,将不启用捆绑,若是你人为的设置了将覆盖默认设置;
使用就是这些,下面咱们须要搞懂它是如何运行的,要了解一下它的基本原理;
既然IIS集成了管道模型,那么咱们确定是能找到对应的HttpModule的,为了节省时间我就不去下载源码了,咱们直接用反编译工具看一下;
这就是Bundle的HttpModule,它只用来处理
Bundle的链接地址,虽然它在HTTP的管道中;找到它就好顺藤摸瓜了,可是奇怪的是我在Web.config里没有发现它的配置信息,奇怪了,难道它还跑去系统文件改,固然是不可能的;因此我一时还想不起能有什么办法动态注册,提起动态注册忽然有了思路,好像有一个Assembly级别的特性用来注册Application_Start启动时候的前置代码,会在Application启动以前执行,来看一下;
果真藏着这里呢,它注册了一个PreApplicationStartCode静态类,使用Start方法启动;
这段代码很简单,先判断有没有执行过注册,若是没有就执行动态注册,这个动态注册组件是.NETFramework自带的,在Microsoft.Web.Infrastructure里面只不过属于平台相关的,跟ASP.NET没有直接关系,咱们能够用Microsoft.Web.Infrastructure来开发本身的WEB组件;这里有一个疑问,为何静态方法也要加判断呢,不是只会执行一次吗,由于静态方法的执行是不受控制的,因此若是不加判断颇有可能会注册屡次,出于严谨考虑仍是加上;
如今基本上咱们已经找到源头了,服务端这里咱们先放一下,对于客户端的疑问不少,它既然帮咱们捆绑了,那么缓存是如何处理的,也就是说它的输出缓存有没有设置,若是设置了不是有问题;
为了很好的了解请求之间的信息,咱们用Fiddler监听一下;
咱们看见它的Cache部分是用了If-Modified-Since来表示本地的文件的最后一次修改,这样是为了可以让服务器去验证文件是否改动,若是没有改动服务器的响应状态码为304,说明Bundle在输出的时候并无设置对这个文件进行客户端强制缓存,咱们经过Pragma: no-cache头也能看出来了;
那么咱们得出结论,全部Bundle出来的文件都不可能直接缓存在浏览器中,每次都会带上Cache段If-Modified-Since去验证服务器的文件版本;恰好这里咱们能够跟动态输出的静态文件地址的后面的参数对上了;
好比:
/Content/css?v=ZPnWVRT3c0yyrVDPmI-xkJuhBdJfQsL3A0K5C9WTOk01
这个连接后面的v参数是表示当前Bundle后虚拟文件的版本,若是咱们在服务器上把文件修改了以后那么这个文件的If-Modified-Since验证就失败了,会生成新的版本号做为链接的参数;咱们来看一下,内心踏实;
我加了一个width:auto的style,那么这个时候我刷新客户端应该是不会再有304出现了;
显然/Content/css?v=doYFOk3BdOYWDIRbQ7juV6eQdlJAu6RtC0G13El7X041 文件的版本变了,那么Response也不该该是304了;
若是静态文件的版本号发生改变,根本就不会带上 If-Modified-Since,这个是用在每次进行进行Post是用来验证的;其实意思就是说若是没有IIS集成模式那么捆绑文件的方式只能改变静态文件的文件名;
Bundle对象是全部须要捆绑文件的基类,若是咱们须要扩展一些静态文件,如一些特定领域的静态文件,咱们能够直接继承这个类;
【XML文件的缓存】
扩展XML文件很简单,咱们只须要继承一下Bundle对象,全部关于动态生成URL都有专门的对象处理,咱们来看下代码;
1 public class XmlBundle : Bundle 2 { 3 public XmlBundle(string path) : base(path) { } 4 } 5 public static class XmlBundleRender 6 { 7 public static IHtmlString Render(string path) 8 { 9 BundleResolver bundle = new BundleResolver(BundleTable.Bundles); 10 return new HtmlString( 11 string.Format(@"<link href=""{0}"" rel=""stylesheet""/>", bundle.GetBundleUrl(path))); 12 } 13 }
首先咱们须要一个继承自Bundle对象的XmlBundle,用来表示咱们全部将要传输的XML文件捆绑容器,而后咱们须要一个静态方法用来注册捆绑后的URL;
这个URL的生成有专门的BundleResolver对象来完成,咱们只须要传入全部的BundleCollection对象,我这里为了能在浏览器中测试因此写了一段stylesheet类型的link;这样咱们就能直接在咱们须要的地方直接使用了,我在index视图中引用:@MvcApplication4.Seed.XmlBundleRender.Render("~/custom/xml");是否是很简单,这样咱们就能对全部想控制捆绑的文件进行捆绑,只须要继承加简单的静态方法辅助;
咱们来看一下咱们的XML文件是否具备全部缓存特性;
第一次请求没有加If-Modified-Since段,返回的内容是一个简单的<model>222</model> 测试简单,如今咱们看它是否在下一次不改变内容的状况下使用缓存;
在咱们预料之中,使用了缓存数据,下面咱们须要把服务器上的XML文件进行修改,将222改为243454637看是否自动刷新本地缓存也就是说不会是304返回状态;
也刷新缓存,符合理论根据,正确的返回了咱们修改后的值;
结:其实HTTP不只仅用在浏览器中,会有不少使用HTTP的场合,因此咱们能很好的将这种功能用来捆绑一些图片、文字等多种场合中,确实是个不错的组件;文章结束,谢谢;
做者:王清培
出处:http://www.cnblogs.com/wangiqngpei557/
本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。