2011-04-28 3 views
9

Итак, я читал this stackoverflow post о «autoversioning» в ASP.NET MVC для файлов CSS/JS и задавался вопросом, что для этого нужно «лучшей» стратегии.Autoversioning CSS/JS в ASP.NET MVC?

Решения при условии вставки номер сборки - что означает каждый раз вы публикуете - это изменит каждый файл, который не является идеальным, потому что если вы сделаете изменения, только 1 * .css или * .js, то она будет меняться каждый и каждый файл.

1) Как это можно сделать только для «одиночных файлов» вместо использования сборки сайта с датой модификации или что-то на IIS7?

2) Также, если у меня есть какой-то «статический» актив, например - http://static.domain.com/js/123.js - как я могу использовать rewrite для отправки последнего файла для запроса, если кто-то интегрировал эту статическую ссылку на свой сайт?

i.e. http://static.domain.com/js/123.js - это ссылка, и когда запрос приходит для этого - проверьте и отправьте последний файл?

+0

Честно говоря, если вы связываете, то КАЖДЫЙ SINGLE-файл будет означать, как, 2-5 minified + bundled files. Я думаю, что это разумное решение. – Worthy7

ответ

4

1) Используйте вместо этого время изменения файла. Вот пример:

public static string GeneratePathWithTime(string cssFileName) 
{ 
    var serverFilePath = server.MapPath("~/static/" + cssFileName); 
    var version = File.GetLastWriteTime(serverFilePath).ToString("yyyyMMddhhmmss"); 
    return string.Format("/static/{0}/{1}", version, cssFileName); 
} 

Это будет генерировать путь «/static/201109231100/style.css» для «style.css» (при условии, ваш style.css находится в каталоге static). Затем вы должны добавить правило перезаписи в IIS для перезаписи «/static/201109231100/style.css» на «/static/style.css». Номер версии будет изменен только тогда, когда файл css был изменен и применим только к измененным файлам.

2) Вы можете обработать запрос к 123.js с помощью HttpModule и отправить его последний контент, но я не думаю, что вы можете гарантировать, что запрос получит самую последнюю версию. Это зависит от того, как браузер обрабатывает свой кеш. Вы можете установить более раннее время истечения срока действия (например, одну минуту назад) в заголовке ответа, чтобы сообщить обозревателям всегда повторно загружать файл, но все зависит от самого браузера, чтобы решить, следует ли повторно загружать файл или нет , Вот почему нам нужно генерировать другой путь для наших измененных файлов каждый раз, когда мы обновляем наши файлы в вашем вопросе 1), браузер всегда будет пытаться загрузить файл, если URL-адрес никогда не был посещен раньше.

+2

Вам не нужно настраивать правила перезаписи в IIS - MVC настойчиво поддерживает ** Маршрутизацию **! –

+0

Несомненно. И не только MVC. Вы также можете написать обработчик запроса и зарегистрировать его в web.config или использовать Global.asax. Они также поддерживаются. Переписывание IIS является одним из многих решений. Я рекомендую переписывать IIS, потому что он обрабатывает запросы до времени выполнения .net и может быть легко настроен без изменения вашего кода. – Miller

+0

Вы правы, с ASP.NET 4, Маршрутизация также доступна в ядре ASP.NET (вне MVC). Тем не менее, я имел в виду MVC, поскольку вопрос помечен им. –

3

Возможно, вы захотите взглянуть на Blogpost Dean Hume's MVC and the HTML5 Application Cache. В этой должности он указывает элегантный способ автоматической обработки версий для каждого запроса, используя библиотеку класса @ShirtlessKirk:

@Url.Content("~/Content/Site.css").AppendHash(Request) 
+0

Просто предостережение любому, кто наткнулся на этот ответ - этот метод опирается на кэш приложений, который, кажется, устарел: https://developer.mozilla.org/en/docs/Web/HTML/Using_the_application_cache – Orilux

3

Я написал Url Helper, который делает для меня очистки кэша.

public static string CacheBustedContent(this UrlHelper helper, string contentPath) 
{ 
    var path = string.Empty; 

    if (helper.RequestContext.HttpContext.Cache["static-resource-" + contentPath] == null) 
    { 
     var fullpath = helper.RequestContext.HttpContext.Server.MapPath(contentPath); 
     var md5 = GetMD5HashFromFile(fullpath); 
     path = helper.Content(contentPath) + "?v=" + md5; 

     helper.RequestContext.HttpContext.Cache.Add("static-resource-" + contentPath, path, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(24, 0, 0), System.Web.Caching.CacheItemPriority.Default, null); 
    } 
    else 
    { 
     path = helper.RequestContext.HttpContext.Cache["static-resource-" + contentPath].ToString(); 
    } 

    return path; 
} 

