2011-01-30 19 views
18

Ho letto un sacco di articoli su come eseguire la versione automatica dei file CSS/JS, ma nessuno di questi fornisce un modo elegante per farlo in ASP.NET MVC.Auto-versioning in ASP.NET MVC per file CSS/JS?

Questo collegamento - How to force browser to reload cached CSS/JS files? - fornisce una soluzione per Apache - ma sono un po 'confuso su come questo possa essere implementato tramite ASP.NET MVC?

Qualcuno potrebbe essere in grado di fornire alcuni consigli su come farlo su IIS7 e ASP.NET MVC - in modo che i file CSS/JS abbiano automaticamente inserito un numero di versione nell'URL senza modificare la posizione del file?

Cioè, così i collegamenti vengono fuori collegano questo ecc. Presumibilmente usando l'URL Riscrivere o?

<link rel="stylesheet" href="/css/structure.1194900443.css" type="text/css" /> 
<script type="text/javascript" src="/scripts/prototype.1197993206.js"></script> 

Thx

risposta

15

di fronte a questo problema ho scritto una serie di funzioni wrapper intorno Content metodo s' il UrlHelper:

EDIT:

seguito alle discussioni nei commenti qui sotto ho aggiornato questo codice:

public static class UrlHelperExtensions 
{ 
    private readonly static string _version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); 

    private static string GetAssetsRoot() 
    { 
     string root = ConfigurationManager.AppSettings["AssetsRoot"]; 
     return root.IsNullOrEmpty() ? "~" : root; 
    } 

    public static string Image(this UrlHelper helper, string fileName) 
    { 
     return helper.Content(string.Format("{0}/v{2}/assets/img/{1}", GetAssetsRoot(), fileName, _version)); 
    } 

    public static string Asset(this UrlHelper helper, string fileName) 
    { 
     return helper.Content(string.Format("{0}/v{2}/assets/{1}", GetAssetsRoot(), fileName, _version)); 
    } 

    public static string Stylesheet(this UrlHelper helper, string fileName) 
    { 
     return helper.Content(string.Format("{0}/v{2}/assets/css/{1}", GetAssetsRoot(), fileName, _version)); 
    } 

    public static string Script(this UrlHelper helper, string fileName) 
    { 
     return helper.Content(string.Format("{0}/v{2}/assets/js/{1}", GetAssetsRoot(), fileName, _version)); 
    } 
} 

Utilizzando queste funzioni in collaborazione con la rewrite regola seguente dovrebbe funzionare:

<rewrite> 
    <rules> 
    <rule name="Rewrite assets"> 
     <match url="^v(.*?)/assets/(.*?)" /> 
     <action type="Rewrite" url="/assets/{R:2}" /> 
    </rule> 
    </rules> 
</rewrite> 

This article discute come creare regole di riscrittura in IIS7.

Questo codice utilizza il numero di versione dell'assieme corrente come parametro della stringa di query sul percorso del file emesso. Quando eseguo un aggiornamento al sito e gli incrementi del numero di build, lo stesso vale per il parametro querystring sul file, quindi l'interprete riscriverà nuovamente il file.

+0

hey clonked - Grazie mille per il codice, tuttavia il problema con l'utilizzo del numero di versione è dettagliato nell'articolo collegato sopra. Impedirà la memorizzazione nella cache, poiché le richieste con i parametri GET potrebbero non essere memorizzate nella cache (secondo le specifiche HTTP) e IE è noto per aver ignorato il numero di versione - ecco perché volevo un modo per includere il numero di versione all'interno dell'URL/file.123. css - ala URL Riscrivi – Tom

+0

Le mie scuse, non ho letto il contenuto del tuo link. Sono contento anche se ho partecipato, perché ho imparato che i miei metodi non erano corretti! Vedrò se riesco a rivedere la mia soluzione e condividerla. –

+0

Ho aggiornato il codice che ho postato per utilizzare la funzionalità di riscrittura degli URL di IIS 7. –

