Asp.net mvc ASP.NET MVC中CSS/JS的自动版本控制?

Asp.net mvc ASP.NET MVC中CSS/JS的自动版本控制?,asp.net-mvc,auto-versioning,Asp.net Mvc,Auto Versioning,因此,我在阅读ASP.NET MVC中有关CSS/JS文件的“自动版本控制”的内容,并想知道执行此操作的“最佳”策略是什么 提供的解决方案会插入一个程序集编号,这意味着每次发布时,它都会更改每个不理想的文件,因为如果只修改1*.css或*.js,它会更改每个文件 1) 如何仅针对“单个文件”而不使用使用修改日期或IIS7上的某个内容的现场装配 2) 还有,如果我有一些“静态”资产,比如——如果有人将此静态链接集成到他们的站点上,我如何使用“重写”发送请求的最新文件 i、 e.是链接,当有此请求时

因此,我在阅读ASP.NET MVC中有关CSS/JS文件的“自动版本控制”的内容,并想知道执行此操作的“最佳”策略是什么

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

1) 如何仅针对“单个文件”而不使用使用修改日期或IIS7上的某个内容的现场装配

2) 还有,如果我有一些“静态”资产,比如——如果有人将此静态链接集成到他们的站点上,我如何使用“重写”发送请求的最新文件

i、 e.是链接,当有此请求时-检查并发送最新文件?

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);
}
这将为“
style.css
”生成类似“
/static/201109231100/style.css
”的路径(假设您的
style.css
位于
static
目录中)。 然后,您将在IIS中添加一个重写规则,将“
/static/201109231100/style.css
”重写为“
/static/style.css
”。仅当css文件已修改且仅适用于已修改的文件时,版本号才会更改

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

您可能想看看Dean Hume的博客帖子。在那篇文章中,他指出了一种优雅的方法,可以使用以下类库自动处理每个请求的版本控制:


我写了一个Url帮助器,它为我进行缓存破坏

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(),该调用根据文件的内容或上次修改日期生成唯一字符串


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

ASP.NET 4.5+附带 这是为了解决这个问题而设计的。

如果您确实需要一个简单的滚动解决方案,您可以使用下面的答案,但我始终认为正确的方法是使用捆绑和缩小框架


您可以像这样修改AssemblyInfo.cs文件:

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" />

更新:以前的版本在Azure上不起作用,我在下面进行了简化和更正。(注意,要使其在IIS Express的开发模式下工作,您需要从Microsoft安装URL Rewrite 2.0-它使用WebPi安装程序,请确保先关闭Visual Studio)

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

方法:每次生成项目时自动增加程序集版本,并将该数字用于您希望保持刷新的特定资源上的路由静态文件。(因此something.js包含为something.v1234.js,其中1234在每次生成项目时自动更改)-我还添加了一些附加功能,以确保在生产中使用.min.js文件,并在调试时使用常规的.js文件(我使用WebFeel自动化缩小过程)。此解决方案的一个优点是它可以在本地/开发模式以及生产模式下工作。(我使用的是Visual Studio 2015/Net 4.6,但我相信在早期版本中也可以使用

步骤1:生成时启用部件上的自动增量 在AssemblyInfo.cs文件(位于项目的“属性”部分下)中,更改以下行:

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

步骤2:在web.config中为带有嵌入式版本段塞的文件设置url重写(请参见步骤3)

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

<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>
步骤4:使用我们在Global.asax.cs中设置的应用程序变量更改Razor视图中的src链接

@HttpContext.Current.Application["CSSVer"]
@HttpContext.Current.Application["JSVer"]
例如,在my_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)

@RenderSection(“PageCSS”,必填项:false)
这里有几点需要注意:1)文件上没有扩展名。2)也没有.min。这两个都由Global.asax.cs中的代码处理

@HttpContext.Current.Application["CSSVer"]
@HttpContext.Current.Application["JSVer"]
同样,(也在_Layout.cs中)在我的javascript部分:我有以下代码:

<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)

@RenderSection(“脚本”,必需:false)
第一个文件是我用WebLibe手动创建的所有第三方库的捆绑包
<!-- 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)
<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)