Erzwingen Sie, dass Browser die neuesten JS- und CSS-Dateien in der asp.net-Anwendung abrufen

104

Einige Browser speichern JS- und CSS-Dateien im Cache und können sie nur aktualisieren, wenn Sie sie dazu zwingen. Was ist der einfachste Weg.

Ich habe gerade diese Lösung implementiert, die zu funktionieren scheint.

Deklarieren Sie eine Versionsvariable auf Ihrer Seite

  public string version { get; set; }

Rufen Sie die Versionsnummer vom Schlüssel web.config ab

 version = ConfigurationManager.AppSettings["versionNumber"];

Rufen Sie auf Ihrer Aspx-Seite Javascript und Stylesheets wie folgt auf

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

Wenn Sie also in Ihrer web.config die Version 1.1 von 1.0 festlegen, lädt Ihr Browser die neuesten Dateien herunter, was Ihnen und Ihren Benutzern hoffentlich einige Frustrationen erspart.

Gibt es eine andere Lösung, die besser funktioniert, oder verursacht dies unvorhergesehene Probleme für eine Website?

Kiew
quelle
Interessante Frage, ich hatte kürzlich das gleiche Problem, war aber nur ein Problem während der Entwicklungstests. Es war mir egal, da wir nicht beabsichtigen, diese Datei nach dem Start zu ändern. Würde gerne eine Lösung für zukünftige Referenz wissen!
Brett Allen
Das einzige Problem, das ich sehen kann, ist, dass Änderungen an der web.config im Hintergrund einen Neustart der Anwendung aufrufen: msdn.microsoft.com/en-us/library/aa478432.aspx
Montag,
Danke für die Frage. Dies half mir bei der Lösung eines großen Problems.
Reddy

Antworten:

76

Ich habe dieses Problem gelöst, indem ich einen letzten geänderten Zeitstempel als Abfrageparameter an die Skripte angehängt habe.

Ich habe dies mit einer Erweiterungsmethode gemacht und in meinen CSHTML-Dateien verwendet. Hinweis: Diese Implementierung speichert den Zeitstempel 1 Minute lang im Cache, damit die Festplatte nicht so stark überlastet wird.

Hier ist die Erweiterungsmethode:

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

Und dann auf der CSHTML-Seite:

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

Im gerenderten HTML sieht dies folgendermaßen aus:

 <script type='text/javascript' src='/MyJavascriptFile.js?20111129120000'></script>
Adam Tegen
quelle
1
Das ist großartig für MVC. Ich frage mich, ob das neueste MVC 5-Framework dieses Problem löst. Der Ansatz, den die Bündelung mit - {version} Wildcard verwendet, ist auch eine Möglichkeit, dieses Problem zu lösen. Allerdings müssen die Dateien nach jedem neuen Build umbenannt werden ...
Kiew
Ich verwende die Grundlagen Ihres MVC-Beispiels in einer Webforms-Website und es funktioniert hervorragend. Vielen Dank für das Teilen!
Bryan
Sollte es Grund zur Sorge geben, den zuletzt geänderten Datums- / Zeitstempel für Ressourcendateien anzuzeigen? Wenn eine verwendete Datei vor einigen Jahren einen Datums- / Zeitstempel hatte, könnte dies eine Information sein, die ein Unternehmen möglicherweise nicht für seine Benutzer öffentlich machen möchte?
Bryan
Es ist der Standardweg, meistens folgen Anwendungen. Dieser Zeitstempel sollte sich jedoch nur ändern, wenn Sie Ihre Anwendung bereitstellen oder erstellen. Andernfalls wird die Seite jedes Mal aktualisiert oder zu anderen Seiten in Ihrer Anwendung gewechselt. Der Browser lädt alle Stylesheets und Javascript erneut herunter, was nicht gut ist
Tarun
2
Welche Auswirkungen hat dies auf die Leistung der Seite? Wie viel Verzögerung kann das Laden der Seite verursachen?
Durgesh Sonawane
28

