Статьи

Пакетирование в ASP.NET

ASP.NET — это технологический стек, заработавший репутацию в повышении производительности. С выпуском ASP.NET 4.5 стек расширил границы, добавив автоматическое пакетирование веб-ресурсов, что делает его простым и гибким в работе.

В этой статье я хотел бы взглянуть на пакетирование в ASP.NET. Я расскажу, как легко настроить пакетирование в любом проекте ASP.NET.

В ASP.NET 4.5 платформа получила новое пространство имен под названием System.Web.Optimization . Посмотрим, как это работает.

Настроить

Для этого урока я начинаю с пустого проекта ASP.NET MVC. Таким образом, я могу сосредоточиться на том, что нужно для настройки автоматического комплектования. Те же основные шаги применимы и к веб-формам. Я буду использовать Razor и C # для этого урока.

После нажатия на приглашения для нового проекта, добавьте эти пакеты в Консоль диспетчера пакетов NuGet:

 PM> Install-Package Microsoft.AspNet.Mvc PM> Install-Package jQuery PM> Install-Package Bootstrap PM> Install-Package Microsoft.AspNet.Optimization 

Я бы хотел, чтобы вы обратили внимание на пакет NuGet под названием Microsoft.AspNet.Optimization . Если вы работаете над существующим проектом ASP.NET, этот пакет NuGet облегчит вашу работу. После того, как он будет установлен, все, что вам нужно сделать, это настроить остальную часть водопровода.

С платформой веб-оптимизации вы получаете инструменты для автоматизации управления веб-ресурсами. Вы можете найти официальную документацию на MSDN .

Теперь добавьте папку с именем App_Start в ваше основное решение, если у вас ее еще нет. Нам нужно настроить пакетирование, добавив этот статический класс.

 public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { } } 

Маршрутизация настроена для любого существующего проекта, поэтому я не буду включать его в этот учебник.

Чтобы сообщить платформе ASP.NET о наших недавно настроенных пакетах, сделайте это в Global.asax :

 public class Global : HttpApplication { protected void Application_Start(object sender, EventArgs e) { BundleConfig.RegisterBundles(BundleTable.Bundles); } } 

ASP.NET — это управляемая событиями среда. Если вы можете себе представить, сервер IIS бездействует, ожидая событий. В этом случае это будут запросы браузера клиента через HTTP. Когда ваше приложение запускается впервые, ASP.NET вызывает Application_Start в Global.asax . Внутри Application_Start вы можете войти и настроить конкретные пакеты, которые вы хотите использовать в своем приложении.

В конце концов, мое решение настроено так:

Настройка решения

Смотреть трафик

Пришло время добавить пакеты и посмотреть, как они работают внутри браузера. Добавьте это к BundleConfig который является статическим классом, который я указал выше:

 public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new StyleBundle("~/bundle/bootstrap-styles") .Include("~/Content/bootstrap.css") .Include("~/Content/bootstrap-theme.css") .Include("~/Content/Site.css")); bundles.Add(new StyleBundle("~/bundle/Home/Index-styles") .Include("~/Content/StyleSheet1.css") .Include("~/Content/StyleSheet2.css") .Include("~/Content/StyleSheet3.css")); bundles.Add(new ScriptBundle("~/bundle/bootstrap-scripts") .Include("~/Scripts/bootstrap.js") .Include("~/Scripts/jquery-{version}.js") .Include("~/Scripts/modernizr-{version}.js")); bundles.Add(new ScriptBundle("~/bundle/Home/Index-scripts") .Include("~/Scripts/JavaScript1.js") .Include("~/Scripts/JavaScript2.js") .Include("~/Scripts/JavaScript3.js")); } } 

Ваши конкретные потребности будут другими. Приведенный выше метод принимает BundleCollection в качестве параметра. Обратите внимание, что это BundleTable.Bundles от Global.asax . Затем я создаю наборы стилей и сценариев в соответствии со своими конкретными потребностями.

Я использую подстановочный знак {version} чтобы сказать механизму связывания захватить любую версию jQuery, которая есть в моем решении. В конфигурации Release jQuery .min.js добавляется в комплект, но не в Debug. Это дает мне гибкость в моей среде разработки при работе с jQuery. Я могу поменять местами разные версии jQuery, и мои настройки пакета не будут заботиться. Этот же метод подстановочных знаков применяется к любой другой клиентской библиотеке.

Поскольку я могу создавать свои собственные пакеты, я могу адаптировать ресурсы, которые мне нужны для конкретных экранов.

Я разместил пакеты ~/bundle/bootstrap-styles и ~/bundle/bootstrap-scripts внутри главной страницы _Layout.cshtml . Так как он многословный с большим количеством начальной загрузки, я опущу его в этом уроке.

Вот как выглядит моя страница Index.cshtml Razor:

 @{ ViewBag.Title = "Index"; } @Styles.Render("~/bundle/Home/Index-styles") <h2>Hello World</h2> <p> Be sure to check out glyphs like these: <span class="glyphicon glyphicon-plus"></span>. </p> @Scripts.Render("~/bundle/Home/Index-scripts") 

