6

.NET/ASP.NET 4.5 Bundle组件(捆绑、缩小静态文件)

 3 years ago
source link: https://www.cnblogs.com/wangiqngpei557/p/3309812.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

.NET/ASP.NET 4.5 Bundle组件(捆绑、缩小静态文件)

阅读目录:

  • 1.开篇介绍
  • 2.System.Web.Optimization 组件
  • 3.System.Web.Optimization 组件基本原理
  • 4.扩展自定义类型静态文件

1】开篇介绍

这篇文章将简单的分析一下有关静态文件捆绑的ASP.NET组件System.Web.Optimization的运行原理及基本的缓存问题;

在我们的项目里面充斥着很多静态文件,为了追求模块化、插件化很多静态文件都被设计成模块的方式或者被分解,在需要的时候在通过组合的方式在UI层上使用;这就带来一个问题,文件多了会影响浏览器加载页面的速度,而且由于浏览器的并发限制,对于并行的请求不是无限制的,所以捆绑静态文件的功能就产生;其实在以前,IIS还没有集成管道模型的时候我们只能通过动态资源的方式进行输出,也就是我们经常在*aspx页面里看见很多*.axd结尾的请求,当然多数情况下是配合ASP.NETAJAX用来输出动态JS、HTMDOM、CSS用的;

最新的IIS已经很好的集成了ASP.NET管道模型,也就是说我们完全可以通过ASP.NET本身的扩展来控制所有经过IIS的请求,包括静态文件,所以让捆绑静态文件成为了可能;

下面我们将分析一下System.Web.Optimization组件的基本运行原理,它是如何动态加载的,如何控制缓存的;

2】System.Web.Optimization 组件

每当我们新建一个ASP.NETMVC4站点的时候都会在~/App_Start目录下有一个BundleConfig.cs的启动文件,当然创建其他的ASP.NET4.0及4.0以上的项目也会有;

我第一次看见这个文件实在让我困惑,所以我打算简单的分析一下,知道其基本原理;

09142412-d4749f9606944c1287601c4cb91d55ac.jpg

代码是一个静态方法,然后传入一个BundleCollection集合对象,其实就是Bundle对象的集合,然后通过向集合内部注册多个Bundle;每个Bundle对应着多个静态文件,可以想象成就是键值对集合;通过后面的Include方法包含N多个静态文件,这里的静态文件路径可以是符合特定规则的字符串,由它内部去计算;

这是注册阶段,然后就是使用阶段,使用阶段很简单只要我们通过我们注册的Key字符串就能直接引用这些静态文件列表;

09142444-22e32644541a4e8d8ca05d0219cae648.jpg

我们只要关注Styles.Render、Scripts.Render两个方法,这两个方法是想页面注入之前在后台配置的静态文件列表;这样我们在客户端看见的就是被捆绑过后的文件集合了;

09142506-803929daff6f4c8c9b958228e166604a.jpg

文件的连接地址已经是被捆绑过后的地址了,这个地址就是我们在之前注册的时候用的key,后面它需要这个key去获取value 静态文件列表;要想你的捆绑起效果需要在注册的时候加上一段:BundleTable.EnableOptimizations = true;代码,意思是说开启捆绑,如果不开启捆绑则默认在调试环境里将不起效果,因为System.Web.Optimization使用了默认捆绑策略,如果是在Debug模式下,将不启用捆绑,如果你人为的设置了将覆盖默认设置;

使用就是这些,下面我们需要搞懂它是如何运行的,要了解一下它的基本原理;

3】System.Web.Optimization 组件基本原理

既然IIS集成了管道模型,那么我们肯定是能找到对应的HttpModule的,为了节省时间我就不去下载源码了,我们直接用反编译工具看一下;

09142539-4b3ff8cc5f374b2b9cba4cfc9860d806.jpg

这就是Bundle的HttpModule,它只用来处理
Bundle的连接地址,虽然它在HTTP的管道中;找到它就好顺藤摸瓜了,但是奇怪的是我在Web.config里没有发现它的配置信息,奇怪了,难道它还跑去系统文件改,当然是不可能的;所以我一时还想不起能有什么办法动态注册,提起动态注册突然有了思路,好像有一个Assembly级别的特性用来注册Application_Start启动时候的前置代码,会在Application启动之前执行,来看一下;

09142559-095a8ccda63244c884d8df84cdff3cdf.jpg

果然藏着这里呢,它注册了一个PreApplicationStartCode静态类,使用Start方法启动;

09142631-186ce90d972f4823a55dd7d2a254d033.jpg

