在ASP.NET MVC中自动转换CSS / JS?

时间:2011-04-28 12:45:32

标签: asp.net-mvc auto-versioning

所以我正在阅读有关CSS / JS文件的ASP.NET MVC中的“autoversioning”的this stackoverflow post,并且想知道“最佳”策略是做什么的。

提供的解决方案插入一个程序集编号 - 这意味着每次发布时 - 它将更改不理想的每个单个文件,因为如果您只修改1 * .css或* .js然后它会改变每一个文件。

1)如何仅针对“单个文件”而不是使用修改日期或IIS7上的某些内容进行站点范围的组装?

2)此外,如果我有某种“静态”资产,例如 - http://static.domain.com/js/123.js - 如果有人将此静态链接集成到他们的网站上,如何使用重写来发送请求的最新文件?

即。 http://static.domain.com/js/123.js是链接,当有请求时 - 检查并发送最新文件?

5 个答案:

答案 0 :(得分:16)

我解决这个问题的方法是在 AssemblyInfo.cs 文件中添加autoversioning到我的MVC项目,如下所示:

Change
[assembly: AssemblyVersion("1.0.0.0")]
to    
[assembly: AssemblyVersion("1.0.*")]

这意味着每次构建项目时,它都会有一个比前一个更高的新程序集版本。现在您拥有唯一的版本号。

然后我创建了一个UrlHelperExtension类,它可以帮助我在我的视图中需要它时获取这些信息:

public static class UrlHelperExtensions
{
    public static string ContentVersioned(this UrlHelper self, string contentPath)
    {
        string versionedContentPath = contentPath + "?v=" + Assembly.GetAssembly(typeof(UrlHelperExtensions)).GetName().Version.ToString();
        return self.Content(versionedContentPath);
    }
}

您现在可以通过以下方式轻松地为视图添加版本号:

<link href="@Url.ContentVersioned("style.css")" rel="stylesheet" type="text/css" />

查看您的网页来源时,您现在会看到类似

的内容
<link href="style.css?v=1.0.4809.30029" rel="stylesheet" type="text/css" />

答案 1 :(得分:6)

1) 请改用文件修改时间。这是一个例子:

public static string GeneratePathWithTime(string cssFileName)
{
  var serverFilePath = server.MapPath("~/static/" + cssFileName);
  var version = File.GetLastWriteTime(serverFilePath).ToString("yyyyMMddhhmmss");
  return string.Format("/static/{0}/{1}", version, cssFileName);
}

这将为“/static/201109231100/style.css”生成类似“style.css”的路径(假设您的style.css位于static目录中)。 然后,您将在IIS中添加重写规则,将“/static/201109231100/style.css”重写为“/static/style.css”。版本号仅在修改css文件时更改,并且仅适用于已修改的文件。

2) 您可以通过HttpModule处理对123.js的请求并发送它的最新内容,但我认为您不能保证请求获得最新版本。这取决于浏览器如何处理其缓存。您可以在响应标头中设置较早的过期时间(例如,一分钟前),以告知浏览器始终重新下载文件,但是由浏览器本身决定是否重新下载文件。这就是为什么我们每次更新问题时都需要为修改后的文件生成不同的路径1),如果以前从未访问过该URL,浏览器将始终尝试下载该文件。

答案 2 :(得分:5)