Вы могли бы заменить GetMD5HashFromFile() с CRC или любого другого рода вызов, который генерирует уникальную строку на основе содержимого или последнего изменения даты-файла.

Недостатком является то, что он будет вызван всякий раз, когда кеш признан недействительным. И если вы каким-то образом измените файл на live, но не сбрасываете пул приложений, вам, вероятно, нужно будет прикоснуться к файлу web.config, чтобы он был правильно загружен.

+1

Это говорит о том, Мне очень нравится SquishIt для минимизации, объединения и кэширования как javascript, так и css. http://www.codethinked.com/squishit-the-friendly-aspnet-javascript-and-css-squisher – davewasthere

9

Способ, которым я решил эту проблему, заключался в том, чтобы добавить autoversioning в мой проект MVC в AssemblyInfo.CS файл следующим образом:

Change 
[assembly: AssemblyVersion("1.0.0.0")] 
to  
[assembly: AssemblyVersion("1.0.*")] 

Это означает, что каждый раз, когда проект будет построен, он будет иметь новую версию сборки, которая выше, чем предыдущий. Теперь у вас есть свой уникальный номер версии.

Затем я создал класс UrlHelperExtension, который поможет мне получить эту информацию, когда мне это нужно в моих взглядах:

public static class UrlHelperExtensions 
{ 
    public static string ContentVersioned(this UrlHelper self, string contentPath) 
    { 
     string versionedContentPath = contentPath + "?v=" + Assembly.GetAssembly(typeof(UrlHelperExtensions)).GetName().Version.ToString(); 
     return self.Content(versionedContentPath); 
    } 
} 

Теперь вы можете легко добавить номер версии ваших взглядов следующим образом:

<link href="@Url.ContentVersioned("style.css")" rel="stylesheet" type="text/css" /> 

При просмотре исходного кода страницы теперь вы будете иметь то, что выглядит как

<link href="style.css?v=1.0.4809.30029" rel="stylesheet" type="text/css" /> 
+0

Я получаю сообщение об ошибке ** Нет перегрузки для метода 'ContentVersioned' принимает 1 аргумент ** i am Anjyr

+0

Отличное решение! – mrpotocnik

+0

@ Anjyr, основанный на приведенном выше предположении и предполагая, что у вас есть расширение ContentVersioned, например, выше, src='~/Scripts/demoproject/@FileVersioning.ContentVersioned ("custom.js") ' to src =' @ Url.ContentVersioned ("~/full/path/to/custom.js") ' – mrpotocnik

2

UPDATE: Предыдущая версия не работает на Azure, я упростил и исправил ниже. (Обратите внимание, что для работы в режиме разработки с помощью IIS Express вам потребуется установить URL Rewrite 2.0 из Microsoft http://www.iis.net/downloads/microsoft/url-rewrite - он использует установщик WebPi, обязательно закройте Visual Studio)

Если вы хотите изменить фактические имена файлов, а не добавление запроса (который игнорируется некоторыми прокси/браузерами для статических файлов). Вы можете выполнить следующие шаги: (Я знаю, что это старый пост, но я столкнулся с ним при разработке решения :

Как это сделать: автоматического приращения версии сборки каждый раз, когда проект построен, и использовать этот номер для маршрутизации статического файла на конкретном ре источники, которые вы хотели бы сохранить. (поэтому 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")] 

в

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

Шаг 2: Настройка URL REW обряд в web.config для файлов с внедренными версиями слизней (см шага 3)

В web.config (основнымы для проекта) добавить следующие правила в разделе <system.webServer> я положил его непосредственно после </httpProtocol> конечного тега.

<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 (находится в корневом каталоге проекта) добавить следующий код в защищенный ничтожной 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: Изменить ГКЗ ссылки в Бритва рассматривает использование переменных приложения, которые мы поставили в 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) в моем яваскрипта разделе: У меня есть следующий код:

<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, чтобы посмотреть его работы)

Полное обсуждение по этому вопросу на: 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(в том числе способ сделать это без URL Rewrite)

+0

простой и чистый ... спасибо Ричард. – Bharat