buộc các trình duyệt tải các tệp js và css mới nhất trong ứng dụng asp.net


104

Một số trình duyệt lưu vào bộ nhớ cache các tệp js và css, không thể làm mới chúng trừ khi bạn buộc chúng. Cách dễ nhất là gì.

Tôi vừa thực hiện giải pháp này có vẻ hoạt động.

Khai báo một biến phiên bản trên trang của bạn

  public string version { get; set; }

Nhận số phiên bản từ khóa web.config

 version = ConfigurationManager.AppSettings["versionNumber"];

Trong trang aspx của bạn, hãy thực hiện các lệnh gọi tới javascript và các bảng định kiểu như vậy

<script src="scripts/myjavascript.js?v=<%=version %>" type="text/javascript"></script>
<link href="styles/mystyle.css?v=<%=version %>" rel="stylesheet" type="text/css" />

Vì vậy, nếu bạn đặt phiên bản = 1.1 từ 1.0 trong web.config, trình duyệt của bạn sẽ tải xuống các tệp mới nhất, hy vọng sẽ giúp bạn và người dùng của bạn đỡ thất vọng.

Có giải pháp nào khác hoạt động tốt hơn hay điều này sẽ gây ra bất kỳ sự cố không lường trước cho trang web?


Câu hỏi thú vị, tôi đã gặp vấn đề tương tự gần đây, nhưng chỉ là một vấn đề trong quá trình thử nghiệm phát triển. Không quan tâm nhiều đến nó vì chúng tôi không có ý định thay đổi các tệp đó sau khi khởi chạy. Rất muốn biết một giải pháp mặc dù để tham khảo trong tương lai!
Brett Allen

Vấn đề duy nhất tôi có thể thấy là các thay đổi đối với web.config, trong nền, sẽ gọi khởi động lại ứng dụng: msdn.microsoft.com/en-us/library/aa478432.aspx
monty,

Cảm ơn vì đã hỏi. Điều này đã giúp tôi giải quyết một vấn đề lớn.
Reddy

Câu trả lời:


76

Tôi đã giải quyết điều này bằng cách đóng dấu thời gian được sửa đổi lần cuối làm tham số truy vấn cho các tập lệnh.

Tôi đã làm điều này với một phương thức mở rộng và sử dụng nó trong các tệp CSHTML của mình. Lưu ý: việc triển khai này lưu vào bộ nhớ cache dấu thời gian trong 1 phút để chúng tôi không làm hỏng đĩa quá nhiều.

Đây là phương thức mở rộng:

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;
        }
    }
}

Và sau đó trong trang CSHTML:

 @Html.IncludeVersionedJs("/MyJavascriptFile.js")

Trong HTML được hiển thị, điều này xuất hiện dưới dạng:

 <script type='text/javascript' src='/MyJavascriptFile.js?20111129120000'></script>

1
điều này là tuyệt vời cho mvc, tôi tự hỏi nếu khuôn khổ mvc 5 mới nhất có xử lý vấn đề này không? Cách tiếp cận đó bundling sử dụng với - {version} ký tự đại diện cũng là một cách để giải quyết vấn đề này, tuy nhiên nó đòi hỏi các tập tin được đổi tên sau mỗi lần xây dựng mới ...
kiev

Tôi đang sử dụng thông tin cơ bản về ví dụ MVC của bạn trong một trang web biểu mẫu web và nó hoạt động rất tốt, vì vậy cảm ơn bạn đã chia sẻ!
Bryan,

Có nên lo ngại về việc hiển thị dấu ngày / giờ sửa đổi lần cuối cho các tệp tài nguyên không? Nếu một tệp đang được sử dụng có dấu ngày / giờ cách đây vài năm, có thể là thông tin mà một công ty có thể không muốn công khai cho người dùng của họ không?
Bryan,

Đó là cách tiêu chuẩn, hầu hết các ứng dụng đều tuân theo. Nhưng dấu thời gian đó chỉ nên thay đổi khi bạn triển khai hoặc xây dựng ứng dụng của mình. Nếu không mỗi khi người dùng làm mới trang hoặc chuyển sang các trang khác trong ứng dụng của bạn. Trình duyệt sẽ tải xuống lại tất cả các bảng định kiểu và javascript của bạn, điều này không tốt
Tarun

