Pull to refresh

Переходим на WebMarkupMin 2.X

Reading time22 min
Views3.8K
Логотипы WebMarkupMin, .NET Core и NUglify
Весной прошлого года, когда ASP.NET 5 был еще в стадии Beta 3, я начал получать от пользователей письма с просьбами сделать WebMarkupMin совместимым с DNX 4.5.1 и DNX Core 5.0. Основной проблемой было то, что новый .NET не поддерживал настройку с помощью конфигурационных файлов App.config и Web.config. Переписывание WebMarkupMin.Core, WebMarkupMin.MsAjax и WebMarkupMin.Yui не должно было представлять особой сложности, потому что нужно было просто удалить весь код, использующий библиотеку System.Configuration. Серьезные проблемы должны были возникнуть при переписывании ASP.NET-расширений, потому что для них нужно было разработать совершенно новую модель конфигурации, а это, в свою очередь, требовало очень серьезных изменений в архитектуре. Эти изменения затрагивали не только код, но и структуру решения и NuGet-пакеты, поэтому я решил начать с чистого листа и сделал репозиторий на GitHub. На тот момент, до релиза стабильной версии нового ASP.NET оставалось как минимум полгода, поэтому нужно было одновременно поддерживать 2 ветви WebMarkupMin: стабильную 1.X на CodePlex и предварительную 2.X на GitHub.

Как известно всем, выход стабильных версий .NET и ASP.NET Core 1.0 задержался еще на несколько месяцев и состоялся только в конце июня этого года. Вслед за релизом этих фреймворков, состоялся и релиз WebMarkupMin 2.0. В этой статье я расскажу вам о том, как обновить существующие приложения под WebMarkupMin 2.X, а также как добавить его в веб-приложения, написанные на ASP.NET Core.

Критические изменения и нововведения


Для того чтобы установить пакеты WebMarkupMin 2.X вам необходимо обновить NuGet Package Manager до версии 2.8.6 или выше.

Основным критическим изменением версии 2.X стал отказ от использования файлов Web.config и App.config для настройки WebMarkupMin. Теперь при настройке вместо декларативного подхода (использование конфигурационных файлов) используется императивный подход (использование программного кода).

Поэтому при обновлении WebMarkupMin до версии 2.X нужно обязательно сделать 2 вещи:

  1. Удалить пакет WebMarkupMin.ConfigurationIntelliSense, т.к. в нем больше нет необходимости.
  2. После удаления устаревших пакетов и обновления старых версий пакетов до новых, необходимо удалить группу конфигурационных секций webMarkupMin и ее объявление из файлов Web.config и App.config:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <configSections>
        …
        <sectionGroup name="webMarkupMin">
          …
        </sectionGroup>
        …
      </configSections>
      …
      <webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
        …
      </webMarkupMin>
      …
    </configuration>

Далее рассмотрим процедуру обновления для каждого пакета в отдельности.

Core


После обновления пакета WebMarkupMin.Core нужно в коде вашего приложения заменить все подключения пространств имен WebMarkupMin.Core.Minifiers и WebMarkupMin.Core.Settings на WebMarkupMin.Core.

Внешние минификаторы CSS- и JS-кода


К сожалению, модули WebMarkupMin.MsAjax и WebMarkupMin.Yui не поддерживают .NET Core, и поэтому могут использоваться только в приложениях .NET 4.X, веб-приложениях ASP.NET 4.X и веб-приложениях ASP.NET Core, созданных на основе шаблона «ASP.NET Core Web Application (.NET Framework)». Это вызвано тем, что авторы Microsoft Ajax Minifier и YUI Compressor for .NET не портировали свои библиотеки под .NET Core. Про YUI Compressor for .NET не могу сказать ничего определенного, возможно через какое-то время его все-таки портируют. Насчет Microsoft Ajax Minifier уже все предельно ясно: его разработка была прекращена в марте 2015 года (после ухода Рона Логана из Microsoft). Но не все так плохо, потому что существует «форк» Microsoft Ajax Minifier под названием NUglify, который совместим с .NET Core. В новой версии WebMarkupMin есть пакет, основанный на нем — WebMarkupMin.NUglify.

MS Ajax


После обновления пакета WebMarkupMin.MsAjax нужно в коде вашего приложения заменить все подключения пространств имен WebMarkupMin.MsAjax.Minifiers и WebMarkupMin.MsAjax.Settings на WebMarkupMin.MsAjax.

YUI


После обновления пакета WebMarkupMin.Yui нужно в коде вашего приложения заменить все подключения пространств имен WebMarkupMin.Yui.Minifiers и WebMarkupMin.Yui.Settings на WebMarkupMin.Yui.

NUglify