0

Io di solito aggiungere una stringa di query falso per i miei file di risorse .. cioè

<link rel="stylesheet" href="/css/structure.css?v=1194900443" type="text/css" /> 
<script type="text/javascript" src="/scripts/prototype.js?v=1197993206"></script> 

Non richiede alcun aiutanti URL e lavora non importa ciò che è in esecuzione in background la. Ad essere onesti, non ho mai testato questo metodo, ma ho trovato che risolve sempre eventuali problemi di memorizzazione nella cache delle risorse che le persone stavano vivendo.

Probabilmente dovresti aggiornare manualmente lo v=, ma non sarebbe terribilmente difficile aggiungere un parametro di versione alle risorse da un file di configurazione da qualche parte.

Edit:

sono tornato e accuratamente letto attraverso il contenuto del link qui sopra e mi rendo conto che probabilmente avete già scartato questo metodo. Mi scuso per averlo suggerito di nuovo.

+0

Questo ha impedito il caching del tutto quando l'ho provato in Firefox e Chrome. – Sam

0

suppongo prossima soluzione con opzioni avanzate (modalità di debug/release, le versioni):

file JS o CSS inclusi da modo:

<script type="text/javascript" src="Scripts/exampleScript<%=Global.JsPostfix%>" /> 
<link rel="stylesheet" type="text/css" href="Css/exampleCss<%=Global.CssPostfix%>" /> 

Global.JsPostfix e Global.CssPostfix è calcolato il seguente modo in Global.ASax:

protected void Application_Start(object sender, EventArgs e) 
{ 
    ... 
    string jsVersion = ConfigurationManager.AppSettings["JsVersion"]; 
    bool updateEveryAppStart = Convert.ToBoolean(ConfigurationManager.AppSettings["UpdateJsEveryAppStart"]); 
    int buildNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Revision; 
    JsPostfix = ""; 
#if !DEBUG 
    JsPostfix += ".min"; 
#endif  
    JsPostfix += ".js?" + jsVersion + "_" + buildNumber; 
    if (updateEveryAppStart) 
    { 
     Random rand = new Random(); 
     JsPosfix += "_" + rand.Next(); 
    } 
    ... 
} 
+0

Non credo che sia possibile aggiungere <% = Global.JsPostfix%> tipo di codice server nel tag head con la proprietà runat = "server". –

0

UPDATE: La versione precedente non ha funzionato su Azure, ho semplificato e corretto sotto. (Si noti, per questo di lavorare in modalità di sviluppo con IIS Express, è necessario installare URL Rewrite 2.0 da Microsoft http://www.iis.net/downloads/microsoft/url-rewrite - utilizza il programma di installazione WebPi, assicurarsi di chiudere Visual Studio prima)

UPDATE: regola fissa per file .min

Recentemente ho passato una giornata completamente infruttuosa cercando di ottenere il bundling automatico (per supportare la versione automatica) in C#/Net 4.6/MVC 5/Razor per funzionare. Ho letto molti articoli sia su StackOverflow che altrove, ma non sono riuscito a trovare una spiegazione end-to-end su come configurarla. Inoltre non mi interessa il modo in cui i file sono version-ed (aggiungendo una stringa di query con la versione alla richiesta di file statici - ad esempio somefile.js? V = 1234) perché alcuni mi hanno detto che alcuni server proxy ignorano la query stringhe quando si memorizzano nella cache le risorse statiche.

Quindi, dopo un breve viaggio nella tana del coniglio, ho eseguito il rollback della mia versione per l'auto-versioning e ho incluso istruzioni complete su come farlo funzionare di seguito.

completa discussione @: 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

IL PROBLEMA: Hai in generale 2 tipi di file JavaScript/CSS in un progetto.

1) 3 librerie di parti (come jquery o baffi) che cambiano molto raramente (e quando lo fanno, la versione sul file generalmente cambia) - queste possono essere raggruppate/minificate su una base "necessaria" usando WebGrease o JSCompress.com (includere solo il file in bundle/versione in _Layout.cshtml)