这段代码很简单,先判断有没有执行过注册,如果没有就执行动态注册,这个动态注册组件是.NETFramework自带的,在Microsoft.Web.Infrastructure里面只不过属于平台相关的,跟ASP.NET没有直接关系,我们可以用Microsoft.Web.Infrastructure来开发自己的WEB组件;这里有一个疑问,为什么静态方法也要加判断呢,不是只会执行一次吗,因为静态方法的执行是不受控制的,所以如果不加判断很有可能会注册多次,出于严谨考虑还是加上;

现在基本上我们已经找到源头了,服务端这里我们先放一下,对于客户端的疑问很多,它既然帮我们捆绑了,那么缓存是如何处理的,也就是说它的输出缓存有没有设置,如果设置了不是有问题;

【客户端缓存相关】

为了很好的了解请求之间的信息,我们用Fiddler监听一下;

09142710-36370c45a7d645bfb85ad4f34b460775.jpg

我们看见它的Cache部分是用了If-Modified-Since来表示本地的文件的最后一次修改,这样是为了能够让服务器去验证文件是否改动,如果没有改动服务器的响应状态码为304,说明Bundle在输出的时候并没有设置对这个文件进行客户端强制缓存,我们通过Pragma: no-cache头也能看出来了;

那么我们得出结论,所有Bundle出来的文件都不可能直接缓存在浏览器中,每次都会带上Cache段If-Modified-Since去验证服务器的文件版本;刚好这里我们可以跟动态输出的静态文件地址的后面的参数对上了;

/Content/css?v=ZPnWVRT3c0yyrVDPmI-xkJuhBdJfQsL3A0K5C9WTOk01

这个链接后面的v参数是表示当前Bundle后虚拟文件的版本,如果我们在服务器上把文件修改了之后那么这个文件的If-Modified-Since验证就失败了,会生成新的版本号作为连接的参数;我们来看一下,心里踏实;

09142738-9346277ac78c47c4acfde62d922c9f5c.jpg

我加了一个width:auto的style,那么这个时候我刷新客户端应该是不会再有304出现了;

显然/Content/css?v=doYFOk3BdOYWDIRbQ7juV6eQdlJAu6RtC0G13El7X041 文件的版本变了,那么Response也不应该是304了;

09142759-b14b3bffb0a7480fac0455e3da166967.jpg

09142815-3fb0de0102fd4fa6acd17dd5e687adf0.jpg

如果静态文件的版本号发生改变,根本就不会带上 If-Modified-Since,这个是用在每次进行进行Post是用来验证的;其实意思就是说如果没有IIS集成模式那么捆绑文件的方式只能改变静态文件的文件名;

4】扩展自定义类型静态文件

Bundle对象是所有需要捆绑文件的基类,如果我们需要扩展一些静态文件,如一些特定领域的静态文件,我们可以直接继承这个类;

【XML文件的缓存】

扩展XML文件很简单,我们只需要继承一下Bundle对象,所有关于动态生成URL都有专门的对象处理,我们来看下代码;

ContractedBlock.gifExpandedBlockStart.gif

View Code

首先我们需要一个继承自Bundle对象的XmlBundle,用来表示我们所有将要传输的XML文件捆绑容器,然后我们需要一个静态方法用来注册捆绑后的URL;

这个URL的生成有专门的BundleResolver对象来完成,我们只需要传入所有的BundleCollection对象,我这里为了能在浏览器中测试所以写了一段stylesheet类型的link;这样我们就能直接在我们需要的地方直接使用了,我在index视图中引用:@MvcApplication4.Seed.XmlBundleRender.Render("~/custom/xml");是不是很简单,这样我们就能对所有想控制捆绑的文件进行捆绑,只需要继承加简单的静态方法辅助;

我们来看一下我们的XML文件是否具有所有缓存特性;

09142911-60c59829c9ce4f62a078908bfd3e6b49.jpg

第一次请求没有加If-Modified-Since段,返回的内容是一个简单的<model>222</model> 测试简单,现在我们看它是否在下一次不改变内容的情况下使用缓存;

09142934-5cc047aedadb438da06a70df9af742a1.jpg

在我们预料之中,使用了缓存数据,下面我们需要把服务器上的XML文件进行修改,将222改成243454637看是否自动刷新本地缓存也就是说不会是304返回状态;

09142954-ec11ff3f4d2f4e2184d83ab9d2bf4b09.jpg

也刷新缓存,符合理论根据,正确的返回了我们修改后的值;

结:其实HTTP不仅仅用在浏览器中,会有很多使用HTTP的场合,所以我们能很好的将这种功能用来捆绑一些图片、文字等多种场合中,确实是个不错的组件;文章结束,谢谢;

作者:王清培

出处:http://www.cnblogs.com/wangiqngpei557/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK