C# 强制浏览器在 asp.net 应用程序中获取最新的 js 和 css 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2185872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
force browsers to get latest js and css files in asp.net application
提问by kiev
Some browsers cache js and css files, failing to refresh them unless you force them to. What's the easiest way.
一些浏览器会缓存 js 和 css 文件,除非您强制刷新它们,否则无法刷新它们。最简单的方法是什么。
I just implemented this solution that seems to work.
我刚刚实施了这个似乎有效的解决方案。
Declare a version variable on your page
在页面上声明一个版本变量
public string version { get; set; }
Get the version number from web.config key
从 web.config 键中获取版本号
version = ConfigurationManager.AppSettings["versionNumber"];
In your aspx page make the calls to javascript and stylesheets like so
在您的 aspx 页面中,像这样调用 javascript 和样式表
<script src="scripts/myjavascript.js?v=<%=version %>" type="text/javascript"></script>
<link href="styles/mystyle.css?v=<%=version %>" rel="stylesheet" type="text/css" />
So if you set the version = 1.1 from 1.0 in your web.config your browser will download the latest files which will hopefully save you and your users some frustration.
因此,如果您在 web.config 中从 1.0 设置 version = 1.1,您的浏览器将下载最新的文件,这有望为您和您的用户节省一些麻烦。
Is there another solution that works better, or will this cause any unforeseen issues for a website?
是否有其他更好的解决方案,或者这是否会导致网站出现任何不可预见的问题?
采纳答案by Adam Tegen
I solved this by tacking a last modified timestamp as a query parameter to the scripts.
我通过将最后修改的时间戳作为查询参数添加到脚本中解决了这个问题。
I did this with an extension method, and using it in my CSHTML files. Note:this implementation caches the timestamp for 1 minute so we don't thrash the disk quite so much.
我用一个扩展方法做到了这一点,并在我的 CSHTML 文件中使用它。 注意:此实现将时间戳缓存 1 分钟,因此我们不会对磁盘造成太大影响。
Here is the extension method:
下面是扩展方法:
public static class JavascriptExtension {
public static MvcHtmlString IncludeVersionedJs(this HtmlHelper helper, string filename) {
string version = GetVersion(helper, filename);
return MvcHtmlString.Create("<script type='text/javascript' src='" + filename + version + "'></script>");
}
private static string GetVersion(this HtmlHelper helper, string filename)
{
var context = helper.ViewContext.RequestContext.HttpContext;
if (context.Cache[filename] == null)
{
var physicalPath = context.Server.MapPath(filename);
var version = $"?v={new System.IO.FileInfo(physicalPath).LastWriteTime.ToString("MMddHHmmss")}";
context.Cache.Add(filename, version, null,
DateTime.Now.AddMinutes(5), TimeSpan.Zero,
CacheItemPriority.Normal, null);
return version;
}
else
{
return context.Cache[filename] as string;
}
}
}
And then in the CSHTML page:
然后在 CSHTML 页面中:
@Html.IncludeVersionedJs("/MyJavascriptFile.js")
In the rendered HTML, this appears as:
在呈现的 HTML 中,这显示为:
<script type='text/javascript' src='/MyJavascriptFile.js?20111129120000'></script>
回答by Daniel Vassallo
Your solution works. It is quite popular in fact.
您的解决方案有效。事实上,它很受欢迎。
Even Stack Overflow uses a similar method:
甚至 Stack Overflow 也使用类似的方法:
<link rel="stylesheet" href="http://sstatic.net/so/all.css?v=6184">
Where v=6184
is probably the SVN revision number.
v=6184
SVN 版本号可能在哪里。
回答by Tim S. Van Haren
The main problem with doing it this way is mainly that you will need to remember to update your version number in your code every time you make any change to your css or js files.
这样做的主要问题在于,每次对 css 或 js 文件进行任何更改时,您都需要记住更新代码中的版本号。
A possibly better way to do it is to set a guaranteed unique parameter with each of your css or js files, like so:
一个可能更好的方法是为每个 css 或 js 文件设置一个有保证的唯一参数,如下所示:
<script src="scripts/myjavascript.js?_=<%=DateTime.Now.Ticks%>" type="text/javascript"></script>
<link href="styles/mystyle.css?_=<%=DateTime.Now.Ticks%>" rel="stylesheet" type="text/css" />
This forces the files to be requested from the server every single time, which also means that your site will not be as performant upon page load, since those files will never be cached, and will use unneeded bandwidth each time.
这会强制每次都从服务器请求文件,这也意味着您的站点在页面加载时的性能会下降,因为这些文件永远不会被缓存,并且每次都会使用不需要的带宽。
Essentially, if you can remember to update the version number every time a change is made, you can get away with how you're doing it.
从本质上讲,如果您能记得每次更改时更新版本号,您就可以摆脱自己的做法。
回答by Pekka
Interestingly, this very site has issues with the approach you describe in connection with some proxy setups, even though it should be fail-safe.
有趣的是,这个站点与您描述的与某些代理设置相关的方法存在问题,即使它应该是故障安全的。
Check this Meta Stack Overflowdiscussion.
检查这个Meta Stack Overflow讨论。
So in light of that, it might make sense not to use a GET parameter to update, but the actual file name:
因此,鉴于此,不使用 GET 参数来更新可能更有意义,而是使用实际文件名:
href="/css/scriptname/versionNumber.css"
even though this is more work to do, as you'll have to actually create the file, or build a URL rewrite for it.
尽管这需要做更多的工作,因为您必须实际创建文件,或为其构建 URL 重写。
回答by Ravi Ram
For ASP.NET pages I am using the following
对于 ASP.NET 页面,我使用以下内容
BEFORE
前
<script src="/Scripts/pages/common.js" type="text/javascript"></script>
AFTER (force reload)
之后(强制重新加载)
<script src="/Scripts/pages/common.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>
Adding the DateTime.Now.Ticks works very well.
添加 DateTime.Now.Ticks 效果很好。
回答by HymanArbiter
There is a simpler answer to this than the answer given by the op in the question (the approach is the same):
对此有一个比问题中的操作给出的答案更简单的答案(方法相同):
Define the key in the web.config:
在 web.config 中定义密钥:
<add key="VersionNumber" value="06032014"/>
Make the call to appsettings directly from the aspx page:
直接从 aspx 页面调用 appsettings:
<link href="styles/navigation.css?v=<%=ConfigurationManager.AppSettings["VersionNumber"]%>" rel="stylesheet" type="text/css" />
回答by jonesy827
ASP.NET MVC will handle this for you if you use bundles for your JS/CSS. It will automatically append a version number in the form of a GUID to your bundles and only update this GUID when the bundle is updated (aka any of the source files have changes).
如果您为 JS/CSS 使用包,ASP.NET MVC 将为您处理此问题。它会自动以 GUID 的形式将版本号附加到您的包中,并且仅在包更新时更新此 GUID(也就是任何源文件有更改)。
This also helps if you have a ton of JS/CSS files as it can greatly improve content load times!
如果您有大量 JS/CSS 文件,这也很有帮助,因为它可以大大缩短内容加载时间!
回答by Bryan
Based on Adam Tegan's answer, modified for use in a web forms application.
基于Adam Tegan 的回答,经过修改以在 Web 表单应用程序中使用。
In the .cs class code:
在 .cs 类代码中:
public static class FileUtility
{
public static string SetJsVersion(HttpContext context, string filename) {
string version = GetJsFileVersion(context, filename);
return filename + version;
}
private static string GetJsFileVersion(HttpContext context, string filename)
{
if (context.Cache[filename] == null)
{
string filePhysicalPath = context.Server.MapPath(filename);
string version = "?v=" + GetFileLastModifiedDateTime(context, filePhysicalPath, "yyyyMMddhhmmss");
return version;
}
else
{
return string.Empty;
}
}
public static string GetFileLastModifiedDateTime(HttpContext context, string filePath, string dateFormat)
{
return new System.IO.FileInfo(filePath).LastWriteTime.ToString(dateFormat);
}
}
In the aspx markup:
在 aspx 标记中:
<script type="text/javascript" src='<%= FileUtility.SetJsVersion(Context,"/js/exampleJavaScriptFile.js") %>'></script>
And in the rendered HTML, it appears as
在呈现的 HTML 中,它显示为
<script type="text/javascript" src='/js/exampleJavaScriptFile.js?v=20150402021544'></script>
回答by Ender2050
Here's an approach that works with ASP.NET 5 / MVC 6 / vNext.
这是一种适用于ASP.NET 5 / MVC 6 / vNext 的方法。
Step 1:Create a class to return the last write time of the file, similar to other answers in this thread. Note, this requires ASP.NET 5 (or other) dependency injection.
步骤1:创建一个类来返回文件的最后写入时间,类似于该线程中的其他答案。请注意,这需要 ASP.NET 5(或其他)依赖项注入。
public class FileVersionService
{
private IHostingEnvironment _hostingEnvironment;
public FileVersionService(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
public string GetFileVersion(string filename)
{
var path = string.Format("{0}{1}", _hostingEnvironment.WebRootPath, filename);
var fileInfo = new FileInfo(path);
var version = fileInfo.LastWriteTimeUtc.ToString("yyyyMMddhhmmssfff");
return version;
}
}
Step 2:Register the service to be injected inside startup.cs:
第二步:在startup.cs中注册要注入的服务:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<FileVersionService>();
...
}
Step 3:Then, in ASP.NET 5, it is possible to inject the service directly into a layout view such as _Layout.cshtmllike this:
第 3 步:然后,在 ASP.NET 5 中,可以将服务直接注入到布局视图中,例如_Layout.cshtml,如下所示:
@inject Namespace.Here.FileVersionService fileVersionService
<!DOCTYPE html>
<html lang="en" class="@ViewBag.HtmlClass">
<head>
...
<link href="/css/[email protected]("\css\styles.css")" rel="stylesheet" />
...
</head>
<body>
...
</body>
There are some finishing touches that could be done to combine physical paths better and handle the file name in a style more consistent with the syntax, but this is a starting point. Hope it helps people moving to ASP.NET 5.
有一些收尾工作可以更好地组合物理路径并以更符合语法的样式处理文件名,但这是一个起点。希望它可以帮助人们迁移到 ASP.NET 5。
回答by Uwe Keim
Based on the above answerI've written a small extension class to work with CSS and JS files:
基于上面的答案,我编写了一个小的扩展类来处理 CSS 和 JS 文件:
public static class TimestampedContentExtensions
{
public static string VersionedContent(this UrlHelper helper, string contentPath)
{
var context = helper.RequestContext.HttpContext;
if (context.Cache[contentPath] == null)
{
var physicalPath = context.Server.MapPath(contentPath);
var version = @"v=" + new FileInfo(physicalPath).LastWriteTime.ToString(@"yyyyMMddHHmmss");
var translatedContentPath = helper.Content(contentPath);
var versionedContentPath =
contentPath.Contains(@"?")
? translatedContentPath + @"&" + version
: translatedContentPath + @"?" + version;
context.Cache.Add(physicalPath, version, null, DateTime.Now.AddMinutes(1), TimeSpan.Zero,
CacheItemPriority.Normal, null);
context.Cache[contentPath] = versionedContentPath;
return versionedContentPath;
}
else
{
return context.Cache[contentPath] as string;
}
}
}
Instead of writing something like:
而不是写这样的东西:
<link href="@Url.Content(@"~/Content/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content(@"~/Scripts/bootstrap.min.js")"></script>
You can now write:
你现在可以写:
<link href="@Url.VersionedContent(@"~/Content/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<script src="@Url.VersionedContent(@"~/Scripts/bootstrap.min.js")"></script>
I.e. simply replace Url.Content
with Url.VersionedContent
.
即简单地替换Url.Content
为Url.VersionedContent
。
Generated URLs look something like:
生成的 URL 类似于:
<link href="/Content/bootstrap.min.css?v=20151104105858" rel="stylesheet" type="text/css" />
<script src="/Scripts/bootstrap.min.js?v=20151029213517"></script>
If you use the extension class you might want to add error handling in case the MapPath
call doesn't work, since contentPath
isn't a physical file.
如果您使用扩展类,您可能想要添加错误处理以防MapPath
调用不起作用,因为contentPath
它不是物理文件。