Ihre Lösung funktioniert. Es ist in der Tat sehr beliebt.

Sogar der Stapelüberlauf verwendet eine ähnliche Methode:

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

Wo v=6184ist wahrscheinlich die SVN-Revisionsnummer.

Daniel Vassallo
quelle
Dies wäre ein viel anstrengenderer Ansatz als der in der akzeptierten Antwort beschriebene. Das Überprüfen der SVN-Version der Datei bei jeder Bereitstellung einer Seite ist ein Leistungsaufwand, insbesondere wenn die Anzahl der Benutzer im Laufe der Zeit zunimmt.
Neolisk
4
Sie können die Revisionsnummer während des Builds abrufen, in eine Datei (z. B. eine teilweise CS-Datei) schreiben und diese Datei in Ihr Projekt aufnehmen, damit Sie sie zur Laufzeit nicht von svn lesen müssen. Ich habe diesen Ansatz mit msbuild verwendet, um Revisionsnummern in meine AssemblyInfo.cs-Dateien von svn einzufügen.
Ramazan Binarbasi
2
Die Verwendung einer globalen Versions- / Versionsnummer hat mindestens einen Nachteil: Durch das Veröffentlichen eines Website-Updates werden die Browser-Caches für alle .js- und .css-Dateien ungültig, nicht nur für die geänderten. Dies spielt wahrscheinlich bei den meisten Anträgen keine Rolle, aber ich erwähne es der Vollständigkeit halber.
Adam Tegen
Wenn Sie die Version Ihrer Assemblyinfo.cs-Dateien während einer Bereitstellung oder Erstellung automatisch aktualisieren, kann die Nebenversion für diese Nummer verwendet werden.
Kristianp
27

In ASP.NET Core (MVC 6) funktioniert dies sofort über den asp-append-versionTag-Helfer:

<script src="scripts/myjavascript.js" asp-append-version="true"></script>
<link href="styles/mystyle.css rel="stylesheet" asp-append-version="true" />
Metallherz
quelle
1
Vielen Dank, dass Sie uns informiert haben! Ich wusste es vorher nicht!
Federico Navarrete
18

ASP.NET MVC übernimmt dies für Sie, wenn Sie Bundles für Ihr JS / CSS verwenden. Es wird automatisch eine Versionsnummer in Form einer GUID an Ihre Bundles angehängt und diese GUID nur aktualisiert, wenn das Bundle aktualisiert wird (auch bekannt als Änderungen an den Quelldateien).

Dies ist auch hilfreich, wenn Sie eine Menge JS / CSS-Dateien haben, da dies die Ladezeiten von Inhalten erheblich verbessern kann!

Siehe hier

jonesy827
quelle
Meinen Sie damit, dass bei Verwendung von Bundles in einer MVC-Anwendung keine der Methoden in der hier veröffentlichten Antwort erforderlich ist? Wenn ja, ist das Bündeln wirklich viel wichtiger, als ich jemals gedacht habe. Könnten Sie uns bitte dieses Problem erläutern? Vielen Dank.
Jack
1
Ja genau. Solange Ihre Skripte in einem Bundle enthalten sind, wird automatisch eine Versionsnummer für jedes Bundle generiert, wenn Änderungen in einer der Quelldateien des Bundles festgestellt werden.
jonesy827
Und vergessen Sie nicht, dass Sie als Entwickler immer noch Kopfschmerzen haben. Die ASP.NET-Bündelung hilft ohnehin beim Debuggen und Entwickeln.
it3xl
12

Dafür gibt es in asp.net eine integrierte Möglichkeit: Bündelung . Benutze es einfach. Jede neue Version hat das eindeutige Suffix "? V = XXXXXXX". Im Debug-Modus ist die Bündelung deaktiviert, um die Einstellung make in web.config einzuschalten:

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

Oder fügen Sie der Methode RegisterBundles (BundleCollection-Bundles) Folgendes hinzu:

BundleTable.EnableOptimizations = true;