2
Tác động đến hiệu suất của trang là gì? Nó có thể gây ra bao nhiêu độ trễ để tải trang?
Durgesh Sonawane

28

Giải pháp của bạn hoạt động. Nó khá phổ biến trên thực tế.

Ngay cả Stack Overflow cũng sử dụng một phương pháp tương tự:

<link rel="stylesheet" href="http://sstatic.net/so/all.css?v=6184"> 

Trong trường hợp v=6184có lẽ là số phiên bản SVN.


Đây sẽ là một cách tiếp cận đánh thuế nhiều hơn so với cách được mô tả trong câu trả lời được chấp nhận. Kiểm tra phiên bản SVN của tệp mỗi khi một trang được phân phát là một chi phí hiệu suất, đặc biệt là khi số lượng người dùng tăng lên theo thời gian.
Neolisk

4
Bạn có thể lấy số sửa đổi trong quá trình xây dựng, ghi nó vào một tệp (ví dụ: một phần tệp .cs), đưa tệp đó vào dự án của bạn, vì vậy bạn không cần phải đọc nó từ svn trong thời gian chạy. Tôi đã sử dụng cách tiếp cận này với msbuild để đặt số sửa đổi trong tệp AssemblyInfo.cs của tôi từ svn.
Ramazan Binarbasi

2
Sử dụng phiên bản toàn cầu / số sửa đổi có ít nhất một nhược điểm: xuất bản bản cập nhật trang web làm mất hiệu lực bộ nhớ cache của trình duyệt cho tất cả các tệp .js và .css, không chỉ những tệp đã thay đổi. Điều này có lẽ không quan trọng trong phần lớn các ứng dụng, nhưng tôi đề cập đến nó để hoàn thiện.
Adam Tegen

Nếu bạn cập nhật phiên bản của tệp assemblyinfo.cs của mình tự động trong quá trình triển khai hoặc xây dựng, thì phiên bản nhỏ có thể được sử dụng cho số đó.
kristianp

28

Trong ASP.NET Core (MVC 6), điều này hoạt động hiệu quả thông qua trình asp-append-versiontrợ giúp thẻ:

<script src="scripts/myjavascript.js" asp-append-version="true"></script>
<link href="styles/mystyle.css rel="stylesheet" asp-append-version="true" />

1
Cảm ơn vì đã cho chúng tôi biết! Tôi không biết điều đó trước đây!
Federico Navarrete,

18

ASP.NET MVC sẽ xử lý điều này cho bạn nếu bạn sử dụng gói cho JS / CSS của mình. Nó sẽ tự động thêm số phiên bản dưới dạng GUID vào các gói của bạn và chỉ cập nhật GUID này khi gói được cập nhật (hay còn gọi là bất kỳ tệp nguồn nào có thay đổi).

Điều này cũng hữu ích nếu bạn có rất nhiều tệp JS / CSS vì nó có thể cải thiện đáng kể thời gian tải nội dung!

Xem tại đây


Ý của bạn là nếu chúng ta sử dụng các gói trong một ứng dụng MVC, thì không cần bất kỳ phương pháp nào trong câu trả lời đã đăng ở đây? Nếu vậy, việc đóng gói thực sự quan trọng hơn nhiều mà tôi từng nghĩ. Bạn có thể vui lòng làm rõ cho chúng tôi về vấn đề này? Cảm ơn.
Jack

1
Đúng chính xác. Miễn là các tập lệnh của bạn được bao gồm trong một gói, nó sẽ tự động tạo số phiên bản cho mỗi gói khi các thay đổi được phát hiện trong bất kỳ tệp nguồn nào của gói.
jonesy827

Và đừng quên rằng bạn vẫn phải đau đầu với tư cách là một nhà phát triển. Gói ASP.NET giúp ích rất nhiều trong quá trình gỡ lỗi và phát triển.
it3xl

