您的位置:首页 > 产品设计 > UI/UE

runAllManagedModulesForAllRequests="true" 的思考

2015-07-19 12:33 513 查看
最近在使用 MVC 开发的时候,遇到一个对我来说“奇怪的问题”,就是使用 BundleTable 进行 CSS、JS 文件绑定,然后使用 Styles.Render、Scripts.Render 进行获取,但总是获取不到绑定的 CSS、JS 文件,然后报“404错误”,话说再多,不如一个代码示例。
BundleConfig 配置代码:
public
class BundleConfig
{

// For more information on bundling, visithttp://go.microsoft.com/fwlink/?LinkId=301862

public static void
RegisterBundles(BundleCollectionbundles)
{
bundles.Add(new ScriptBundle("~/bundles/test.js").Include(

"~/Scripts/bootstrap.js",

"~/Scripts/respond.js"));

bundles.Add(new StyleBundle("~/bundles/test.css").Include(

"~/Content/bootstrap.css",

"~/Content/site.css"));
}
}
视图获取:
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - My ASP.NET Application</title>
@Styles.Render("~/bundles/test.css")
@Scripts.Render("~/bundles/test.js")
</head>
运行结果:

这个问题我相信大家应该都遇到过,当然前提条件是按照我上面那种写法,问题出来了,那该如何解决呢?因为你不知道问题出在哪,所以只能进行反复的尝试,最后我无意间把 .css 和 .js 后缀去掉就可以了,在上一个开发项目我就是这么干的,然后现在开发的项目又遇到这个问题,这就引起了我的重视,当然这不是一个解决方法,只是你不知道它背后的东西罢了。
小标签:当使用 VS
调试模式时,即 web.config
中 debug="true",使用BundleConfig.RegisterBundles
进行注册是没有效果的,但是可以展示,只不过没有起到“绑定”文件的作用,解决方式是,需要手动在
Application_Start 代码中添加:BundleTable.EnableOptimizations= true;
除了把 .css 和 .js 后缀去掉,网上搜索,还有一种解决方法就是,在 web.config 添加如下配置:
<system.webServer>

<modulesrunAllManagedModulesForAllRequests="true">

</modules>
</system.webServer>
runAllManagedModulesForAllRequests这个东西,之前我也遇到过,但不是像这次使用 Styles.Render、Scripts.Render 引起的,而是使用 MapRoute 进行 .htm 文件路由配置的时候,出现“404”错误,然后在 web.config 添加上面的配置就可以了,我还纪录了一篇博文:【记录】ASP.NETMVC
MapRoute .htm 不起作用,哎,当时并没有深入进行研究 runAllManagedModulesForAllRequests,只是认为既然能解决问题就行了,现在一想,其实心里有点后怕,为什么这样说?看下面就知道了。
runAllManagedModulesForAllRequests到底是什么东西呢?其实从它名字上面,你就可以明白一点,这也就是命名好的好处啊,咳咳,说白了,其意思就是为所有 Modules 管理请求的一个开关,如果设置为 true,就是把所有请求到 Modules 的通道打通了,没有任何阻拦,那 Modules 又是什么呢?字面意思可以理解为“模块”或“单元”的意思,它是属于 Web 服务器的东西,和 Web 应用程序不太相关,Web 应用程序只是对它发起一个请求,Modules
的相关东西,可以看下这一篇非常好的文章:IIS ModulesOverview
使用 IIS 部署站点的时候,在点击站点,右侧会有一个“主页”,我们会看到 Modules 的“身影”:

点击“模块”,就可以看到 IIS 所有的默认 Modules:

所有 Module 的具体说明可以查看:Module Reference,我们看一个等会我们要用到的 Module-StaticFileModule(静态文件管理模块):
· Description: Sends out static files withthe file extension .html, .jpg, as well as many others. ThestaticContent/mimeMap configuration collection determines the list of fileextensions.
· Configuration sections:system.webServer/staticContent
· Dependencies: None.
· Potential issues when removing thismodule: Static files no longer become served. Requests for files return a 404Not Found error indicating that no handler was matched.
上面说到,使用 MapRoute 进行 .htm 文件路由配置,出现“404错误”,我原本是想通过配置 StaticFileModule 进行解决,试过之后发现不行,staticContent/mimeMap配置中,IIS 默认是有 .htm 配置的,具体为:<mimeMapfileExtension=".htm" mimeType="text/html"/>,详细博文介绍:IIS
6中mimemap属性的默认设置,而且最重要的是 StaticFileModule 是管理所有静态文件请求的,其实 MapRoute 进行 .htm 文件路由配置的请求,是到不了 StaticFileModule 模块处理的,要不然早就可以访问了,URL 路由配置有一个单独的模块-UrlMappingsModule,这部分内容后面再了解。
至于 Styles.Render、Scripts.Render 获取包含后缀绑定的“404错误”,可以用下面配置进行解决:
<system.webServer>

<modules>

<addname="BundleModule"
type="System.Web.Optimization.BundleModule"/>