Beispielsweise:

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")
Alex Tkachuk
quelle
Dies funktioniert jedoch nur in Release- oder Produktionsumgebungen. Was ist mit der Entwicklung, wenn der Debug-Modus aktiviert ist? Behebt Bundle dieses Problem immer noch?
VAAA
Ja, Bundlind macht Entwicklern das Leben nicht einfacher. Sie müssen nach jeder Skriptänderung Strg-F5 drücken. Und wenn Sie Frames haben, wird es noch lustiger.
it3xl
6

Es gibt eine einfachere Antwort darauf als die Antwort der Operation in der Frage (der Ansatz ist der gleiche):

Definieren Sie den Schlüssel in der web.config:

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

Rufen Sie Appsettings direkt von der aspx-Seite aus auf:

<link href="styles/navigation.css?v=<%=ConfigurationManager.AppSettings["VersionNumber"]%>" rel="stylesheet" type="text/css" />
JackArbiter
quelle
Ich mag das, bin aber besorgt, warum diese Lösung so wenig Stimmen hat ...
SimplyInk
@SimplyInk Ich weiß es nicht, aber es gibt 20 verschiedene Antworten, also könnte das etwas damit zu tun haben. Wenn es funktioniert und es Ihnen gefällt, können Sie es gerne positiv bewerten.
JackArbiter
4

Basierend auf der Antwort von Adam Tegan , geändert für die Verwendung in einer Webformularanwendung.

Im CS-Klassencode:

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

Im Aspx-Markup:

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

Und im gerenderten HTML erscheint es als

<script type="text/javascript" src='/js/exampleJavaScriptFile.js?v=20150402021544'></script>
Bryan
quelle
2
Hallo! Ihr Beispiel funktioniert, aber Sie sollten entweder die Caching-Referenzen entfernen oder den Code für die Verwendung des Caches korrigieren, da dies verwirrend sein kann, warum Sie ihn verwenden. Um den Cache zu verwenden, sollten Sie die Version der Datei mithilfe der Methode context.Cache.Add im Fall context.Cache [Dateiname] == null zum Cache hinzufügen. Wenn der context.Cache [Dateiname]! = Null ist, sollten Sie den zwischengespeicherten Wert (context.Cache [Dateiname]) zurückgeben
Flavia Obreja
1
Flavia, ich denke, Ihre Erklärung ist sinnvoll, und ich denke, es ist eine einfachere und effizientere Implementierung. Vielen Dank für die hilfreichen Kommentare und Rückmeldungen.
Bryan
4

Interessanterweise weist genau diese Site Probleme mit dem Ansatz auf, den Sie im Zusammenhang mit einigen Proxy-Setups beschreiben, obwohl er ausfallsicher sein sollte.

Überprüfen Sie diese Meta Stack Overflow- Diskussion.

Vor diesem Hintergrund ist es möglicherweise sinnvoll, keinen GET-Parameter zum Aktualisieren zu verwenden, sondern den tatsächlichen Dateinamen:

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

Auch wenn dies mehr Arbeit ist, müssen Sie die Datei tatsächlich erstellen oder eine URL neu schreiben.

Pekka 웃
quelle
4

Ich wollte einen einfachen Einzeiler, um den Pfad einzigartig zu machen und den Cache zu sprengen. Das hat bei mir funktioniert:

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

Wenn die Datei seit dem letzten Laden auf der Seite geändert wurde, ruft der Browser die aktualisierte Datei ab.

Es generiert den last modifiedStempel aus der .jsDatei und legt ihn dort anstelle der Version ein, auf die möglicherweise nicht einfach zugegriffen werden kann.

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

Eine andere Möglichkeit könnte darin bestehen, die Prüfsumme der Datei abzurufen.