12

Có một cách tích hợp trong asp.net cho điều này: gói . Chỉ cần sử dụng nó. Mỗi phiên bản mới sẽ có hậu tố duy nhất "? V = XXXXXXX". Ở chế độ gỡ lỗi, gói bị tắt, để bật thực hiện cài đặt trong web.config:

<system.web>
    <compilation debug="false" />
</system.web>

Hoặc thêm vào phương thức RegisterBundles (Gói BundleCollection):

BundleTable.EnableOptimizations = true;

Ví dụ:

BundleConfig.cs:

bundles.Add(new ScriptBundle("~/Scripts/myjavascript.js")
                .Include("~/Scripts/myjavascript.js"));

bundles.Add(new StyleBundle("~/Content/mystyle.css")
                .Include("~/Content/mystyle.css"));

_Layout.cshtml:

@Scripts.Render("~/Scripts/myjavascript.js")
@Styles.Render("~/Content/mystyle.css")

Nhưng điều này sẽ chỉ hoạt động trong môi trường phát hành hoặc sản xuất. Điều gì về phát triển khi chế độ gỡ lỗi được bật? Gói vẫn khắc phục sự cố này?
VAAA

Yeah, Bundlind không giúp các nhà phát triển sống dễ dàng hơn. Bạn phải nhấn Ctrl-F5 sau mỗi lần thay đổi tập lệnh. Và nếu bạn có khung, nó sẽ còn hài hước hơn.
it3xl

6

Có một câu trả lời đơn giản hơn cho câu trả lời này so với câu trả lời được đưa ra bởi op trong câu hỏi (cách tiếp cận là giống nhau):

Xác định khóa trong web.config:

<add key="VersionNumber" value="06032014"/>

Thực hiện cuộc gọi đến các cài đặt ứng dụng trực tiếp từ trang aspx:

<link href="styles/navigation.css?v=<%=ConfigurationManager.AppSettings["VersionNumber"]%>" rel="stylesheet" type="text/css" />

Tôi thích điều này, nhưng lo ngại tại sao giải pháp này có quá ít phiếu bầu ...
SimplyInk

@SimplyCảm ơn tôi không biết, nhưng có 20 câu trả lời khác nhau, vì vậy điều đó có thể liên quan đến nó. Nếu nó hoạt động và bạn thích nó, hãy ủng hộ nó.
JackArbiter

4

Dựa trên câu trả lời của Adam Tegan , được sửa đổi để sử dụng trong ứng dụng biểu mẫu web.

Trong mã lớp .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);
    }
}

Trong đánh dấu aspx:

<script type="text/javascript" src='<%= FileUtility.SetJsVersion(Context,"/js/exampleJavaScriptFile.js") %>'></script>

Và trong HTML được hiển thị, nó xuất hiện dưới dạng

<script type="text/javascript" src='/js/exampleJavaScriptFile.js?v=20150402021544'></script>

2
Chào! Ví dụ của bạn đang hoạt động, nhưng bạn nên xóa các tham chiếu trong bộ nhớ đệm hoặc sửa mã để sử dụng bộ đệm vì có thể gây nhầm lẫn tại sao bạn đang sử dụng nó. Để sử dụng bộ đệm ẩn, bạn nên thêm phiên bản của tệp vào bộ đệm bằng cách sử dụng phương thức context.Cache.Add trong trường hợp context.Cache [tên tệp] == null. ! Nếu context.Cache [filename] = null thì bạn nên trả về giá trị cache (context.Cache [filename])
Flavia Obreja

1
Flavia, tôi nghĩ lời giải thích của bạn có lý và tôi nghĩ đó là cách triển khai đơn giản hơn, hiệu quả hơn. Cảm ơn bạn đã đăng những nhận xét và phản hồi hữu ích.
Bryan

4

Điều thú vị là chính trang web này có vấn đề với cách tiếp cận mà bạn mô tả liên quan đến một số thiết lập proxy, mặc dù nó phải an toàn với lỗi.

Kiểm tra cuộc thảo luận Meta Stack Overflow này .