На данный момент, API WebMarkupMin.NUglify полностью идентичен WebMarkupMin.MsAjax. Поэтому при переходе с WebMarkupMin.MsAjax на WebMarkupMin.NUglify в коде приложения достаточно просто заменить префиксы MsAjax на NUglify.

Расширения для интеграции с ASP.NET


Все пакеты с ASP.NET-расширениями для версии 1.X (WebMarkupMin.Web, WebMarkupMin.Mvc и WebMarkupMin.WebForms) признаны устаревшими и не используются в WebMarkupMin 2.X.

Перечислю основные нововведения в расширениях для ASP.NET:

  1. Переход на императивный подход к настройке расширений.
  2. Теперь можно ассоциировать типы содержимого (MIME-типы) с соответствующими минификаторами разметки.
  3. Появилась возможность указывать минификатору какие страницы сайта он должен обработать.


ASP.NET 4.X HTTP modules


Чтобы обновить веб-приложение ASP.NET, которое использует HTTP-модули из пакета WebMarkupMin.Web нужно выполнить следующие действия:

  1. Удалить пакет WebMarkupMin.Web.
  2. Установить пакет WebMarkupMin.AspNet4.HttpModules.
  3. Обновить оставшиеся старые пакеты WebMarkupMin до версии 2.X.
  4. В файле Web.config нужно заменить: пространство имен WebMarkupMin.Web.HttpModules на WebMarkupMin.AspNet4.HttpModules, имя сборки WebMarkupMin.Web на WebMarkupMin.AspNet4.HttpModules и имя класса CompressionModule на HttpCompressionModule.

Благодаря появлению возможности указывать минификатору какие страницы сайта он должен обработать, HTTP-модули HtmlMinificationModule и XhtmlMinificationModule теперь могут использоваться вместе.

ASP.NET 4.X MVC


Чтобы обновить веб-приложение ASP.NET MVC, которое использует фильтры действий из пакета WebMarkupMin.Mvc нужно выполнить следующие действия:

  1. Удалить пакеты WebMarkupMin.Mvc и WebMarkupMin.Web.
  2. Установить пакет WebMarkupMin.AspNet4.Mvc.
  3. Обновить оставшиеся старые пакеты WebMarkupMin до версии 2.X.
  4. В коде вашего приложения заменить все подключения пространства имен WebMarkupMin.Mvc.ActionFilters на WebMarkupMin.AspNet4.Mvc.

Стоит также отметить, что в отличии от старых версий WebMarkupMin, в версии 2.X вы можете применять фильтры действий к контроллерам:

…
using System.Web.Mvc;

using WebMarkupMin.AspNet4.Mvc;
…

namespace WebMarkupMin.Sample.AspNet4.Mvc4.Controllers
{
    [CompressContent]
    [MinifyHtml]
    [MinifyXhtml]
    [MinifyXml]
    …
    public class HomeController : Controller
    {
        …
    }
} 

Кроме того, в версии 2.X можно применять фильтры действий на уровне всего веб-приложения. Для этого нужно отредактировать файл App_Start/FilterConfig.cs следующим образом:

using System.Web.Mvc;

using WebMarkupMin.AspNet4.Mvc;

namespace WebMarkupMin.Sample.AspNet4.Mvc4
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            …
            filters.Add(new CompressContentAttribute());
            filters.Add(new MinifyHtmlAttribute());
            filters.Add(new MinifyXhtmlAttribute());
            filters.Add(new MinifyXmlAttribute());
            …
        }
    }
}

Также в прошлое ушли ошибки вида «The 'MinifyXXXAttribute' attribute can not be applied to the 'XXX' action method of the 'XXX' controller, because it returns the result with not supported content type.». Теперь, если тип содержимого результата действия не соответствует фильтру, то к этому результату просто не применяется минификация.

ASP.NET 4.X Web Forms


Чтобы обновить веб-приложение ASP.NET Web Forms, которое использует классы страниц или мастер-страниц из пакета WebMarkupMin.WebForms нужно выполнить следующие действия:

  1. Удалить пакеты WebMarkupMin.WebForms и WebMarkupMin.Web.
  2. Установить пакет WebMarkupMin.AspNet4.WebForms.
  3. Обновить оставшиеся старые пакеты WebMarkupMin до версии 2.X.
  4. В коде вашего приложения заменить все подключения пространств имен WebMarkupMin.WebForms.Pages и WebMarkupMin.WebForms.MasterPages на WebMarkupMin.AspNet4.WebForms.

В версии 2.X были добавлены классы страниц, которые поддерживают только минификацию (без HTTP-сжатия): MinifiedHtmlPage и MinifiedXhtmlPage. Также соответствующие классы появились и для мастер-страниц: MinifiedHtmlMasterPage и MinifiedXhtmlMasterPage.

ASP.NET Core 1.X


