Подтвердить что ты не робот

Автоматическое управление версиями в 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>

спасибо

4b9b3361

Ответ 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-адреса перезаписи)