MVC4 - 当启用优化设置为true时,Bundling无法正常工作

44

我想知道我在这里做错了什么。我正在使用ASP.NET C# MVC4,并且我想利用新的CSS / JS优化功能。

以下是我的HTML部分

@Styles.Render("~/content/css")

这是我的BunduleConfig.cs部分

bundles.Add(new StyleBundle("~/content/css").Include(
                        "~/content/css/reset.css",
                        "~/content/css/bla.css"));

// BundleTable.EnableOptimizations = true;

输出(可行):

<link href="/content/css/reset.css" rel="stylesheet"/>
<link href="/content/css/bla.css" rel="stylesheet"/>

但是当我取消注释BundleTable.EnableOptimizations = true;后,HTML输出结果如下

<link href="/content/css?v=5LoJebKvQJIN-fKjKYCg_ccvmBC_LF91jBasIpwtUcY1" rel="stylesheet"/>

当然这是404错误。我不知道我做错了什么,请帮我,这是我第一次使用MVC4。


如果您创建了EnableOptimizations=true通常会查找的~content/css/reset.min.css和bla.min.css文件,会发生什么? - Phil
我刚刚创建了一个空项目,并尝试使用两个css文件,结果出现了同样的问题。也许是因为我把我的css文件放在/content/css/文件夹中而不是仅仅放在/content/中,但我怀疑这个原因... - Stan
6个回答

70

我认为问题在于您将捆绑包放在了一个虚拟URL上,该URL实际上存在但是是一个目录。

MVC会从您的捆绑包中创建一个虚拟文件,并将其从您指定的捆绑包路径提供出来。

解决这个问题的正确方法是使用一个不直接映射到现有目录的捆绑包路径,而是在该目录中使用虚拟文件名(也不映射到实际文件名)。

例如:

如果您的站点有一个名为/content/css的文件夹,请按以下方式创建css捆绑包:

在BundleConfig.cs中:

bundles.Add(new StyleBundle("~/content/css/AllMyCss.css").Include(
                        "~/content/css/reset.css",
                        "~/content/css/bla.css"));

在页面上:

@Styles.Render("~/content/css/AllMyCss.css")

请注意,这假定您的css文件夹中没有名为AllMyCss.css的文件。