В новой версии WebMarkupMin появилось расширение для ASP.NET Core — пакет WebMarkupMin.AspNetCore1. По функционалу этот пакет напоминает WebMarkupMin.AspNet4.HttpModules, только вместо четырех HTTP-модулей здесь содержится один компонент middleware. Главным отличием этого пакета от WebMarkupMin.AspNet4.HttpModules является, то что подключение модулей (возможностей) и их настройка осуществляются в одном месте – в файле Startup.cs.

Рассмотрим пример подключения модулей:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

using WebMarkupMin.AspNetCore1;

namespace TestAspNetCore1
{
    public class Startup
    {
        …
        // This method gets called by the runtime.
        // Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            …
            // Add WebMarkupMin services.
            services.AddWebMarkupMin()
                .AddHtmlMinification()
                .AddXmlMinification()
                .AddHttpCompression()
                ;

            // Add framework services.
            services.AddMvc();
        }

        // This method gets called by the runtime.
        // Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env,
            ILoggerFactory loggerFactory)
        {
            …
            app.UseWebMarkupMin();

            app.UseMvc(routes =>
            {
                …
            });
        }
    }
}

В методе ConfigureServices производится регистрация сервисов. С помощью метода-расширения AddWebMarkupMin и его дочерних методов (AddHtmlMinification, AddXmlMinification и AddHttpCompression) мы добавляем сервисы WebMarkupMin в контейнер внедрения зависимостей:

  1. Метод AddWebMarkupMin регистрирует следующие классы в качестве синглтонов: ThrowExceptionLogger (реализация интерфейса ILogger), KristensenCssMinifierFactory (реализация интерфейса ICssMinifierFactory) и CrockfordJsMinifierFactory (реализация интерфейса IJsMinifierFactory). Сам по себе этот метод не подключает ни одного модуля (возможности), для этой цели служат его дочерние методы. Например, если не вызвать метод AddHtmlMinification, то HTML-минификация будет недоступна.
  2. Метод AddHtmlMinification регистрирует класс HtmlMinificationManager (реализация интерфейса IHtmlMinificationManager) в качестве синглтона. Также существует аналогичный метод — AddXhtmlMinification, который регистрирует класс XhtmlMinificationManager как реализацию интерфейса IXhtmlMinificationManager.
  3. Метод AddXmlMinification регистрирует класс XmlMinificationManager (реализация интерфейса IXmlMinificationManager) в качестве синглтона.
  4. Метод AddHttpCompression регистрирует класс HttpCompressionManager (реализация интерфейса IHttpCompressionManager) в виде синглтона.

В методе Configure производится регистрация компонентов middleware. С помощью метода-расширения UseWebMarkupMin мы добавляем класс WebMarkupMinMiddleware в конвейер ASP.NET. Вызов этого метода должен быть сделан непосредственно перед вызовом метода UseMvc, потому что компонент RouterMiddleware завершает цепочку вызовов.

Таким образом, мы добавили в наше веб-приложение HTML-минификацию, XML-минификацию и HTTP-сжатие. В разделе «Модель конфигурации ASP.NET Core-расширения» мы рассмотрим, как настроить и переопределить добавленные сервисы.

Базовая модель конфигурации ASP.NET-расширений


До WebMarkupMin 2.X настройка ASP.NET-расширений производилась путем редактирования файла Web.config. Сейчас для настройки расширений вместо декларативного подхода (использование конфигурационного файла) используется императивный подход (использование программного кода).

Отказ от декларативного подхода был вызван следующими причинами:

  1. Microsoft уже несколько лет, использует императивный подход для настройки отдельных частей ASP.NET (например, Web API или Web Optimization Framework).
  2. В ASP.NET Core осталась лишь ограниченная поддержка файлов Web.config (в основном для интеграции с IIS).

Расширения для ASP.NET 4.X и ASP.NET Core 1.X используют различные конфигурационные модели. В ASP.NET 4.X настройка расширений производится через специальные классы: WebMarkupMinConfiguration, HtmlMinificationManager, XhtmlMinificationManager и XmlMinificationManager. В ASP.NET Core 1.X настройка расширений основана на фреймворке Microsoft.Extensions.Options и использует следующие классы: WebMarkupMinOptions, HtmlMinificationOptions, XhtmlMinificationOptions и XmlMinificationOptions. Однако эти модели конфигурации имеют много общего, а их интерфейсы и базовые классы выделены в отдельный пакет — WebMarkupMin.AspNet.Common.

Базовые настройки ASP.NET-расширений