Vì vậy, do đó, có thể hợp lý khi không sử dụng tham số GET để cập nhật, mà là tên tệp thực tế:

href="/css/scriptname/versionNumber.css" 

mặc dù việc này còn nhiều việc phải làm vì bạn sẽ phải thực sự tạo tệp hoặc tạo URL ghi lại cho nó.


4

Tôi muốn một lớp lót đơn giản để tạo đường dẫn duy nhất để phá vỡ bộ nhớ cache. Điều này đã làm việc cho tôi:

<script src="scripts/main.js?bust_js_cache=<%=System.IO.File.GetLastWriteTime(Server.MapPath("scripts/main.js")).ToString("HH:mm:ss")%>" type="text/javascript"></script>

Nếu tệp đã được sửa đổi kể từ lần cuối cùng nó được tải trên trang, trình duyệt sẽ kéo tệp cập nhật.

Nó tạo last modifiedtem từ .jstệp và gắn nó vào đó thay vì phiên bản có thể không dễ dàng truy cập.

<script src="scripts/main.js?bust_js_cache=10:18:38" type="text/javascript"></script>

Một tùy chọn khác có thể là lấy tổng kiểm tra của tệp.


1
Cho đến nay, cách dễ nhất để làm điều này và có lẽ là chi phí thấp nhất.
Tony Hinkle,

1
Giải pháp hoàn hảo. Tôi cũng đã thử nghiệm Chrome 70, Firefox 63 và IE 11 để đảm bảo rằng bộ nhớ đệm đang thực sự hoạt động. Nó là. Điều này chỉ phá vỡ bộ nhớ đệm trên các phiên bản mới của tệp, ít nhất là trên các phiên bản mới nhất của trình duyệt. Tôi đã nghe nói ở nơi khác rằng một số trình duyệt tải lại mọi tệp bằng chuỗi truy vấn (?). Có thể điều đó đã từng xảy ra hoặc có thể nó vẫn đúng với Safari và Opera. ĐK.
Brad Mathews

3

Đây là một cách tiếp cận hoạt động với ASP.NET 5 / MVC 6 / vNext .

Bước 1: Tạo lớp trả về thời gian ghi cuối cùng của tệp, tương tự như các câu trả lời khác trong luồng này. Lưu ý, điều này yêu cầu tiêm phụ thuộc ASP.NET 5 (hoặc khác).

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;
     }
}

Bước 2: Đăng ký dịch vụ được đưa vào bên trong startup.cs :

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddScoped<FileVersionService>();
    ...
}

Bước 3: Sau đó, trong ASP.NET 5, có thể đưa dịch vụ trực tiếp vào dạng xem bố cục như _Layout.cshtml như sau:

@inject Namespace.Here.FileVersionService fileVersionService
<!DOCTYPE html>
<html lang="en" class="@ViewBag.HtmlClass">
<head>
    ...
    <link href="/css/styles.css?v=@fileVersionService.GetFileVersion("\\css\\styles.css")" rel="stylesheet" />
    ...
</head>
<body>
    ...
</body>

Có một số bước hoàn thiện có thể được thực hiện để kết hợp các đường dẫn vật lý tốt hơn và xử lý tên tệp theo phong cách phù hợp hơn với cú pháp, nhưng đây là điểm bắt đầu. Hy vọng nó sẽ giúp mọi người chuyển sang ASP.NET 5.


hành vi này thực sự được hỗ trợ ra khỏi hộp, hãy xem câu trả lời của tôi
metalheart

3

Tôi đã sử dụng một kỹ thuật hơi khác trong trang web aspnet MVC 4 của mình:

_ViewStart.cshtml:

@using System.Web.Caching
@using System.Web.Hosting
@{
    Layout = "~/Views/Shared/_Layout.cshtml";
    PageData.Add("scriptFormat", string.Format("<script src=\"{{0}}?_={0}\"></script>", GetDeployTicks()));
}

