• 塞翁失马,焉知非福:由 Styles.Render 所引发 runAllManagedModulesForAllRequests="true" 的思考


    最近在使用 MVC 开发的时候,遇到一个对我来说“奇怪的问题”,就是使用 BundleTable 进行 CSS、JS 文件绑定,然后使用 Styles.Render、Scripts.Render 进行获取,但总是获取不到绑定的 CSS、JS 文件,然后报“404错误”,话说再多,不如一个代码示例。

    BundleConfig 配置代码:

    public class BundleConfig
    {
        // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
        public static void RegisterBundles(BundleCollection bundles)
        {
            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>
        <modules runAllManagedModulesForAllRequests="true">
        </modules>
      </system.webServer>
    

    runAllManagedModulesForAllRequests 这个东西,之前我也遇到过,但不是像这次使用 Styles.Render、Scripts.Render 引起的,而是使用 MapRoute 进行 .htm 文件路由配置的时候,出现“404”错误,然后在 web.config 添加上面的配置就可以了,我还纪录了一篇博文:【记录】ASP.NET MVC MapRoute .htm 不起作用,哎,当时并没有深入进行研究 runAllManagedModulesForAllRequests,只是认为既然能解决问题就行了,现在一想,其实心里有点后怕,为什么这样说?看下面就知道了。

    runAllManagedModulesForAllRequests 到底是什么东西呢?其实从它名字上面,你就可以明白一点,这也就是命名好的好处啊,咳咳,说白了,其意思就是为所有 Modules 管理请求的一个开关,如果设置为 true,就是把所有请求到 Modules 的通道打通了,没有任何阻拦,那 Modules 又是什么呢?字面意思可以理解为“模块”或“单元”的意思,它是属于 Web 服务器的东西,和 Web 应用程序不太相关,Web 应用程序只是对它发起一个请求,Modules 的相关东西,可以看下这一篇非常好的文章:IIS Modules Overview

    使用 IIS 部署站点的时候,在点击站点,右侧会有一个“主页”,我们会看到 Modules 的“身影”:

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

    所有 Module 的具体说明可以查看:Module Reference,我们看一个等会我们要用到的 Module-StaticFileModule(静态文件管理模块):

    • Description: Sends out static files with the file extension .html, .jpg, as well as many others. The staticContent/mimeMap configuration collection determines the list of file extensions.
    • Configuration sections: system.webServer/staticContent
    • Dependencies: None.
    • Potential issues when removing this module: Static files no longer become served. Requests for files return a 404 Not Found error indicating that no handler was matched.

    上面说到,使用 MapRoute 进行 .htm 文件路由配置,出现“404错误”,我原本是想通过配置 StaticFileModule 进行解决,试过之后发现不行,staticContent/mimeMap 配置中,IIS 默认是有 .htm 配置的,具体为:<mimeMap fileExtension=".htm" mimeType="text/html"/>,详细博文介绍:IIS 6中mimemap属性的默认设置,而且最重要的是 StaticFileModule 是管理所有静态文件请求的,其实 MapRoute 进行 .htm 文件路由配置的请求,是到不了 StaticFileModule 模块处理的,要不然早就可以访问了,URL 路由配置有一个单独的模块-UrlMappingsModule,这部分内容后面再了解。

    至于 Styles.Render、Scripts.Render 获取包含后缀绑定的“404错误”,可以用下面配置进行解决:

      <system.webServer>
        <modules>
          <add name="BundleModule" type="System.Web.Optimization.BundleModule" />
        </modules>
      </system.webServer>
    

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

    先来看一段 web.config 配置:

    <configuration>
      <system.web>
        <authentication mode="Forms">
          <forms name="MembershipCookie" 
                 loginUrl="Login.aspx" 
                 protection="All" 
                 timeout="525600" 
                 slidingExpiration="true" 
                 enableCrossAppRedirects="true" 
                 path="/" />
        </authentication>
        <authorization>
          <deny users="?"  />
        </authorization>
      </system.web>
      <location path="Default.aspx">
        <system.web>
          <authorization>
            <allow users="*"/>
          </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.0 and 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 更新说明:

    第一篇博文主要是说明 IIS 的一个更新,具体内容可以简化为:After this patch is applied, 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>
          <remove name="ExtensionlessUrl-Integrated-4.0" />
          <remove name="ExtensionlessUrl-ISAPI-4.0_64bit" />
          <remove name="ExtensionlessUrl-ISAPI-4.0_32bit" />
        </handlers>
      </system.webServer>
    </configuration>
    

    其实这个问题和 runAllManagedModulesForAllRequests 不太相关,但它可以带你思考 URL 和 Modules 之间的“微妙关系”,至于为什么避免使用 runAllManagedModulesForAllRequests="true",我贴出两篇博文:

    这篇博文就到这,后面解决一下不配置 runAllManagedModulesForAllRequests="true",使用 MapRoute 进行 .htm 文件路由配置,出现的“404错误”。

    参考资料:

  • 相关阅读:
    selenium判断元素是否为空
    charles 设置弱网测试(转)
    python爬虫初步认知
    Ubuntu运行*.sh文件出现 bash: ./a.sh: /bin/bash^M: bad interpreter: No such file or directory问题解决方案
    Unity3D【安装...........】
    世界上最早的区块链——中国麻将【........】
    Cypher 概述与基本语法
    Win10系统还原与恢复出厂教程【启动系统还原功能】
    增加首页音乐播放器APlayer
    Fabric 持久化
  • 原文地址:https://www.cnblogs.com/xishuai/p/Styles-Render-runAllManagedModulesForAllRequests-true.html
Copyright © 2020-2023  润新知