Классы WebMarkupMinConfiguration и WebMarkupMinOptions наследуют класс WebMarkupMinConfigurationBase, который имеет следующие свойства.
Свойство Тип данных Значение по умолчанию Описание
DisableMinification Булевский false Отключает минификацию разметки.
DisableCompression Булевский false Отключает HTTP-сжатие текстового контента.
MaxResponseSize Целое число -1 Максимальный размер HTTP-ответа (в байтах), при превышении которого отключается минификация разметки. Если значение этого свойства равно -1, то проверка размера HTTP-ответа не производится.
DisablePoweredBy­HttpHeaders Булевский false Отключает HTTP-заголовки *-Minification-Powered-By (например, заголовок X-HTML-Minification-Powered-By: WebMarkupMin)

Этот класс и его подклассы являются заменой конфигурационной секции configuration/webMarkupMin/webExtensions из предыдущей версии WebMarkupMin.

Менеджеры и опции минификации разметки


Менеджеры минификации по своей сути являются настраиваемыми фабриками, которые создают экземпляры минификаторов разметки. Но помимо этого они еще содержат логику, позволяющую выборочно применять минификацию (на основе типа содержимого и URL).

Все классы менеджеров и опций минификации разметки имеют свойства IncludedPages и ExcludedPages, которые позволяют включать/исключать страницы сайта из процесса обработки минификатором. Эти свойства имеют тип IList<IUrlMatcher>, и по умолчанию содержат пустые списки, т.к. по умолчанию фильтрация отключена и минифицируются все страницы.

Существует 3 встроенных реализации интерфейса IUrlMatcher:

  1. ExactUrlMatcher. В качестве шаблона используется URL (например, new ExactUrlMatcher("/contact")).
  2. RegexUrlMatcher. В качестве шаблона используется регулярное выражение, совместимое со стандартом ECMAScript (например, new RegexUrlMatcher(@"^/minifiers/x(?:ht)?ml-minifier$")).
  3. WildcardUrlMatcher. Используется шаблон, поддерживающий синтаксис Wildcard (например, new WildcardUrlMatcher("/minifiers/x*ml-minifier")). Этот синтаксис поддерживает 2 метасимвола: звездочку (*) — соответствует любой строке символов, даже пустой; и знак вопроса (?) — соответствует любому одиночному символу.

По умолчанию все вышеперечисленные реализации интерфейса IUrlMatcher не чувствительны к регистру. Чтобы изменить это поведение нужно передать в конструктор класса в качестве второго параметра значение равное true (например, new ExactUrlMatcher("/Contact", true)).

Менеджер и опции HTML минификации


Классы HtmlMinificationManager и HtmlMinificationOptions имеют следующие общие свойства:
Свойство Тип данных Значение по умолчанию Описание
MinificationSettings HtmlMinification­Settings Экземпляр класса HtmlMinification­Settings Настройки HTML-минификатора.
SupportedMediaTypes ISet<string> text/html Список поддерживаемых типов содержимого.
IncludedPages IList<IUrlMatcher> Пустой список Включает страницы сайта в процесс обработки HTML-минификатором.
ExcludedPages IList<IUrlMatcher> Пустой список Исключает страницы сайта из процесса обработки HTML-минификатором.
CssMinifierFactory ICssMinifierFactory Экземпляр класса KristensenCssMinifier­Factory Фабрика CSS-минификаторов.
JsMinifierFactory IJsMinifierFactory Экземпляр класса CrockfordJsMinifier­Factory Фабрика JS-минификаторов.

Менеджер и опции XHTML минификации


Классы XhtmlMinificationManager и XhtmlMinificationOptions имеют следующие общие свойства:
Свойство Тип данных Значение по умолчанию Описание
MinificationSettings XhtmlMinification­Settings Экземпляр класса XhtmlMinification­Settings Настройки XHTML-минификатора.
SupportedMediaTypes ISet<string> text/html, application/xhtml+xml Список поддерживаемых типов содержимого.
IncludedPages IList<IUrlMatcher> Пустой список Включает страницы сайта в процесс обработки XHTML-минификатором.
ExcludedPages IList<IUrlMatcher> Пустой список Исключает страницы сайта из процесса обработки XHTML-минификатором.
CssMinifierFactory ICssMinifierFactory Экземпляр класса KristensenCssMinifier­Factory Фабрика CSS-минификаторов.
JsMinifierFactory IJsMinifierFactory Экземпляр класса CrockfordJsMinifier­Factory Фабрика JS-минификаторов.

Менеджер и опции XML минификации


Классы XmlMinificationManager и XmlMinificationOptions имеют следующие общие свойства:
Свойство Тип данных Значение по умолчанию Описание
MinificationSettings XmlMinification­Settings Экземпляр класса XmlMinification­Settings Настройки XML-минификатора.
SupportedMediaTypes ISet<string> application/xml, text/xml, application/xml-dtd, application/xslt+xml, application/rss+xml, application/atom+xml, application/rdf+xml, application/soap+xml, application/wsdl+xml, image/svg+xml, application/mathml+xml, application/voicexml+xml, application/srgs+xml Список поддерживаемых типов содержимого.
IncludedPages IList<IUrlMatcher> Пустой список Включает страницы сайта в процесс обработки XML-минификатором.
ExcludedPages IList<IUrlMatcher> Пустой список Исключает страницы сайта из процесса обработки XML-минификатором.