@functions
{

    private static string GetDeployTicks()
    {
        const string cacheKey = "DeployTicks";
        var returnValue = HttpRuntime.Cache[cacheKey] as string;
        if (null == returnValue)
        {
            var absolute = HostingEnvironment.MapPath("~/Web.config");
            returnValue = File.GetLastWriteTime(absolute).Ticks.ToString();
            HttpRuntime.Cache.Insert(cacheKey, returnValue, new CacheDependency(absolute));
        }
        return returnValue;
    }
}

Sau đó, trong các chế độ xem thực tế:

 @Scripts.RenderFormat(PageData["scriptFormat"], "~/Scripts/Search/javascriptFile.min.js")

3

<?php $rand_no = rand(10000000, 99999999)?> <script src="scripts/myjavascript.js?v=<?=$rand_no"></script>

Điều này phù hợp với tôi trên tất cả các trình duyệt. Ở đây tôi đã sử dụng PHP để tạo số ngẫu nhiên. Bạn có thể sử dụng ngôn ngữ phía máy chủ của riêng mình. '


Câu trả lời rất hay, nhưng ASP MVC có thể gặp một chút vấn đề nếu bạn không xem xét những gì Adam đã giải thích vì tôi đã thử nó và thư mục Bundle không nhận ra nó nếu bạn làm việc với MVC 5. Nhưng cảm ơn bạn đã gợi ý!
Federico Navarrete,

2

Bắt đầu từ câu trả lời ở trên, tôi đã sửa đổi một chút mã để làm cho trình trợ giúp cũng hoạt động với các tệp CSS và thêm phiên bản mỗi khi bạn thực hiện một số thay đổi trong tệp và không chỉ khi bạn xây dựng

public static class HtmlHelperExtensions
{
    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>");
    }

    public static MvcHtmlString IncludeVersionedCss(this HtmlHelper helper, string filename)
    {
        string version = GetVersion(helper, filename);
        return MvcHtmlString.Create("<link href='" + filename + version + "' type ='text/css' rel='stylesheet'/>");
    }

    private static string GetVersion(this HtmlHelper helper, string filename)
    {
        var context = helper.ViewContext.RequestContext.HttpContext;
        var physicalPath = context.Server.MapPath(filename);
        var version = "?v=" +
        new System.IO.FileInfo(physicalPath).LastWriteTime
        .ToString("yyyyMMddHHmmss");
        context.Cache.Add(physicalPath, version, null,
          DateTime.Now.AddMinutes(1), TimeSpan.Zero,
          CacheItemPriority.Normal, null);

        if (context.Cache[filename] == null)
        {
            context.Cache[filename] = version;
            return version;
        }
        else
        {
            if (version != context.Cache[filename].ToString())
            {
                context.Cache[filename] = version;
                return version;
            }
            return context.Cache[filename] as string;
        }
    }
}

1

Nhận thời gian sửa đổi tệp, như được hiển thị bên dưới

private static string GetLastWriteTimeForFile(string pathVal)
    {
        return System.IO.File.GetLastWriteTime(HostingEnvironment.MapPath(pathVal)).ToFileTime().ToString();
    }

Nối điều này với đầu vào là chuỗi truy vấn

public static string AppendDateInFile(string pathVal)
    {
        var patheWithDate = new StringBuilder(pathVal);
        patheWithDate.AppendFormat("{0}x={1}",
                               pathVal.IndexOf('?') >= 0 ? '&' : '?',
                               GetLastWriteTimeForFile(pathVal));
        return patheWithDate.ToString();
    }

Gọi cái này từ đánh dấu.

Phương pháp tiếp cận của trình trợ giúp tiện ích mở rộng MVC

Thêm một phương thức mở rộng

namespace TNS.Portal.Helpers
{
    public static class ScriptExtensions
    {
        public static HtmlString QueryStringScript<T>(this HtmlHelper<T> html, string path)
        {
            var file = html.ViewContext.HttpContext.Server.MapPath(path);
            DateTime lastModified = File.GetLastWriteTime(file);
            TagBuilder builder = new TagBuilder("script");
            builder.Attributes["src"] = path + "?modified=" + lastModified.ToString("yyyyMMddhhmmss");
            return new HtmlString(builder.ToString());
        }