6
把捆绑包放在不存在的目录里,会不会对CSS中的相对引用造成问题?原文链接为:http://devwhib.blogspot.com/2012/08/mvc-4-bundles-where-are-my-css.html - gidmanma
有很多方法可以解决相对引用问题。如果您的 CSS 中存在相对引用,可以将它们转换为绝对引用、将资源嵌入到 CSS 中、将相对引用视为 CSS 文件本身位于虚拟 URL 上,或者使虚拟 URL 与实际文件位置的深度相同。 - dodexahedron
按照您所说的 @dodexahedron 做了,但还是不行 :(在浏览器控制台中获取到此URL的404错误:http://localhost:60676/Content/css/AllCss.css?v=z5INlMepX0JyqDsv6-_cVrsvSaZhyo_AfX42UtDMW4g1 - iamraviraj

26

我不确定是网站优化还是WebGrease过于挑剔,但其中一个(或两者)是这样的,你需要非常小心。

首先,你的代码没有任何问题:

bundles.Add(new StyleBundle("~/content/css").Include(
                        "~/content/css/reset.css",
                        "~/content/css/bla.css"));

实际上,这正是微软所做的。他们使用~/bundles作为CSS的主要原因是相对路径对于图像会出现问题。想想你的浏览器如何查看一个bundle——和它查看任何其他URL的方式完全相同,所有普通的路径相关规则在相对路径方面仍然适用。想象一下,如果你的CSS中有一个到../images/bullet.png的图像路径。如果你使用~/bundles,那么浏览器会在一个不存在的bundles目录的上级目录中查找。它最终可能会在~/images中查找,而你实际上将其放在了~/content/images中。

我发现几件事情可能真的会破坏它并导致404错误:

  • FYI:我的目录结构是包含CSS图像文件夹的Content/CSS
  • 我已经将EnableOptimizations=true设置为在测试时强制使用bundles
  • 你应该做的第一件事是“查看源代码”,只需单击CSS链接即可查看它们是否有效

假设我们正在开发一个有关猫的网站。你可能有这个:

 @Styles.Render("~/Content/css/cats.css")    // dont do this - see below why

 bundles.Add(new StyleBundle("~/content/css/cats.css").Include(
                    "~/content/css/reset.css",
                    "~/content/css/bla.css"));

这将在你的HTML中生成一个指向此路径的CSS链接:

/Content/css/cats.css?v=JMoJspikowDah2auGQBfQAWj1OShXxqAlXxhv_ZFVfQ1

然而,由于我使用了扩展名.css,IIS(我想)会混淆,因此这将导致404错误。

如果我将它更改为以下内容,则可以正常运行:

 @Styles.Render("~/Content/css/cats")

 bundles.Add(new StyleBundle("~/content/css/cats").Include(
                    "~/content/css/reset.css",
                    "~/content/css/bla.css"));

其他人已经指出的另一个问题是,你不能这样做

 @Styles.Render("~/Content/css")

如果您的Content目录中有一个CSS目录或文件(不太可能有一个没有扩展名的文件名为css的文件)。

另一个技巧是,您需要确保生成的HTML具有版本号。

<link href="/Content/css/cats?v=6GDW6wAXIN5DJCxVtIkkxLGpojoP-tBQiKgBTQMSlWw1" rel="stylesheet"/>
如果它看起来像这样,而且没有显示出来,那么你在 Bundle 表和 cshtml 文件中的包名称可能并不完全匹配。
<link href="/Content/css/cats" rel="stylesheet"/>

我不确定我是否看错了,但似乎你在建议new StyleBundle("~/content/css")是可以接受和推荐的,但如果您的“content”目录中有一个“css”文件夹(这是很常见的设置),则不可以。 - Matt Mitchell
@MattMitchell 实际上这就是原帖中所说的,所以我解释了为什么它会导致错误以及为什么你不应该将其命名为这样。 - Simon_Weaver

4

不要忘记确保捆绑的HttpModule已经存在。

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

这在第一次使用时让我感到困扰。不确定NuGet包是否应该添加必要的配置,但在我的情况下没有。


3
我刚解决了一个类似的问题。问题是我通过NuGet安装了“chosen”插件,但在 BundleConfig 类中,包含 CSS 文件的代码行看起来像这样:
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css",)); 
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/chosen.css"));

在那个类中,我有这样一行代码:

BundleTable.EnableOptimizations = true;

解决方法是将两个 bundles.Add() 合并,代码如下:
bundles.Add(new StyleBundle("~/Content/css").Include(
                            "~/Content/site.css", 
                            "~/Content/chosen.css"
                        ));

这对我解决了问题。

3

我认为那看起来是正确的。当启用优化时,您只会有一个引用,并且它将是您在StyleBundle(/content/css)中指定的名称。在调试模式下(或更具体地说,在web config中debug=false),您将像平常一样获得非优化文件。如果您仔细观察,您会发现它们只是您键入的纯文本。但是,当启用优化时(通常在运行发布模式时),您将得到一个奇怪的URL。

如果您查看其输出,它将被缩小。查询字符串“?v=5KLoJ....”基于包中的文件的哈希值。这样可以安全地HTTP缓存引用,时间可以长达您想要的时间。如果您喜欢,可以永远,但是我认为默认值为一年。但是,如果您修改任何样式表,则会生成新的哈希值,这就是“缓存破坏”,因此您将在浏览器上获得新副本。

话虽如此,我不确定为什么您会得到404错误。我怀疑这与您的路由配置或IIS设置有关。您是否在使用IISExpress的Visual Studio中运行?


我正在使用VS2010,使用ASP.NET开发服务器(集成的用于测试/调试)。 - Stan
你是否调用了EnableDefaultBundles()函数?否则,似乎你的URL没有被传递 - 尝试将应用程序池的模式更改为“集成”。 - cirrus

0

这也可能是因为出于某种原因,您尚未将bundleconfig.json部署到服务器上。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接