Менеджер HTTP-сжатия


Класс HttpCompressionManager тоже является фабрикой и отвечает за создание экземпляров GZip- и Deflate-компрессоров. Но в отличие от менеджеров минификации он не имеет настраиваемых свойств. Также, как и менеджеры минификации, он содержит логику, позволяющую применять HTTP-сжатие выборочно (сжимается только текстовое содержимое).

Решение о том, какой тип компрессора нужно создать принимается на основе значения HTTP-заголовка Accept-Encoding. Если браузер поддерживает оба типа сжатия, то предпочтение отдается Deflate.

Модель конфигурации ASP.NET 4.X-расширений


Настройка ASP.NET 4.X-расширений производится через специальные классы: WebMarkupMinConfiguration, HtmlMinificationManager, XhtmlMinificationManager и XmlMinificationManager (эти классы определены в пакете WebMarkupMin.AspNet4.Common).

Настройки ASP.NET-расширения


Класс WebMarkupMinConfiguration в дополнение к свойствам, наследованным от класса WebMarkupMinConfigurationBase, также имеет свои собственные свойства:
Свойство Тип данных Значение по умолчанию Описание
AllowMinification­InDebugMode Булевский false Разрешает минификацию разметки в режиме отладки.
AllowCompression­InDebugMode Булевский false Разрешает HTTP-сжатие текстового содержимого в режиме отладки.

Режим отладки определяется на основе значения атрибута debug конфигурационного элемента configuration/system.web/compilation из файла Web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  …
  <system.web>
    …
    <compilation debug="false" … />
    …
  </system.web>
  …
</configuration>

По умолчанию в режиме отладки не производиться минификация и HTTP-сжатие. Чтобы включить их нужно присвоить вышеперечисленным конфигурационным свойствам значение равное true или перевести веб-приложения в режим релиза.

Особенности настройки


Прежде чем рассказать об особенностях настройки расширений для ASP.NET 4.X в WebMarkupMin версии 2.X, я сначала приведу пример настроек на основе файла Web.config из предыдущей версии:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    …
    <sectionGroup name="webMarkupMin">
      <section name="core"
        type="WebMarkupMin.Core.Configuration.CoreConfiguration, WebMarkupMin.Core" />
      <section name="msAjax"
        type="WebMarkupMin.MsAjax.Configuration.MsAjaxConfiguration, WebMarkupMin.MsAjax" />
      <section name="webExtensions"
        type="WebMarkupMin.Web.Configuration.WebExtensionsConfiguration, WebMarkupMin.Web" />
    </sectionGroup>
    …
  </configSections>
  …
  <webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
    <core>
      <html removeRedundantAttributes="true"
        removeHttpProtocolFromAttributes="true"
        removeHttpsProtocolFromAttributes="true" />
      <xhtml removeRedundantAttributes="true"
        removeHttpProtocolFromAttributes="true"
        removeHttpsProtocolFromAttributes="true" />
      <xml collapseTagsWithoutContent="true" />
      <css defaultMinifier="MsAjaxCssMinifier">
        <minifiers>
          <add name="NullCssMinifier"
            displayName="Null CSS Minifier"
            type="WebMarkupMin.Core.Minifiers.NullCssMinifier, WebMarkupMin.Core" />
          <add name="KristensenCssMinifier"
            displayName="Mads Kristensen's CSS minifier"
            type="WebMarkupMin.Core.Minifiers.KristensenCssMinifier, WebMarkupMin.Core" />
          <add name="MsAjaxCssMinifier"
            displayName="Microsoft Ajax CSS Minifier"
            type="WebMarkupMin.MsAjax.Minifiers.MsAjaxCssMinifier, WebMarkupMin.MsAjax" />
        </minifiers>
      </css>
      <js defaultMinifier="MsAjaxJsMinifier">
        <minifiers>
          <add name="NullJsMinifier"
            displayName="Null JS Minifier"
            type="WebMarkupMin.Core.Minifiers.NullJsMinifier, WebMarkupMin.Core" />
          <add name="CrockfordJsMinifier"
            displayName="Douglas Crockford's JS Minifier"
            type="WebMarkupMin.Core.Minifiers.CrockfordJsMinifier, WebMarkupMin.Core" />
          <add name="MsAjaxJsMinifier"
            displayName="Microsoft Ajax JS Minifier"
            type="WebMarkupMin.MsAjax.Minifiers.MsAjaxJsMinifier, WebMarkupMin.MsAjax" />
        </minifiers>
      </js>
      <logging defaultLogger="MyLogger">
        <loggers>
          <add name="NullLogger"
            displayName="Null Logger"
            type="WebMarkupMin.Core.Loggers.NullLogger, WebMarkupMin.Core" />
          <add name="ThrowExceptionLogger"
            displayName="Throw exception logger"
            type="WebMarkupMin.Core.Loggers.ThrowExceptionLogger, WebMarkupMin.Core" />
          <add name="MyLogger"
            displayName="My logger"
            type="TestAspNetMvc5.MyLogger, TestAspNetMvc5" />
        </loggers>
      </logging>
    </core>
    <msAjax>
      <css colorNames="Major" />
      <js quoteObjectLiteralProperties="true" />
    </msAjax>
    <webExtensions disableMinificationInDebugMode="false"
      disableCompressionInDebugMode="false" />
  </webMarkupMin>
  …