Sniperd
quelle
1
Bei weitem der einfachste Weg, dies zu tun, und wahrscheinlich der niedrigste Overhead.
Tony Hinkle
1
Perfekte Lösung. Ich habe auch Chrome 70, Firefox 63 und IE 11 getestet, um sicherzustellen, dass das Caching tatsächlich funktioniert. Es ist. Dadurch wird das Caching nur bei neuen Versionen der Datei unterbrochen, zumindest bei den neuesten Versionen der Browser. Ich habe an anderer Stelle erwähnt, dass einige Browser jede Datei mit einem Querystring (?) Neu laden. Vielleicht war das früher der Fall oder vielleicht gilt es immer noch für Safari und Opera. DK.
Brad Mathews
3

Hier ist ein Ansatz, der mit ASP.NET 5 / MVC 6 / vNext funktioniert .

Schritt 1: Erstellen Sie eine Klasse, um die letzte Schreibzeit der Datei zurückzugeben, ähnlich wie bei anderen Antworten in diesem Thread. Beachten Sie, dass hierfür die Abhängigkeitsinjektion von ASP.NET 5 (oder einer anderen) erforderlich ist.

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

Schritt 2: Registrieren Sie den Dienst, der in startup.cs injiziert werden soll :

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

Schritt 3: In ASP.NET 5 ist es dann möglich, den Dienst direkt in eine Layoutansicht wie _Layout.cshtml wie folgt einzufügen :

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

Es gibt einige Feinarbeiten, die durchgeführt werden könnten, um physische Pfade besser zu kombinieren und den Dateinamen in einem Stil zu behandeln, der der Syntax besser entspricht. Dies ist jedoch ein Ausgangspunkt. Ich hoffe, es hilft Menschen, auf ASP.NET 5 umzusteigen.

Ender2050
quelle
Dieses Verhalten wird tatsächlich
sofort
3

Ich habe auf meiner Aspnet MVC 4-Site eine etwas andere Technik angewendet:

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

Dann in den aktuellen Ansichten:

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

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

Dies funktioniert bei mir in allen Browsern. Hier habe ich PHP verwendet, um zufällige Nr. Zu generieren. Sie können Ihre eigene serverseitige Sprache verwenden. "

Mukesh Rai
quelle
Gute Antwort, aber ASP MVC kann ein bisschen problematisch sein, wenn Sie nicht überlegen, was Adam erklärt hat, weil ich es versucht habe und der Bundle-Ordner es nicht erkennt, wenn Sie mit MVC 5 arbeiten. Aber danke für den Vorschlag!
Federico Navarrete
2

Ausgehend von der obigen Antwort habe ich den Code ein wenig geändert, damit der Helfer auch mit CSS-Dateien funktioniert, und jedes Mal eine Version hinzugefügt, wenn Sie Änderungen an den Dateien vornehmen und nicht nur, wenn Sie den Build ausführen

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;
        }
    }
}
Sergi Mulà
quelle
1

Holen Sie sich die Änderungszeit der Datei, wie unten gezeigt

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

Fügen Sie dies mit der Eingabe als Querystring hinzu

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

Nennen Sie dies vom Markup.

MVC Extension Helper Approach

Fügen Sie eine Erweiterungsmethode hinzu

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

    }
}

Fügen Sie diesen Namespace in web.config hinzu

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

Verwenden Sie es in Ansicht als

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

Vereinfachte vorherige Vorschläge und Bereitstellung von Code für .NET Web Forms-Entwickler.

Dies akzeptiert sowohl relative ("~ /") als auch absolute URLs im Dateipfad zur Ressource.

Fügen Sie eine statische Erweiterungsklassendatei wie folgt ein:

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

Und nennen Sie es dann auf Ihrer Masterseite als solche:

<link type="text/css" rel="stylesheet" href="<%= Context.VersionedContent("~/styles/mystyle.css") %>" />
<script type="text/javascript" src="<%= Context.VersionedContent("~/scripts/myjavascript.js") %>"></script>
Jason Ellingson
quelle
Netter Ansatz auch!
Federico Navarrete
0

Basierend auf der obigen Antwort habe ich eine kleine Erweiterungsklasse geschrieben, um mit CSS- und JS-Dateien zu arbeiten:

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

Anstatt etwas zu schreiben wie:

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