2) file css/js specifici della pagina che devono essere aggiornati ogni volta che viene spinto un nuovo build. (Senza avere la cache burbero chiara utente o fare rinfresca multipli)

mia soluzione: incremento automatico della versione di assembly ogni volta che il progetto è costruito, e l'uso che il numero di file statico instradato sulle risorse specifiche ti piacerebbe rimanere aggiornato. (quindi qualcosa.js è incluso come qualcosa.v1234.js con 1234 che cambia automaticamente ogni volta che il progetto viene creato) - Ho anche aggiunto alcune funzionalità aggiuntive per garantire che i file .min.js vengano utilizzati in produzione e che vengano utilizzati i file regular.js durante il debug (sto usando WebGrease per automatizzare il processo di minimizzazione) Una cosa bella di questa soluzione è che funziona in modalità locale/dev e anche in produzione.

Come fare: incremento automatico della versione di assembly ogni volta che il progetto è costruito, e l'uso che il numero di file statico instradato sulle risorse specifiche che si desidera mantenere aggiornato. (quindi qualcosa.js è incluso come qualcosa.v1234.js con 1234 che cambia automaticamente ogni volta che il progetto viene creato) - Ho anche aggiunto alcune funzionalità aggiuntive per garantire che i file .min.js vengano utilizzati in produzione e che vengano utilizzati i file regular.js durante il debug (sto usando WebGrease per automatizzare il processo di minimizzazione) Una cosa bella di questa soluzione è che funziona in modalità locale/dev e anche in produzione. (Sto usando Visual Studio 2015/Net 4.6, ma credo che questo sarà il lavoro nelle versioni precedenti, nonché

Fase 1:. attivare Auto-incremento sul gruppo quando costruito Nel AssemblyInfo.File cs (che si trova nella sezione "proprietà" del progetto modificare le seguenti righe:

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

a

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

Fase 2: Impostare URL Rewrite in web.config per i file con incorporato lumache di versione (vedi punto 3)

nel web.config (quello principale per il progetto) aggiungere le regole follwing nel system.webServer.

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

Passaggio 3: Imposta le variabili dell'applicazione per leggere la versione corrente dell'assieme e creare slug di versione nei file js e css.

a Global.asax.cs (che si trova nella directory principale del progetto) aggiungere il seguente codice di protezione Application_Start void() (dopo le righe Registra)

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

Fase 4: Modifica link src in Razor viste utilizzando le variabili dell'applicazione che abbiamo allestito in Global.asax.cs

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

per esempio, nel mio _Layout.cshtml, nella mia sezione testa, ho il seguente blocco di codice per i fogli di stile:

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

un paio di cose da notare: 1) non v'è alcuna estensione sul file. 2) non esiste neanche .min. Entrambi sono gestiti dal codice Global.asax.cs

Allo stesso modo, (anche in _Layout.cs) nel mio javascript sezione: Ho il seguente codice:

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

Il primo file è un pacchetto di tutte le mie librerie di terze parti che ho creato manualmente con WebGrease. Se aggiungo o modifico uno qualsiasi dei file nel pacchetto (che è raro), rinominare manualmente il file in all3bnd101.min.js, all3bnd102.min.js, ecc ... Questo file non corrisponde al gestore di riscrittura, quindi rimarrà memorizzato nella cache sul browser del client fino a quando non si riordina/modifica manualmente il nome.

Il secondo file è ui.js (che verrà scritto come ui.v12345123.js o ui.v12345123.min.js a seconda se si sta eseguendo in modalità di debug o meno) Questo verrà gestito/riscritto. (È possibile impostare un punto di interruzione in Application_OnBeginRequest di Global.asax.cs per guardare il lavoro)

discussione completa su questo a: 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(Compreso un modo per farlo senza URL Rewrite)