kendo - ¿Versiones automáticas en ASP.NET MVC para archivos CSS/JS?
kendo mvc documentation (4)
Cuando me enfrenté a este problema, escribí una serie de funciones de envoltorio alrededor del método de Content
UrlHelper
:
EDITAR:
Siguiendo las discusiones en los comentarios a continuación actualicé 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 junto con la siguiente regla de rewrite
debería funcionar:
<rewrite>
<rules>
<rule name="Rewrite assets">
<match url="^v(.*?)/assets/(.*?)" />
<action type="Rewrite" url="/assets/{R:2}" />
</rule>
</rules>
</rewrite>
Este artículo explica cómo crear reglas de reescritura en IIS7.
Este código utiliza 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 hago una actualización al sitio y los incrementos del número de compilación, también lo hace el parámetro de cadena de consulta en el archivo, y así el agente de usuario vuelve a descargar el archivo.
He leído muchos artículos sobre cómo auto-versionar tus archivos CSS / JS, pero ninguno de estos proporciona una forma elegante de hacerlo en ASP.NET MVC.
Este enlace: ¿Cómo forzar al navegador a volver a cargar archivos CSS / JS en caché? - proporciona una solución para Apache, pero estoy un poco confundido sobre cómo podría implementarse esto a través de ASP.NET MVC.
¿Alguien podría proporcionar algún consejo sobre cómo hacer esto en IIS7 y ASP.NET MVC, de modo que los archivos CSS / JS tengan un número de versión insertado automáticamente en la URL sin cambiar la ubicación del archivo?
Es decir, así que los enlaces salen de este etc., presumiblemente, utilizando 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>
Gracias
Normalmente agrego una cadena de consulta falsa a 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 ayudante de URL y funciona sin importar lo que se esté ejecutando en segundo plano. Para ser honesto, no he probado completamente este método, pero he encontrado que siempre soluciona los problemas de almacenamiento en caché de recursos que las personas estaban experimentando.
Probablemente tendría que actualizar v=
manualmente, pero no sería terriblemente difícil agregar un parámetro de versión a los recursos de un archivo de configuración en algún lugar.
Editar:
Regresé y leí detenidamente el contenido del enlace anterior y me di cuenta de que probablemente ya haya descartado este método. Disculpas por sugerirlo de nuevo.
Supongo que la próxima solución con opciones avanzadas (modo debug / release, versiones):
Js o archivos css incluidos por tal forma:
<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 calculan 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();
}
...
}
ACTUALIZACIÓN: La versión anterior no funcionó en Azure, la he simplificado y corregido a continuación. (Tenga en cuenta que para que esto funcione en el modo de desarrollo con IIS Express, deberá instalar URL Rewrite 2.0 de Microsoft http://www.iis.net/downloads/microsoft/url-rewrite - usa el instalador de WebPi, asegúrese de para cerrar Visual Studio primero)
ACTUALIZACIÓN: Regla fija para archivos .min
Recientemente, pasé un día totalmente infructuoso intentando que el empaquetado automático (para admitir la versión automática de versiones) en C # / Net 4.6 / MVC 5 / Razor funcionara. Leí muchos artículos tanto en como en otros sitios, pero no pude encontrar un resumen completo de cómo configurarlo. Tampoco me importa la forma en que los archivos se editan en la versión (agregando una cadena de consulta con la versión a la solicitud de archivo estático, es decir, somefile.js? V = 1234) porque algunos servidores proxy me han dicho que algunos servidores proxy ignoran la consulta cadenas al almacenar en caché los recursos estáticos.
Así que, después de un breve viaje por el agujero del conejo, he creado mi propia versión para la versión automática e incluí instrucciones completas sobre cómo hacer que funcione a continuación.
EL PROBLEMA: En general, tiene 2 tipos de archivos javascript / css en un proyecto.
1) 3 bibliotecas de la parte (como jquery o bigote) que cambian muy raramente (y cuando lo hacen, la versión en el archivo generalmente cambia): estas pueden agruparse / minimizarse "según sea necesario" usando WebGrease o JSCompress. com (solo incluya el archivo / versión en paquete en su _Layout.cshtml)
2) archivos css / js específicos de la página que deben actualizarse cada vez que se envíe una nueva compilación. (sin que el usuario borre su caché o haga varias actualizaciones)
Mi solución: Incremente automáticamente la versión de ensamblaje cada vez que se genere el proyecto, y use ese número para un archivo estático enrutado en los recursos específicos que le gustaría mantener actualizados. (por lo tanto, something.js se incluye como something.v1234.js con 1234 que cambia automáticamente cada vez que se construye el proyecto). También agregué algunas funciones adicionales para garantizar que los archivos .min.js se usen en producción y que se usen los archivos regulares.js. al depurar (estoy usando WebGrease para automatizar el proceso de reducción) Una cosa buena de esta solución es que funciona en modo local / dev, así como en producción.
Cómo hacerlo: Incremente automáticamente la versión de ensamblaje cada vez que se genere el proyecto, y use ese número para un archivo estático enrutado en los recursos específicos que le gustaría mantener actualizados. (por lo tanto, something.js se incluye como something.v1234.js con 1234 que cambia automáticamente cada vez que se construye el proyecto). También agregué algunas funciones adicionales para garantizar que los archivos .min.js se usen en producción y que se usen los archivos regulares.js. al depurar (estoy usando WebGrease para automatizar el proceso de reducción) Una cosa buena de esta solución es que funciona en modo local / dev, así como en producción. (Estoy usando Visual Studio 2015 / Net 4.6, pero creo que esto también funcionará en versiones anteriores.
Paso 1: habilite el incremento automático en el ensamblaje cuando esté integrado En el archivo AssemblyInfo.cs (que se encuentra en la sección de "propiedades" de su proyecto, cambie 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 la reescritura de URL en web.config para los archivos con las versiones integradas (vea el paso 3)
En web.config (el principal para el proyecto) agregue las siguientes reglas en 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: Configure las Variables de la aplicación para leer su versión de ensamblaje actual 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) agregue el siguiente código a Application_Start () 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: cambie los enlaces src en las vistas de Razor usando las variables de aplicación que configuramos en Global.asax.cs
@HttpContext.Current.Application["CSSVer"]
@HttpContext.Current.Application["JSVer"]
Por ejemplo, en mi _Layout.cshtml, en mi sección principal, tengo el siguiente bloque de código para las 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 para notar aquí: 1) no hay extensión en el archivo. 2) tampoco hay .min. Ambos de estos son manejados por el código en Global.asax.cs
Del mismo modo, (también en _Layout.cs) en mi sección de 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 un paquete de todas mis bibliotecas de terceros que he creado manualmente con WebGrease. Si agrego o cambio cualquiera de los archivos en el paquete (lo cual es raro), entonces 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á en caché en el navegador del cliente hasta que vuelva a empaquetar / 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á. (Puede establecer un punto de interrupción en Application_OnBeginRequest de Global.asax.cs para verlo funcionar)
Discusión completa sobre esto en: Versiones automáticas simplificadas de Javascript / CSS en ASP.NET MVC 5 para detener los problemas de almacenamiento en caché (funciona en Azure y localmente) con o sin reescritura de URL (incluida una forma de hacerlo SIN reescritura de URL)