</configuration>

Далее я воспроизведу эти настройки средствами новой модели конфигурации.

Настройка ASP.NET 4.X-расширений во многом напоминает настройку Microsoft ASP.NET Web Optimization Framework.

В веб-приложениях ASP.NET MVC и Web Forms настройка WebMarkupMin производится в файле App_Start/WebMarkupMinConfig.cs:

using System.Collections.Generic;

using WebMarkupMin.AspNet.Common;
using WebMarkupMin.AspNet.Common.UrlMatchers;
using WebMarkupMin.AspNet4.Common;
using WebMarkupMin.Core;
using WebMarkupMin.MsAjax;

namespace TestAspNetMvc5
{
    public class WebMarkupMinConfig
    {
        public static void Configure(WebMarkupMinConfiguration configuration)
        {
            configuration.AllowMinificationInDebugMode = true;
            configuration.AllowCompressionInDebugMode = true;

            IHtmlMinificationManager htmlMinificationManager = HtmlMinificationManager.Current;
            htmlMinificationManager.ExcludedPages = new List<IUrlMatcher>
            {
                new WildcardUrlMatcher("/minifiers/x*ml-minifier"),
                new ExactUrlMatcher("/contact")
            };
            htmlMinificationManager.MinificationSettings = new HtmlMinificationSettings
            {
                RemoveRedundantAttributes = true,
                RemoveHttpProtocolFromAttributes = true,
                RemoveHttpsProtocolFromAttributes = true
            };

            IXhtmlMinificationManager xhtmlMinificationManager = XhtmlMinificationManager.Current;
            xhtmlMinificationManager.IncludedPages = new List<IUrlMatcher>
            {
                new WildcardUrlMatcher("/minifiers/x*ml-minifier"),
                new ExactUrlMatcher("/contact")
            };
            xhtmlMinificationManager.MinificationSettings = new XhtmlMinificationSettings
            {
                RemoveRedundantAttributes = true,
                RemoveHttpProtocolFromAttributes = true,
                RemoveHttpsProtocolFromAttributes = true
            };

            IXmlMinificationManager xmlMinificationManager = XmlMinificationManager.Current;
            xmlMinificationManager.MinificationSettings = new XmlMinificationSettings
            {
                CollapseTagsWithoutContent = true
            };

            DefaultCssMinifierFactory.Current = new MsAjaxCssMinifierFactory(
                new MsAjaxCssMinificationSettings { ColorNames = CssColor.Major }
            );
            DefaultJsMinifierFactory.Current = new MsAjaxJsMinifierFactory(
                new MsAjaxJsMinificationSettings { QuoteObjectLiteralProperties = true }
            );
            DefaultLogger.Current = new MyLogger();
        }
    }
}

Эти настройки практически идентичны настройкам из файла Web.config, за исключением одной маленькой детали – здесь показан пример использования свойств IncludedPages и ExcludedPages (в предыдущей версии не было такого функционала). В данном примере, с помощью этих свойств мы делим все страницы сайта с типом содержимого text/html на 2 группы: одни обрабатываются HTML-минификатором, а другие XHTML-минификатором. Такое разделение вряд ли пригодится в реальной жизни, но зато достаточно наглядно показывает, как пользоваться этими конфигурационными свойствами.

Другой момент, на котором я хотел бы остановиться – это использование фабрик CSS- и JS-минификаторов. Раньше при настройке ASP.NET-расширений мы указывали имена CSS- и JS-минификаторов, а сейчас вместо них мы используем экземпляры фабрик.

В версии 1.X при создании экземпляров таких минификаторов выполнялись 3 действия:

  1. Поиск в конфигурационном файле по имени минификатора информации о соответствующем .NET-типе.
  2. Создание экземпляра .NET-типа.
  3. Загрузка настроек минификатора из конфигурационного файла.