       public static HtmlString QueryStringStylesheet<T>(this HtmlHelper<T> html, string path)
       {
        var file = html.ViewContext.HttpContext.Server.MapPath(path);
        DateTime lastModified = File.GetLastWriteTime(file);
        TagBuilder builder = new TagBuilder("link");
        builder.Attributes["href"] = path + "?modified=" + lastModified.ToString("yyyyMMddhhmmss");
        builder.Attributes["rel"] = "stylesheet";
        return new HtmlString(builder.ToString());
      }

    }
}

Thêm không gian tên này vào web.config

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="TNS.Portal" />
        <add namespace="TNS.Portal.Helpers" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

Sử dụng nó để xem như

@Html.QueryStringScript("/Scripts/NPIAjaxCalls.js")
@Html.QueryStringStylesheet("/Content/StyledRadio.css")

1

Các đề xuất trước được đơn giản hóa và cung cấp mã cho các nhà phát triển Biểu mẫu Web .NET.

Điều này sẽ chấp nhận cả url tương đối ("~ /") và tuyệt đối trong đường dẫn tệp đến tài nguyên.

Đặt vào tệp lớp phần mở rộng tĩnh, như sau:

public static string VersionedContent(this HttpContext httpContext, string virtualFilePath)
{
    var physicalFilePath = httpContext.Server.MapPath(virtualFilePath);
    if (httpContext.Cache[physicalFilePath] == null)
    {
        httpContext.Cache[physicalFilePath] = ((Page)httpContext.CurrentHandler).ResolveUrl(virtualFilePath) + (virtualFilePath.Contains("?") ? "&" : "?") + "v=" + File.GetLastWriteTime(physicalFilePath).ToString("yyyyMMddHHmmss");
    }
    return (string)httpContext.Cache[physicalFilePath];
}

Và sau đó gọi nó trong Trang chính của bạn như vậy:

<link type="text/css" rel="stylesheet" href="<%= Context.VersionedContent("~/styles/mystyle.css") %>" />
<script type="text/javascript" src="<%= Context.VersionedContent("~/scripts/myjavascript.js") %>"></script>

Cách tiếp cận tốt quá!
Federico Navarrete,

0

Dựa trên câu trả lời ở trên, tôi đã viết một lớp mở rộng nhỏ để làm việc với các tệp CSS và 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;
        }
    }
}

Thay vì viết một cái gì đó như:

<link href="@Url.Content(@"~/Content/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content(@"~/Scripts/bootstrap.min.js")"></script>

Bây giờ bạn có thể viết:

<link href="@Url.VersionedContent(@"~/Content/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<script src="@Url.VersionedContent(@"~/Scripts/bootstrap.min.js")"></script>

Tức là chỉ cần thay thế Url.Contentbằng Url.VersionedContent.

Các URL đã tạo trông giống như sau:

<link href="/Content/bootstrap.min.css?v=20151104105858" rel="stylesheet" type="text/css" />
<script src="/Scripts/bootstrap.min.js?v=20151029213517"></script>

Nếu bạn sử dụng lớp mở rộng, bạn có thể muốn thêm xử lý lỗi trong trường hợp MapPathcuộc gọi không hoạt động, vì contentPathkhông phải là tệp vật lý.


0

Tôi sử dụng một cách tương tự để làm giống như bạn đang làm mà không cần sửa đổi từng trang. Đã thêm một sự kiện PreRender là tệp chính. Nó giữ logic của tôi ở một nơi và áp dụng cho cả tệp js và css.