Sie können jetzt schreiben:

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

Dh einfach ersetzen Url.Contentmit Url.VersionedContent.

Generierte URLs sehen ungefähr so ​​aus:

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

Wenn Sie die Erweiterungsklasse verwenden, möchten Sie möglicherweise eine Fehlerbehandlung hinzufügen, falls der MapPathAufruf nicht funktioniert, da contentPathes sich nicht um eine physische Datei handelt.

Uwe Keim
quelle
0

Ich verwende eine ähnliche Methode, um dasselbe zu tun, ohne jede Seite zu ändern. Ein PreRender-Ereignis wurde als Master-Datei hinzugefügt. Es hält meine Logik an einem Ort und gilt sowohl für JS- als auch für CSS-Dateien.

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"]));
                    }
                }

            }

        }
    }
Jay
quelle
0

Sie können die DefaultTagFormat-Eigenschaft von Skripten oder Stilen überschreiben.

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

Um dieses Problem in meiner ASP.Net Ajax-Anwendung zu beheben, habe ich eine Erweiterung erstellt und dann die Masterseite aufgerufen.

Für weitere Details können Sie über den Link gehen .

Kasim Husaini
quelle
0

Einfache und intelligente Möglichkeit, die CSS-Versionierung in der .net-Anwendung mithilfe des folgenden Konzepts zu implementieren. Sie müssen keinen Back-End-Code schreiben.

<link href="<%="../../App_Themes/Base/css/main.css?v="+ DateTime.Now.ToString("yyyyMMddhhmmss") +""%>" rel="stylesheet" />
SantoshK
quelle
Dadurch wird das Herunterladen bei jedem Rendern der Seite erzwungen, auch wenn sich die Dateien überhaupt nicht geändert haben.
Thanasis Ioannidis
@ThanasisIoannidis Kann verwendet werden, wenn Dateien regelmäßig geändert werden. Eine weitere Option ist das Hinzufügen des AppVersion-Schlüssels in web.config und die Verwendung mit dem Dateinamen. Sie müssen jedoch aktualisieren, wenn Sie die Anwendung für prod freigeben.
SantoshK
-1

Das Hauptproblem dabei ist hauptsächlich, dass Sie daran denken müssen, Ihre Versionsnummer in Ihrem Code jedes Mal zu aktualisieren, wenn Sie Änderungen an Ihren CSS- oder JS-Dateien vornehmen.

Ein möglicherweise besserer Weg, dies zu tun, besteht darin, für jede Ihrer CSS- oder JS-Dateien einen garantierten eindeutigen Parameter festzulegen, wie folgt:

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

Dadurch werden die Dateien jedes Mal vom Server angefordert. Dies bedeutet auch, dass Ihre Site beim Laden der Seite nicht so leistungsfähig ist, da diese Dateien niemals zwischengespeichert werden und jedes Mal nicht benötigte Bandbreite verwenden.

Wenn Sie daran denken können, die Versionsnummer jedes Mal zu aktualisieren, wenn eine Änderung vorgenommen wird, können Sie im Wesentlichen davon profitieren, wie Sie dies tun.

Tim S. Van Haren
quelle
9
und verwendet auch reichlich Bandbreite.
Darren Kopp
2
Richtig, Sie möchten nicht bei jedem Laden einer Seite eine neue Version des JS. Sie möchten lediglich, dass der Browser jedes Mal nach einer neuen Version sucht, wenn Sie tatsächlich eine aktualisierte Version haben.
Kingdango
Dies ist für eine temporäre Lösung in einer 50-KB-CSS-Datei während der Entwicklung durchaus akzeptabel. +1
Colbs
-2

Für ASP.NET-Seiten verwende ich Folgendes

VOR

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

AFTER (Nachladen erzwingen)

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

Das Hinzufügen von DateTime.Now.Ticks funktioniert sehr gut.

Ravi Ram
quelle
Ja, das Problem ist mit der Bandbreite - wie in den Kommentaren oben stackoverflow.com/a/2185918/59508
Kiew