В версии 2.X мы сразу имеем экземпляр соответствующей фабрики, которая создает экземпляры минификаторов с нужными нам настройками. Соответственно есть 2 интерфейса для таких фабрик: ICssMinifierFactory и IJsMinifierFactory. Фабрики всегда идут в комплекте с минификаторами, т.е. для каждого CSS- или JS-минификатора есть своя фабрика.

В данном примере с помощью классов DefaultCssMinifierFactory и DefaultJsMinifierFactory мы задаем фабрики по умолчанию. Эти фабрики будут использоваться менеджерами минификации, только в случае, если мы не задали фабрики явно. Для явного присвоения экземпляров фабрик менеджерам HTML- и XHTML-минификации используются свойства CssMinifierFactory и JsMinifierFactory:

…
using WebMarkupMin.MsAjax;
using WebMarkupMin.Yui;

namespace TestAspNetMvc5
{
    public class WebMarkupMinConfig
    {
        public static void Configure(WebMarkupMinConfiguration configuration)
        {
            …
            IHtmlMinificationManager htmlMinificationManager = HtmlMinificationManager.Current;
            …
            htmlMinificationManager.CssMinifierFactory = new MsAjaxCssMinifierFactory();
            htmlMinificationManager.JsMinifierFactory = new MsAjaxJsMinifierFactory();

            IXhtmlMinificationManager xhtmlMinificationManager = XhtmlMinificationManager.Current;
            …
            xhtmlMinificationManager.CssMinifierFactory = new YuiCssMinifierFactory();
            xhtmlMinificationManager.JsMinifierFactory = new YuiJsMinifierFactory();
            …
        }
    }
}

Для того, чтобы настройки из файла App_Start/WebMarkupMinConfig.cs вступили в силу, нужно добавить вызов метода WebMarkupMinConfig.Configure в файл Global.asax:

…
using System.Web.Routing;

using WebMarkupMin.AspNet4.Common;

namespace TestAspNetMvc5
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            …
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            WebMarkupMinConfig.Configure(WebMarkupMinConfiguration.Instance);
        }
    }
}

В сайтах ASP.NET Web Pages вместо файлов App_Start/WebMarkupMinConfig.cs и Global.asax для настройки используется только один файл — _AppStart.cshtml:

@using WebMarkupMin.AspNet.Common
@using WebMarkupMin.AspNet.Common.UrlMatchers
@using WebMarkupMin.AspNet4.Common
@using WebMarkupMin.Core
@using WebMarkupMin.MsAjax

@using TestAspNetWebPages3

@{
    …
    #region WebMarkupMin configuration

    WebMarkupMinConfiguration configuration = WebMarkupMinConfiguration.Instance;
    configuration.AllowMinificationInDebugMode = true;
    configuration.AllowCompressionInDebugMode = true;

    IHtmlMinificationManager htmlMinificationManager = HtmlMinificationManager.Current;
    htmlMinificationManager.ExcludedPages = new List<IUrlMatcher>
    {
        new WildcardUrlMatcher("/minifiers/x*ml-minifier"),
        new ExactUrlMatcher("/contact")
    };
    htmlMinificationManager.MinificationSettings = new HtmlMinificationSettings
    {
        RemoveRedundantAttributes = true,
        RemoveHttpProtocolFromAttributes = true,
        RemoveHttpsProtocolFromAttributes = true
    };

    IXhtmlMinificationManager xhtmlMinificationManager = XhtmlMinificationManager.Current;
    xhtmlMinificationManager.IncludedPages = new List<IUrlMatcher>
    {
        new WildcardUrlMatcher("/minifiers/x*ml-minifier"),
        new ExactUrlMatcher("/contact")
    };
    xhtmlMinificationManager.MinificationSettings = new XhtmlMinificationSettings
    {
        RemoveRedundantAttributes = true,
        RemoveHttpProtocolFromAttributes = true,
        RemoveHttpsProtocolFromAttributes = true
    };

    IXmlMinificationManager xmlMinificationManager = XmlMinificationManager.Current;
    xmlMinificationManager.MinificationSettings = new XmlMinificationSettings
    {
        CollapseTagsWithoutContent = true
    };

    DefaultCssMinifierFactory.Current = new MsAjaxCssMinifierFactory(
        new MsAjaxCssMinificationSettings { ColorNames = CssColor.Major }
    );
    DefaultJsMinifierFactory.Current = new MsAjaxJsMinifierFactory(
        new MsAjaxJsMinificationSettings { QuoteObjectLiteralProperties = true }
    );
    DefaultLogger.Current = new MyLogger();

    #endregion
}

Данный пример не нуждается в комментариях, т.к. абсолютно идентичен предыдущему.

Модель конфигурации ASP.NET Core-расширения


Опции ASP.NET-расширения


