Автоматическое управление версиями в ASP.NET MVC для файлов CSS/JS?
Я прочитал много статей о том, как автоматически обновлять ваши файлы CSS/JS, но ни один из них действительно не обеспечивает элегантный способ сделать это в ASP.NET MVC.
Эта ссылка - Как заставить браузер перезагружать кэшированные файлы CSS/JS? - предоставляет решение для Apache - но я немного запутался, как это может быть реализован через ASP.NET MVC?
Может ли кто-нибудь дать совет, как это сделать на IIS7 и ASP.NET MVC, чтобы файлы CSS/JS автоматически имели номер версии, вставленный в URL-адрес, без изменения местоположения файла?
Таким образом, ссылки выходят из ссылки и т.д., предположительно используя URL Rewrite или?
<link rel="stylesheet" href="/css/structure.1194900443.css" type="text/css" />
<script type="text/javascript" src="/scripts/prototype.1197993206.js"></script>
спасибо
Ответы
Ответ 1
Когда я столкнулся с этой проблемой, я написал серию оберточных функций вокруг метода UrlHelper
Content
:
EDIT:
После обсуждений в комментариях ниже я обновил этот код:
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));
}
}
Использование этих функций в сочетании со следующим правилом rewrite
должно работать:
<rewrite>
<rules>
<rule name="Rewrite assets">
<match url="^v(.*?)/assets/(.*?)" />
<action type="Rewrite" url="/assets/{R:2}" />
</rule>
</rules>
</rewrite>
В этой статье обсуждается, как создавать правила перезаписи для IIS7.
Этот код использует номер версии текущей сборки в качестве параметра строки запроса в пути к файлу, который он испускает. Когда я делаю обновление сайта и увеличивается число строков, так же как и параметр querystring в файле, и поэтому агент пользователя повторно загружает файл.
Ответ 2
Обычно я добавляю фальшивую строку запроса в мои файлы ресурсов. i.e
<link rel="stylesheet" href="/css/structure.css?v=1194900443" type="text/css" />
<script type="text/javascript" src="/scripts/prototype.js?v=1197993206"></script>
Он не требует каких-либо помощников URL и работает независимо от того, что работает в фоновом режиме. Честно говоря, я не проверил этот метод, но обнаружил, что он всегда исправляет любые проблемы кэширования ресурсов, которые люди испытывают.
Вам, вероятно, придется вручную обновлять v=
, но было бы ужасно сложно добавить параметр версии к ресурсам из файла конфигурации где-нибудь.
Edit:
Я вернулся и прочитал содержание ссылки выше и понял, что вы уже отбросили этот метод. Извиняюсь за повторное предложение.
Ответ 3
Я предполагаю следующее решение с расширенными параметрами (режим отладки/выпуска, версии):
Js или Css файлы, включенные таким образом:
<script type="text/javascript" src="Scripts/exampleScript<%=Global.JsPostfix%>" />
<link rel="stylesheet" type="text/css" href="Css/exampleCss<%=Global.CssPostfix%>" />
Global.JsPostfix и Global.CssPostfix вычисляются следующим образом в 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();
}
...
}
Ответ 4
ОБНОВЛЕНИЕ: Предыдущая версия не работала над Azure, я упростил и исправил ниже. (Обратите внимание: для этого в режиме разработки с IIS Express вам потребуется установить URL Rewrite 2.0 из Microsoft http://www.iis.net/downloads/microsoft/url-rewrite - он использует WebPi, обязательно закройте Visual Studio)
UPDATE: Исправлено правило для .min файлов
Недавно я провел совершенно бесплодный день, пытаясь получить автоматическое связывание (для поддержки автоматического управления версиями) в С#/Net 4.6/MVC 5/Razor для работы. Я читал много статей как в StackOverflow, так и в других местах, но я не мог найти сквозной ход того, как его настроить. Я также не забочусь о том, как файлы версии (добавление строки запроса с версией в статический запрос файла - то есть somefile.js? V = 1234), потому что некоторым из них сказали, что некоторые прокси-серверы игнорируют запрос при кешировании статических ресурсов.
Итак, после короткой поездки вниз по кроличьей норе, я перевернул свою собственную версию для автоматического управления версиями и включил полные инструкции о том, как заставить ее работать ниже.
Полная дискуссия @: Упрощенная автоматическая версия Javascript/CSS в ASP.NET MVC 5, чтобы остановить проблемы с кешированием (работает в Azure и локально) С или без перезаписи URL
ПРОБЛЕМА: В проекте обычно есть 2 типа файлов javascript/css.
1) 3 партийные библиотеки (такие как jquery или усы), которые очень редко меняются (и когда они это делают, версия в файле обычно изменяется) - они могут быть объединены/уменьшены по принципу "по мере необходимости" с использованием WebGrease или JSCompress.com(просто включите связанный файл/версию в ваш _Layout.cshtml)
2) специфичные для страницы файлы css/js, которые необходимо обновлять при каждом нажатии новой сборки. (без того, чтобы пользователь очистил кеш-память или сделал несколько обновлений)
Мое решение:. Автоматически увеличивайте версию сборки каждый раз, когда вы строите проект, и используйте этот номер для маршрутизируемого статического файла на конкретных ресурсах, которые вы хотели бы обновить. (поэтому something.js включен как something.v1234.js с 1234 автоматически меняющимся каждый раз, когда проект построен). Я также добавил некоторые дополнительные функции, чтобы гарантировать, что файлы .min.js используются в производстве, а файлы regular.js используются при отладке (я использую WebGrease для автоматизации процесса minify). Одна из приятных особенностей этого решения заключается в том, что он работает в локальном /dev режиме, а также в производстве.
Как это сделать:. Автоматически увеличивайте версию сборки каждый раз, когда вы строите проект, и используйте этот номер для маршрутизируемого статического файла на конкретных ресурсах, которые вы хотели бы обновить. (поэтому something.js включен как something.v1234.js с 1234 автоматически меняющимся каждый раз, когда проект построен). Я также добавил некоторые дополнительные функции, чтобы гарантировать, что файлы .min.js используются в производстве, а файлы regular.js используются при отладке (я использую WebGrease для автоматизации процесса minify). Одна хорошая вещь об этом решении заключается в том, что он работает в локальном /dev режиме, а также в производстве. (Я использую Visual Studio 2015/Net 4.6, но я считаю, что это будет работать и в более ранних версиях.
Шаг 1: Включить автоинкремент на сборке при построении
В файле AssemblyInfo.cs(в разделе "Свойства" вашего проекта измените следующие строки:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
to
[assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyFileVersion("1.0.0.0")]
Шаг 2: Настройте URL-адрес для перезаписи в файле web.config для файлов со встроенными версиями (см. шаг 3)
В web.config(основной для проекта) добавьте следующие правила в 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>
Шаг 3: Перечислите переменные приложения, чтобы прочитать текущую версию сборки и создать пули версии в файлах js и css.
в Global.asax.cs(найденный в корне проекта) добавьте следующий код в защищенный void Application_Start() (после строк регистра)
// 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";
Шаг 4: Измените ссылки src в представлениях Razor, используя переменные приложения, которые мы установили в Global.asax.cs
@HttpContext.Current.Application["CSSVer"]
@HttpContext.Current.Application["JSVer"]
Например, в моем _Layout.cshtml в моем разделе главы у меня есть следующий блок кода для таблиц стилей:
<!-- 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)
Несколько вещей, чтобы заметить здесь: 1) в файле нет расширения. 2) также нет .min. Оба они обрабатываются кодом в Global.asax.cs
Аналогично, (также в _Layout.cs) в моем разделе javascript: у меня есть следующий код:
<script src="~/Scripts/all3bnd100.min.js" type="text/javascript"></script>
<script src="~/Scripts/[email protected]["JSVer"]" type="text/javascript"></script>
@RenderSection("scripts", required: false)
Первый файл представляет собой набор всех моих сторонних библиотек, которые я создал вручную с помощью WebGrease. Если я добавляю или изменяю какие-либо файлы в комплекте (что редко), я вручную переименовываю файл в all3bnd101.min.js, all3bnd102.min.js и т.д. Этот файл не соответствует обработчику перезаписи, поэтому будет храниться в кэше в браузере клиента, пока вы вручную не переустановите/не измените имя.
Второй файл - ui.js(который будет записан как ui.v12345123.js или ui.v12345123.min.js в зависимости от того, работает ли вы в режиме отладки или нет). Это будет обработано/перезаписано. (вы можете установить контрольную точку в Application_OnBeginRequest файла Global.asax.cs, чтобы посмотреть, как она работает)
Полная дискуссия по этому вопросу: Упрощенная автоматическая версия Javascript/CSS в ASP.NET MVC 5 для остановки кеширования (работает в Azure и локально) С или без URL-адреса Rewrite (Включая способ сделать это БЕЗ URL-адреса перезаписи)