</modules>
</system.webServer>
其实上面这两个问题的“另类”解决方式,归根到底就是想避免使用 runAllManagedModulesForAllRequests="true",为什么要避免使用它?当然是有原因的,在说这个之前,再来看一个有意思的问题,可能和这个不太相关,但我还是想说一下。
先来看一段 web.config 配置:
<configuration>
<system.web>

<authenticationmode="Forms">

<formsname="MembershipCookie"

loginUrl="Login.aspx"

protection="All"

timeout="525600"

slidingExpiration="true"

enableCrossAppRedirects="true"

path="/"/>

</authentication>

<authorization>

<denyusers="?" />

</authorization>
</system.web>
<locationpath="Default.aspx">

<system.web>

<authorization>

<allowusers="*"/>

</authorization>

</system.web>
</location>
</configuration>
这段代码表示什么意思呢?authorization 配置的用户访问类型为“普通用户授权后才能访问”,location/authorization 是对某一页面进行身份验证,针对 Default.aspx 的身份验证类型为“匿名可访问”,并且 Default.aspx 为此站点的默认访问文档,可以理解为此站点出了 Default.aspx,其他页面访问都是需要身份验证的,然后跳转到 Login.aspx。
运行后,你会发现其实并不是这么回事,比如访问 www.mysite.com,按照配置应该会访问 www.mysite.com/Default.aspx,但是你会发现,它会跳转到 www.mysite.com/Login.aspx,为什么会这样呢?其实是 IIS 版本更新的问题,Stack Overflow 中详细的问题描述:ASP.NET
2.0and 4.0 seem to treat the root url differently in Forms Authentication,在他问题描述中,尝试用 UrlRewriter,但是还是没有起到效果,最后做了一个测试:
ASP.NET Version Url Behaviour
-------------------------------------------------------------------------
2.0 http://example.com Renders Default.aspx
2.0 http://example.com/Default.aspx Renders Default.aspx
4.0 http://example.com Redirects to Login.aspx
4.0 http://example.com/Default.aspx Renders Default.aspx
相关的两篇 IIS 更新说明:
· A update is available thatenables certain IIS 7.0 or IIS 7.5 handlers to handle requests whose URLs donot end with a period
· Authorization fails for requeststo the Default Document after KB980368 is installed in Internet InformationServices (IIS) 7.0
or 7.5
第一篇博文主要是说明 IIS 的一个更新,具体内容可以简化为:After this patch isapplied, ASP.NET 4 applications can handle requests for extensionless URLs.Therefore, managed HttpModules that run prior to handler execution will run. 什么意思?就是处理程序增加了一个"*"的映射,也就是说,比如文中提到的,更新之前只能访问如下
URL:www.example.com/ExampleSite/ExampleFile.,注意后面是有“点”的,也就是只能访问有扩展名的 URL,更新之后,可以访问无扩展名的 URL,也就是可以把那个“点”去掉,这样蕴含什么意思呢?注意上面英文的后面一句话,这句话就说明了后面那篇博文的问题原因。
后面一篇博文主要也是说明,上面 Stack Overflow 中所描述的那个问题,比如我访问 www.mysite.com,更新之前,会根据配置文件中的“默认文档”,找到相关页面后,再根据 web.config 中的身份验证配置,进行处理并显示,如果按照上面的 web.config 配置,访问的是 www.mysite.com/Default.aspx(匿名用户),但是更新后,IIS 就可以处理无扩展名的 URL,得到响应的 URL 后,会立马交给 Modules 进行处理,首先就是
UrlAuthentication、FromsAuthentication 模块进行身份验证处理,发现是“非法用户”,然后就跳转到了 www.mysite.com/Login.aspx,而直接访问 www.mysite.com/Default.aspx,会先走配置文件的 location 身份验证说明,因为更新针对的是“无扩展名”的 URL,而 www.mysite.com/Default.aspx 是有扩展名的 URL,说了那么多,微软最后给出的解决方案是:
<configuration>
<system.webServer>

<handlers>

<removename="ExtensionlessUrl-Integrated-4.0"/>

<removename="ExtensionlessUrl-ISAPI-4.0_64bit"/>

<removename="ExtensionlessUrl-ISAPI-4.0_32bit"/>