Класс WebMarkupMinOptions в дополнение к свойствам, наследованным от класса WebMarkupMinConfigurationBase, также имеет свои собственные свойства:
Свойство Тип данных Значение по умолчанию Описание
AllowMinification­InDevelopmentEnvironment Булевский false Разрешает минификацию разметки в development-среде.
AllowCompression­InDevelopmentEnvironment Булевский false Разрешает HTTP-сжатие текстового содержимого в development-среде.

В новой версии ASP.NET отсутствует такое понятие как режим отладки, вместо этого используется понятие текущая среда. Имя текущей среды определяется значением переменной окружения ASPNETCORE_ENVIRONMENT. Этой переменной можно присвоить любое значение, но есть 3 значения, которые были определены разработчиками фреймворка: Development, Staging и Production.

По умолчанию в development-среде отключена минификация и HTTP-сжатие. Чтобы включить их нужно присвоить вышеперечисленным конфигурационным свойствам значение равное true или изменить имя текущей среды на отличное от Development.

Особенности настройки


В начале статьи было показано, как подключить модули (возможности) из пакета WebMarkupMin.AspNetCore1. В этом разделе мы рассмотрим, каким образом можно их настроить. Для настройки мы будем использовать 2 возможности нового ASP.NET: фреймворк Microsoft.Extensions.Options и встроенный механизм внедрения зависимостей. В качестве примера снова воспроизведем настройки из раздела «Модель конфигурации ASP.NET 4.X-расширений»:

using System.Collections.Generic;

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

using WebMarkupMin.AspNet.Common.UrlMatchers;
using WebMarkupMin.AspNetCore1;
using WebMarkupMin.Core;
using WebMarkupMin.NUglify;

namespace TestAspNetCore1
{
    public class Startup
    {
        …
        // This method gets called by the runtime.
        // Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            …
            // Add WebMarkupMin services.
            services.AddWebMarkupMin(options =>
                {
                    options.AllowMinificationInDevelopmentEnvironment = true;
                    options.AllowCompressionInDevelopmentEnvironment = true;
                })
                .AddHtmlMinification(options =>
                {
                    options.ExcludedPages = new List<IUrlMatcher>
                    {
                        new WildcardUrlMatcher("/minifiers/x*ml-minifier"),
                        new ExactUrlMatcher("/contact")
                    };
                    options.MinificationSettings = new HtmlMinificationSettings
                    {
                        RemoveRedundantAttributes = true,
                        RemoveHttpProtocolFromAttributes = true,
                        RemoveHttpsProtocolFromAttributes = true
                    };
                })
                .AddXhtmlMinification(options =>
                {
                    options.IncludedPages = new List<IUrlMatcher>
                    {
                        new WildcardUrlMatcher("/minifiers/x*ml-minifier"),
                        new ExactUrlMatcher("/contact")
                    };
                    options.MinificationSettings = new XhtmlMinificationSettings
                    {
                        RemoveRedundantAttributes = true,
                        RemoveHttpProtocolFromAttributes = true,
                        RemoveHttpsProtocolFromAttributes = true
                    };
                })
                .AddXmlMinification(options =>
                {
                    options.MinificationSettings = new XmlMinificationSettings
                    {
                        CollapseTagsWithoutContent = true
                    };
                })
                .AddHttpCompression()
                ;

            services.AddSingleton<ICssMinifierFactory>(new NUglifyCssMinifierFactory(
                new NUglifyCssMinificationSettings { ColorNames = CssColor.Major }
            ));
            services.AddSingleton<IJsMinifierFactory>(new NUglifyJsMinifierFactory(
                new NUglifyJsMinificationSettings { QuoteObjectLiteralProperties = true }
            ));
            services.AddSingleton<WebMarkupMin.Core.Loggers.ILogger, MyLogger>();
            …
        }
        …
    }
}

Из приведенного выше кода видно, что методы, которые мы использовали для подключения модулей, теперь принимают в качестве параметров делегаты, через которые производится настройка опций.

С помощью внедрения зависимостей мы переопределяем, используемые по умолчанию фабрики минификаторов и логгер. Также из кода видно, что в этом примере мы используем вместо пакета WebMarkupMin.MsAjax его аналог — WebMarkupMin.NUglify, который совместим с .NET Core.

Ссылки


  1. Страница проекта WebMarkupMin на GitHub
  2. Документация WebMarkupMin версии 2.X
  3. Моя статья «WebMarkupMin HTML Minifier – современный HTML-минимизатор для платформы .NET»
  4. Страница проекта NUglify
  5. Статья Виктора Коцюбана «Готовим ASP.NET5, выпуск №3 — внедрение зависимостей по-новому»
  6. Раздел «Dependency Injection» из документации ASP.NET Core.
  7. Раздел «Working with Multiple Environments» из документации ASP.NET Core.

Tags:
Hubs:
+14
Comments8

Articles