Легко. После того, как пакеты определены, я помещаю их в свое приложение в любом месте. Я следую простому соглашению {Controller}/{Action} для определения пакетов. Вы можете сделать то же самое.

Если вы обнаружите, что вы получаете ошибки страницы Razor, потому что не удается найти Styles.Render или Scripts.Render . Обязательно включите это в ваш Web.config который находится в папке Views .

 <system.web.webPages.razor> ... <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> ... <add namespace="System.Web.Optimization"/> </namespaces> </pages> </system.web.webPages.razor> </system.web.webPages.razor> 

Это говорит механизму Razor включить System.Web.Optimization имен System.Web.Optimization при рендеринге динамического HTML. Вы также можете включить любое другое пространство имен, необходимое для вашего конкретного проекта. Это избавит вас от необходимости полностью квалифицировать каждое расширение Razor.

При всем этом давайте посмотрим на сетевой трафик:

Unbundled Network Traffic

Красный означает, что браузер бездействует. Желтый — это время, которое браузер делает для запроса. Синий — это время, которое требуется для получения ответа от сервера. В большинстве современных браузеров вы можете выполнять около шести запросов на домен за раз. Если вам нужно больше шести, браузер будет ждать. Запрос в самом верху — это динамический HTML, который я должен получить с сервера.

Почему это важно?

Чтобы использовать аналогию, вы можете думать о своем внутреннем языке программирования C # как о космическом корабле. Вы получаете скорость и возможности изменения времени, когда вы путешествуете. Пока ваш сервер работает локально на вашем сервере, вы можете предполагать высокую производительность. Но когда конвейер запросов достигает HTTP, это совсем другая история.

Я хотел бы думать о сетевом протоколе HTTP как о корзине мулов. Независимо от того, сколько оптимизации вы выполняете на бэкэнде, вы всегда можете рассчитывать на то, что HTTP работает медленно. Таким образом, как и в повозке с мулом, перед загрузкой через город хорошо бы загрузить ее достаточным количеством провизии. Повторное отключение сервера — верный способ снизить производительность.

HTTP-запросы стоят дорого. Ваша основная задача — сократить количество обходов по HTTP.

Включение

Чтобы включить связывание в платформе, все, что вам нужно сделать, это изменить файл Web.config в папке вашего решения.

 <compilation debug="false" targetFramework="4.5" /> 

Вы также можете жестко закодировать это с помощью:

 BundleTable.EnableOptimizations = true; 

Когда вы жестко программируете его в C #, это имеет приоритет над Web.config . В типичной настройке вы можете использовать преобразование Web.config чтобы включить его в режиме выпуска. Нет необходимости пытаться отлаживать минимизированный код JavaScript.

Давайте посмотрим на связанный трафик:

Пакетный сетевой трафик

Прекрасный. Ресурсы начинают загружаться, как только загружается динамический HTML. Здесь я в полной мере использую возможности браузера, поскольку у меня ровно шесть ресурсов. Обратите внимание, что последний ресурс не запускается, пока не будут отображены все остальные ресурсы. Это потому, что это веб-шрифт, и он происходит из пакета CSS.

Кэширование

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

Например, вот как выглядят наши связанные ресурсы:

 /bundle/bootstrap-styles?v=epi1k_G4Tsd0o4dXIOJcBg5gefY7ieCSx0AUDxqm78U1 /bundle/Home/Index-styles?v=uxFDb5XiuKadZOyd2DKyzUU-mh3OUTNuikUDUlL7e_Q1 /bundle/Home/Index-scripts?v=Giv511fvuZRlJKLjJDPqmIxOhmtht9zFlW7lvvTMf0Y1 /bundle/bootstrap-scripts?v=j4YIBwFVDdtvOMWp63GzkWLSoYrcw0ertU_njZLALnk1 

Строка запроса, добавляемая в конце, является хешем от конкретного содержимого каждого пакета. Когда содержимое внутри пакета изменяется, хеш, добавленный в качестве строки запроса, также изменится.

Вы можете проверить заголовки HTTP.

Кэширование заголовков HTTP

HTTP-заголовок Expires настроен на истечение одного года в будущем.

Вывод

ASP.NET — это крутая технология, разработанная для облегчения вашей жизни. Что мне больше всего нравится в этом, так это то, как движок отображает теги <link> и <style> для вас. Что меня всегда беспокоило, так это то, как эти теги оказываются повсюду. Создание кошмара для управления веб-ресурсами.

Надеюсь, вы сможете увидеть, насколько легко добавить автоматизированный пакет в ваш проект. Для простой демонстрации, которая демонстрирует основную технику, обязательно ознакомьтесь с GitHub .

Как вы нашли функции связывания ASP.NET? Есть ли у вас какие-либо советы по улучшению производительности?