</handlers>
</system.webServer>
</configuration>
其实这个问题和 runAllManagedModulesForAllRequests 不太相关,但它可以带你思考 URL 和 Modules 之间的“微妙关系”,至于为什么避免使用runAllManagedModulesForAllRequests="true",我贴出两篇博文:
· The art ofsimplicity: Optimize the performance of your web applications: Don’t userunAllManagedModulesForAllRequests="true”.
· Don't userunAllManagedModulesForAllRequests="true" when getting your MVCrouting
to work
这篇博文就到这,后面解决一下不配置 runAllManagedModulesForAllRequests="true",使用 MapRoute 进行 .htm 文件路由配置,出现的“404错误”。
参考资料:
· IIS ModulesOverview : The Official Microsoft IIS Site
· ASP.NETBundling and Minification Returning
File Not Found (404) - Scott On Writing.NET
· The art ofsimplicity: Optimize the performance of your web applications: Don’t userunAllManagedModulesForAllRequests="true”.
· What is thecorrect usage of "runAllManagedModulesForAllRequests"
in ASP.NETMVC2/3? - Stack Overflow
· asp.net mvc- Why is my CSS bundling not working with a bin
deployed MVC4 app? - StackOverflow
· 更新程序使某些 IIS 7.0
或 IIS 7.5
处理程序来处理请求的 Url
不以句点结尾
· Authorization fails for requeststo the Default Document after KB980368 is installed in Internet InformationServices (IIS) 7.0
or 7.5
· ASP.NET 2.0and 4.0 seem to treat the root
url differently in Forms Authentication - StackOverflow
· Don't userunAllManagedModulesForAllRequests="true" when getting your MVCrouting
to work
· web.config中authorization下的location中的path的设置
- J-Pei - 博客园
· IIS 6中mimemap属性的默认设置
- 逸乐太子 -
博客园
------------------------------------------------------------------------------------------------------------------------------------
上一篇中,还有个遗留问题没有解决,就是 ASP.NET
MVCMapRoute .htm 不起作用,如果不使用 runAllManagedModulesForAllRequests="true" 的方式,该怎么解决呢?后来找了相关资料,发现了一种解决方案:
<system.webServer>
<modulesrunAllManagedModulesForAllRequests="false" />
<handlers>
<addname="HtmlFileHandler"
path="*.htm"verb="GET"
type="System.Web.Handlers.TransferRequestHandler"preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
</system.webServer>
参考博文:ASP.NETMVC: Route a .html request to an MVC route
之前探讨过,为什么尽量不要使用 runAllManagedModulesForAllRequests="true",然后我找了两篇相关介绍:
· The art ofsimplicity: Optimize the performance of your web applications: Don’t userunAllManagedModulesForAllRequests="true”.
· Don't userunAllManagedModulesForAllRequests="true" when getting your MVCrouting
to work
摘自文中的一段描述:
This highlyrecommended fix can cause other problems. These problems come in the form ofmaking all your registered HTTP modules run on every request, not just managedrequests (e.g. .aspx). This means modules will run
on ever .jpg .gif .css .html.pdf etc.
runAllManagedModulesForAllRequests就像 IIS Modules 和请求的一个通道开关,如果这个开关是打开的,那么访问此站点的所有请求都会进入 Modules 中进行处理,这其中就包含一些静态文件的请求,这也是最常见的一种“没必要处理”的请求,因为请求进入 Modules,那就要有相应的程序进行处理,这就造成没必要的性能开销,因为静态文件只是获取展示,完全没必要进行 Modules 处理,小的站点无所谓,当一些很大 PV 站点也这样做的时候,就会对
IIS 的 Modules 程序处理造成一些“压力”,上面有篇博文总结的结论就是 waste(浪费...) 和 potential(潜在...)。
下面用 Application_BeginRequest 做一个测试,看看对runAllManagedModulesForAllRequests 配置的不同,会有哪些请求被记录,测试示例代码:
protected
void Application_BeginRequest(object sender,EventArgs e)
{
using (StreamWriter _testData =
new StreamWriter(Server.MapPath("~/data.txt"),
true))
{
_testData.WriteLine(Request.Url.ToString());
}
}
runAllManagedModulesForAllRequests="fasle",data.txt 记录: http://localhost:55127/ http://localhost:55127/bundles/test2?v=2Fz3B0iizV2NnnamQFrx-NbYJNTFeBJ2GM05SilbtQU1 http://localhost:55127/bundles/test1?v=MDbdFKJHBa_ctS5x4He1bMV0_RjRq8jpcIAvPpKiN6U1 runAllManagedModulesForAllRequests="true",data.txt 记录: http://localhost:55127/ http://localhost:55127/bundles/test2?v=2Fz3B0iizV2NnnamQFrx-NbYJNTFeBJ2GM05SilbtQU1 http://localhost:55127/bundles/test1?v=MDbdFKJHBa_ctS5x4He1bMV0_RjRq8jpcIAvPpKiN6U1 http://localhost:55127/Content/logo_small_1.gif http://localhost:55127/Content/logo_small_4.gif http://localhost:55127/Content/logo_small_2.gif http://localhost:55127/Content/logo_small_3.gif logo_small_* 图片是我在视图中添加的,这边只是测试静态图片的请求,如果你在一个大型站点下,加上请求测试代码,然后刷新一下页面,你会发现无意义的请求是非常多的。可能你看上面的测试记录,感觉似乎说明不了什么问题,但试想一下,如果一个静态文件很多的站点,然后访问量千万级别的,站点包含的页面也很多,这时候虽然一个很小的问题,但会被无限放大,最后你发现,原来只是一个配置问题。
就写到这,要改代码了。

作者:田园里的蟋蟀

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

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: