2011-01-30 27 views
18

He leído muchos artículos sobre cómo autoverificar tus archivos CSS/JS, pero ninguno de estos proporciona una manera elegante de hacerlo en ASP.NET MVC.Auto-versioning en ASP.NET MVC para archivos CSS/JS?

Este enlace - How to force browser to reload cached CSS/JS files? - proporciona una solución para Apache - pero estoy un poco confundido de cómo esto podría implementarse a través de ASP.NET MVC?

¿Alguien podría dar algunos consejos sobre cómo hacer esto en IIS7 y ASP.NET MVC, para que los archivos CSS/JS tengan automáticamente un número de versión insertado en la URL sin cambiar la ubicación del archivo?

Es decir, así que los enlaces salen a vincular esto, etc. ¿presumiblemente usando la URL Rewrite o?

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

Thx

Respuesta

15

Cuando nos enfrentamos a este problema que escribí una serie de funciones de contenedor alrededor del UrlHelper 's Content método:

EDIT:

Tras las deliberaciones en los comentarios a continuación me actualizado este código:

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

El uso de estas funciones en relación con la norma rewrite siguiente debería funcionar:

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

This article describe cómo crear reglas de reescritura en IIS7.

Este código usa el número de versión del ensamblaje actual como un parámetro de cadena de consulta en la ruta del archivo que emite. Cuando realizo una actualización en el sitio y el número de compilación aumenta, también lo hace el parámetro querystring en el archivo, por lo que el agente de usuario volverá a descargar el archivo.

+0

bueno clonked - Muchas gracias por el código, sin embargo, el problema con el uso del número de versión se detalla en el artículo vinculado anteriormente. Evitará el almacenamiento en caché, ya que las solicitudes con parámetros GET pueden no almacenarse en caché (según la especificación HTTP) e IE es notorio al ignorar el número de versión, así que es por eso que quería incluir el número de versión dentro de la URL/archivo.123. css - ala Reescribir URL – Tom

+0

Mis disculpas, no leí el contenido de su enlace. Sin embargo, estoy contento de haber participado, ya que aprendí que mis métodos eran incorrectos. Veré si puedo revisar mi solución y compartirla. –

+0

He actualizado el código que publiqué para usar la funcionalidad de reescritura de URL de IIS 7. –

0

lo general anexar una cadena de consulta falsa para mis archivos de recursos .. es decir

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

No requiere ningún ayudantes de URL y funciona independientemente de lo que está ejecutando el en segundo plano. Para ser honesto, no he probado este método a conciencia, pero he encontrado que siempre soluciona los problemas de almacenamiento en caché de recursos que la gente estaba experimentando.

Probablemente tengas que actualizar manualmente el v=, pero no sería terriblemente difícil agregar un parámetro de versión a los recursos de un archivo de configuración en alguna parte.

Editar:

Volví y a fondo leído a través del contenido del enlace anterior y darse cuenta de lo que has ya ha sido desechado este método. Disculpas por sugerirlo de nuevo.

+0

Esto evitó el almacenamiento en caché por completo cuando lo probé en Firefox y Chrome. – Sam

0

supongo siguiente solución con opciones avanzadas (modo de depuración/liberación, las versiones):

archivos JS o CSS incluidos por ejemplo manera:

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

Global.JsPostfix y Global.CssPostfix se calcula de la siguiente manera en 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

No creo que pueda agregar el tipo de código de servidor <% = Global.JsPostfix%> en la etiqueta head con la propiedad runat = "server". –

0

ACTUALIZACIÓN: La versión anterior no funcionaba en Azure, he simplificado y corregido a continuación. (Tenga en cuenta, para que esto funcione en el modo de desarrollo con IIS Express, tendrá que instalar de reescritura de URL 2.0 de Microsoft http://www.iis.net/downloads/microsoft/url-rewrite - que utiliza el instalador WebPI, asegúrese de cerrar Visual Studio por primera vez)

ACTUALIZACIÓN: regla fija para archivos .min

Recientemente, pasé un día totalmente infructuoso tratando de obtener la agrupación automática (para admitir la autoversión) en C#/Net 4.6/MVC 5/Razor para trabajar. Leí muchos artículos en StackOverflow y en otros lugares, pero no pude encontrar un recorrido de principio a fin sobre cómo configurarlo. Tampoco me importa cómo se editan los archivos (agregando una cadena de consulta con la versión a la solicitud de archivo estático, es decir, somefile.js? V = 1234) porque algunos me han dicho que ciertos servidores proxy ignoran la consulta cadenas cuando almacena en caché recursos estáticos.

Así que después de un corto viaje por el agujero del conejo, he rodado mi propia versión para auto-versionar e incluí instrucciones completas sobre cómo hacer que funcione a continuación.

discusión completa @: 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

EL PROBLEMA: Por lo general, tiene 2 tipos de archivos javascript/css en un proyecto.

1) Librerías de 3 partes (como jquery o bigote) que muy raramente cambian (y cuando lo hacen, la versión en el archivo generalmente cambia) - estas pueden agruparse/minificarse según sea necesario usando WebGrease o JSCompress.com (solo incluya el archivo/versión incluido en su _Layout.cshtml)

2) archivos css/js específicos de la página que deben actualizarse cada vez que se empuja una nueva compilación. (Sin tener el usuario caché emabrgo nítidas o actualiza varios)

Mi Solución: Auto-incremento de la versión de montaje cada vez que se genere el proyecto, y usar ese número para un archivo estático enrutado de los recursos específicos te gustaría mantenerte renovado. (Así que something.js se incluye como algo.v1234.js con 1234 cambiando automáticamente cada vez que se construye el proyecto) - También agregué algunas funcionalidades adicionales para asegurar que los archivos .min.js se usen en producción y se usen archivos regulares.js al depurar (estoy usando WebGrease para automatizar el proceso de minify) Una cosa buena de esta solución es que funciona tanto en modo local/dev como en producción.

Cómo hacerlo: Auto-incremento de la versión de montaje cada vez que se genere el proyecto, y utilizar ese número para un archivo estático enrutado de los recursos específicos que le gustaría mantener fresco. (Así que something.js se incluye como algo.v1234.js con 1234 cambiando automáticamente cada vez que se construye el proyecto) - También agregué algunas funcionalidades adicionales para asegurar que los archivos .min.js se usen en producción y se usen archivos regulares.js al depurar (estoy usando WebGrease para automatizar el proceso de minify) Una cosa buena de esta solución es que funciona tanto en modo local/dev como en producción. (Estoy usando Visual Studio 2015/Net 4.6, pero creo que esto va a funcionar en las versiones anteriores, así

. Paso 1: Habilitar incremento automático en el conjunto cuando se construyó En el AssemblyInfo.cs archivo (que se encuentra en la sección "propiedades" de su proyecto de cambiar las siguientes líneas:

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

a

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

Paso 2: Configure reescritura de URL en web.config para los archivos con incrustado babosas versión (ver paso 3)

en web.config (el principal para el proyecto) añadir las reglas siguientes aparatos en el 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> 

Paso 3: Configuración de variables de aplicación para leer su versión actual de ensamblaje y crear slugs de versión en sus archivos js y css.

en Global.asax.cs (que se encuentra en la raíz del proyecto) añadir el siguiente código a Application_Start protegida vacío() (después de las líneas de Registro)

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

Paso 4: Cambiar enlaces src en la maquinilla de afeitar considera que el uso de las variables de la aplicación que creó en Global.asax.cs

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

por ejemplo, en mi _Layout.cshtml, en mi sección de la cabeza, tengo el siguiente bloque de código de hojas de estilo:

<!-- 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 par de cosas de aviso aquí: 1) no hay ninguna extensión en el archivo. 2) tampoco hay .min. Ambos son manejados por el código en Global.asax.cs

Del mismo modo, (también en _Layout.cs) en mi sección javascript: Tengo el siguiente código:

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

El primer archivo es una paquete de todas las bibliotecas de terceros que he creado manualmente con WebGrease. Si agrego o cambio alguno de los archivos en el paquete (lo que es raro), renombro manualmente el archivo a all3bnd101.min.js, all3bnd102.min.js, etc ... Este archivo no coincide con el controlador de reescritura, por lo que permanecerá almacenado en caché en el navegador del cliente hasta que vuelva a agrupar/cambiar el nombre manualmente.

El segundo archivo es ui.js (que se escribirá como ui.v12345123.js o ui.v12345123.min.js dependiendo de si se está ejecutando en modo de depuración o no) Esto se manejará/reescribirá. (Se puede establecer un punto de interrupción en Application_OnBeginRequest de Global.asax.cs para ver que funcione)

discusión completa sobre este tema en: 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(Incluyendo una manera de hacerlo sin reescritura de URL)