更新:以前的版本无法在Azure上运行,我已在下面进行了简化和更正。 (注意,为了在IIS Express的开发模式下工作,您需要从Microsoft http://www.iis.net/downloads/microsoft/url-rewrite安装URL Rewrite 2.0 - 它使用WebPi安装程序,确保首先关闭Visual Studio)

如果您想更改文件的实际名称,而不是附加查询字符串(某些代理/浏览器会忽略静态文件)您可以按照以下步骤操作:(我知道这是一个旧帖子,但我在开发解决方案时遇到了它:

如何操作: 每次构建项目时自动增加程序集版本,并将该数字用于特定资源上的路由静态文件喜欢保持精神焕发。 (所以something.js包含为something.v1234.js,每次构建项目时都会自动更改1234) - 我还添加了一些额外的功能,以确保在生产中使用.min.js文件并使用regular.js文件调试时(我正在使用WebGrease自动化缩小过程)这个解决方案的一个好处是它可以在本地/开发模式和生产中工作。 (我使用的是Visual Studio 2015 / Net 4.6,但我相信这也适用于早期版本。

步骤1:在构建时启用程序集上的自动增量 在AssemblyInfo.cs文件中(位于项目的&#34;属性&#34;部分下面)更改以下行:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

[assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyFileVersion("1.0.0.0")]

第2步:在web.config中为包含嵌入版本slugs的文件设置url重写(参见步骤3)

在web.config(项目的主要部分)中,在<system.webServer>部分添加以下规则,我将其直接放在</httpProtocol>结束标记之后。

<rewrite>
  <rules>
    <rule name="static-autoversion">
      <match url="^(.*)([.]v[0-9]+)([.](js|css))$" />
      <action type="Rewrite" url="{R:1}{R:3}" />
    </rule>
    <rule name="static-autoversion-min">
      <match url="^(.*)([.]v[0-9]+)([.]min[.](js|css))$" />
      <action type="Rewrite" url="{R:1}{R:3}" />
    </rule>
  </rules>
</rewrite>

步骤3:设置应用程序变量以读取当前程序集版本并在js和css文件中创建版本slu。

在Global.asax.cs中找到

(在项目的根目录中找到)将以下代码添加到protected void Application_Start()(在Register行之后)

            // setup application variables to write versions in razor (including .min extension when not debugging)
            string addMin = ".min";
            if (System.Diagnostics.Debugger.IsAttached) { addMin = ""; }  // don't use minified files when executing locally
            Application["JSVer"] = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace('.','0') + addMin + ".js";
            Application["CSSVer"] = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace('.', '0') + addMin + ".css";

第4步:使用我们在Global.asax.cs中设置的应用程序变量更改Razor视图中的src链接

@HttpContext.Current.Application["CSSVer"]
@HttpContext.Current.Application["JSVer"]

例如,在我的_Layout.cshtml中,在我的头部分中,我有以下样式表代码块:

<!-- Load all stylesheets -->
<link rel='stylesheet' href='https://fontastic.s3.amazonaws.com/8NNKTYdfdJLQS3D4kHqhLT/icons.css' />
<link rel='stylesheet' href='/Content/css/main-small.@HttpContext.Current.Application["CSSVer"]' />
<link rel='stylesheet' media='(min-width: 700px)' href='/Content/css/medium.@HttpContext.Current.Application["CSSVer"]' />
<link rel='stylesheet' media='(min-width: 700px)' href='/Content/css/large.@HttpContext.Current.Application["CSSVer"]' />
@RenderSection("PageCSS", required: false)

这里有几点需要注意:1)文件上有无扩展名。 2)也没有.min。这两个都由Global.asax.cs

中的代码处理

同样,在我的javascript部分(也在_Layout.cs中):我有以下代码:

<script src="~/Scripts/all3bnd100.min.js" type="text/javascript"></script>
<script src="~/Scripts/ui.@HttpContext.Current.Application["JSVer"]" type="text/javascript"></script>
@RenderSection("scripts", required: false)

第一个文件是我用WebGrease手动创建的所有第三方库的捆绑包。如果我添加或更改捆绑包中的任何文件(这是罕见的),那么我手动将文件重命名为all3bnd101.min.js,all3bnd102.min.js等...此文件与重写处理程序不匹配,所以将保留在客户端浏览器上的缓存,直到您手动重新捆绑/更改名称。

第二个文件是ui.js(根据你是否在调试模式下运行,将写成ui.v12345123.js或ui.v12345123.min.js)这将被处理/重写。 (您可以在Global.asax.cs的Application_OnBeginRequest中设置断点以观察它的工作情况)

对此进行全面讨论:Simplified Auto-Versioning of Javascript / CSS in ASP.NET MVC 5 to stop caching issues (works in Azure and Locally) With or Without URL Rewrite (包括在没有网址重写的情况下执行此操作)

答案 3 :(得分:4)

我写了一个Url Helper,它为我做了CacheBusting。

public static string CacheBustedContent(this UrlHelper helper, string contentPath)
{
    var path = string.Empty;

    if (helper.RequestContext.HttpContext.Cache["static-resource-" + contentPath] == null)
    {
        var fullpath = helper.RequestContext.HttpContext.Server.MapPath(contentPath);
        var md5 = GetMD5HashFromFile(fullpath);
        path = helper.Content(contentPath) + "?v=" + md5;

        helper.RequestContext.HttpContext.Cache.Add("static-resource-" + contentPath, path, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(24, 0, 0), System.Web.Caching.CacheItemPriority.Default, null);
    }
    else
    {
        path = helper.RequestContext.HttpContext.Cache["static-resource-" + contentPath].ToString();
    }

    return path;
}

您可以使用CRC或任何其他类型的调用替换GetMD5HashFromFile(),该调用根据文件的内容或上次修改日期生成唯一字符串。

缺点是每当缓存失效时都会调用它。如果你以某种方式在现场更改文件,但不重置应用程序池,则可能需要触摸web.config以使其正确重新加载。

答案 4 :(得分:3)

你可能想看看Dean Hume的Blogpost MVC and the HTML5 Application Cache。在那篇文章中,他指出了一种使用@ShirtlessKirk的类库自动处理每个请求版本控制的优雅方法:

@Url.Content("~/Content/Site.css").AppendHash(Request)