protected void Page_PreRender(object sender, EventArgs e)
    {
        HtmlLink link = null;
        LiteralControl script = null;


        foreach (Control c in Header.Controls)
        {
            //StyleSheet add version
            if (c is HtmlLink)
            {
                link = c as HtmlLink;


                if (link.Href.EndsWith(".css", StringComparison.InvariantCultureIgnoreCase))
                {
                    link.Href += string.Format("?v={0}", ConfigurationManager.AppSettings["agVersion"]);
                }

            }

            //Js add version
            if (c is LiteralControl)
            {
                script = c as LiteralControl;

                if (script.Text.Contains(".js"))
                {
                    var foundIndexes = new List<int>();


                    for (int i = script.Text.IndexOf(".js\""); i > -1; i = script.Text.IndexOf(".js\"", i + 1))
                    {

                        foundIndexes.Add(i);
                    }

                    for (int i = foundIndexes.Count - 1; i >= 0; i--)
                    {

                        script.Text = script.Text.Insert(foundIndexes[i] + 3, string.Format("?v={0}", ConfigurationManager.AppSettings["agVersion"]));
                    }
                }

            }

        }
    }

0

Bạn có thể ghi đè thuộc tính DefaultTagFormat của Tập lệnh hoặc Kiểu.

Scripts.DefaultTagFormat = @"<script src=""{0}?v=" + ConfigurationManager.AppSettings["pubversion"] + @"""></script>";
Styles.DefaultTagFormat = @"<link href=""{0}?v=" + ConfigurationManager.AppSettings["pubversion"] + @""" rel=""stylesheet""/>";

0

Để giải quyết vấn đề này trong ứng dụng ASP.Net Ajax của tôi, tôi đã tạo một tiện ích mở rộng và sau đó được gọi trong trang chính.

Để biết thêm chi tiết, bạn có thể đi qua liên kết .


0

Cách dễ dàng và thông minh để triển khai lập phiên bản css trong ứng dụng .net theo khái niệm dưới đây .. không cần viết mã back-end.

<link href="<%="../../App_Themes/Base/css/main.css?v="+ DateTime.Now.ToString("yyyyMMddhhmmss") +""%>" rel="stylesheet" />

wil này buộc tải xuống trong mỗi lần hiển thị trang, ngay cả khi các tệp không thay đổi gì cả.
Thanasis Ioannidis

@ThanasisIoannidis Nó có thể sử dụng nơi các tệp thường xuyên thay đổi. một tùy chọn khác là thêm khóa appVersion trong web.config và sử dụng với tên tệp .. nhưng bạn cần cập nhật khi phát hành ứng dụng cho sản phẩm.
SantoshK

-1

Vấn đề chính khi làm theo cách này chủ yếu là bạn sẽ cần phải nhớ cập nhật số phiên bản trong mã của mình mỗi khi bạn thực hiện bất kỳ thay đổi nào đối với tệp css hoặc js của mình.

Một cách có thể tốt hơn để làm điều đó là đặt một tham số duy nhất được đảm bảo với mỗi tệp css hoặc js của bạn, như sau:

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

Điều này buộc các tệp phải được yêu cầu từ máy chủ mỗi lần, điều này cũng có nghĩa là trang web của bạn sẽ không hoạt động hiệu quả khi tải trang, vì những tệp đó sẽ không bao giờ được lưu vào bộ nhớ cache và sẽ sử dụng băng thông không cần thiết mỗi lần.

Về cơ bản, nếu bạn có thể nhớ cập nhật số phiên bản mỗi khi thực hiện thay đổi, bạn có thể hoàn thành cách bạn đang thực hiện.


9
và cũng sử dụng nhiều băng thông.
Darren Kopp

2
Đúng vậy, bạn không muốn có phiên bản JS mới ở mỗi lần tải trang ... bạn chỉ muốn trình duyệt tìm kiếm phiên bản mới mỗi khi bạn thực sự có phiên bản cập nhật.
kingdango

Điều này hoàn toàn có thể chấp nhận được đối với giải pháp tạm thời trên tệp css 50KB khi đang phát triển. +1
Colbs

-2

Đối với các trang ASP.NET, tôi đang sử dụng phần sau

TRƯỚC

<script src="/Scripts/pages/common.js" type="text/javascript"></script>

SAU (buộc tải lại)

 <script src="/Scripts/pages/common.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>

Thêm DateTime.Now.Ticks hoạt động rất tốt.


vâng, vấn đề là với băng thông - như trong các nhận xét ở trên stackoverflow.com/a/2185918/59508
kiev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.