Подготовка Asp.net Core: Поговорим О Нестандартных Подходах При Работе С Представлениями

Продолжаем нашу рубрику на тему ASP.NET Core публикацией от Дмитрия Сикорского ( ДмитрийСикорский ) — руководитель компании «Убраянцы» из Украины.

В своей следующей статье Дмитрий рассказывает о своем опыте нестандартной работы с представлениями в ASP.NET Core. Предыдущие статьи рубрики всегда можно прочитать по ссылке.

#aspnetcolumn — Владимир Юнев В последнее время я много работал над своей модульной платформой для ASP.NET 5 (теперь ASP.NET Core 1.0).

В рамках этого проекта мне приходилось решать различные задачи, и одна из них — работа с представлениями, которые находятся либо просто в нестандартных местах, либо вообще вне основной сборки веб-приложения.

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



Подготовка ASP.NET Core: поговорим о нестандартных подходах при работе с представлениями



Представления в нестандартных местах основной сборки веб-приложения.

Если по какой-то причине ваши представления оказались за пределами назначенной им папки «Представления» (но все равно остались внутри основного проекта приложения), вам необходимо будет сообщить об этом Razor. Если раньше для этого приходилось писать класс, производный от RazorViewEngine, то теперь это стало немного проще.



Подготовка ASP.NET Core: поговорим о нестандартных подходах при работе с представлениями

Совет! Вы можете попробовать сами или загрузив исходный код с GitHub. https://github.com/DmitrySikorsky/AspNet5Views .

Для начала реализуем интерфейс IViewLocationExpander (напомню, что «{1}» в строковой константе будет заменено на имя контроллера, а «{0}» на имя действия):
  
  
  
  
   

public class CustomViewLocationExpander : IViewLocationExpander { public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) { List<string> expandedViewLocations = new List<string>(); expandedViewLocations.AddRange(viewLocations); expandedViewLocations.Add("/Views/SomeExtraFolder/{1}/{0}.

cshtml"); return expandedViewLocations; } public void PopulateValues(ViewLocationExpanderContext context) { } }

Затем «регистрируем» экземпляр полученного класса в методе ConfigurationServices:

services.Configure<RazorViewEngineOptions>(options => { options.ViewLocationExpanders.Add(new CustomViewLocationExpander()); } );

Вот и все, теперь Razor примет к сведению наш новый макет представления.



Представления ресурсов в других сборках

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

Для того, чтобы представления помещались в сборку в качестве ресурсов, нужно добавить в project.json соответствующего проекта следующую строку (на самом деле, таким образом в ресурсы превращаются не только представления): "resource": "Просмотры/**" Чтобы такие представления впоследствии обнаруживались Razor, необходимо реализовать интерфейс IFileProvider и назначить экземпляр результирующего класса соответствующему свойству в методе ConfigurationServices в основном проекте:

services.Configure<RazorViewEngineOptions>(options => { options.FileProvider = this.GetFileProvider(this.applicationBasePath); } );

Метод GetFileProvider создает экземпляр нашего класса CompositeFileProvider, который по сути просто объединяет несколько разных поставщиков (в нашем случае — физические файлы в основной папке проекта и ресурсы из указанных сборок).

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

Например, вы не можете использовать типы, определенные в проекте, в котором находятся сами представления.

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

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

Следующий подход решает эту проблему.

(На самом деле, насколько я понимаю, это еще можно решить.

Я обсуждал этот вопрос здесь: https://github.com/aspnet/Mvc/issues/3413 , но дальше этого обсуждения дело еще не пошло.

)

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

Пожалуй, если вам нужно разместить представления в разных сборках вашего приложения (например, чтобы разделить его на независимые части и упростить обслуживание и совместную работу), то это лучший вариант. Как и в предыдущем случае, при использовании предварительно скомпилированных представлений не нужно копировать их на сервер при публикации, что существенно ускоряет процесс (вместо множества cshtml-файлов копируется только один dll-файл).

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

Чтобы заставить компилятор скомпилировать представления, просто создайте класс RazorPreCompilation в соответствующем проекте, унаследуйте его от RazorPreCompileModule, переопределите его метод EnablePreCompilation, чтобы он возвращал true, и, наконец, поместите его в папку \Compiler\PreProcess:

public class RazorPreCompilation : RazorPreCompileModule { protected override bool EnablePreCompilation(BeforeCompileContext context) => true; }

В основном проекте приложения, чтобы сообщить Razor, что он должен использовать предварительно скомпилированные представления из других сборок, вы просто передаете набор этих сборок соответствующему методу:

services.AddMvc() .

AddPrecompiledRazorViews( new Assembly[] { Assembly.Load(new AssemblyName("AspNet5Views.PrecompiledViews")) } );

Этого достаточно, чтобы все заработало.

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



выводы

В общем, все довольно просто.

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

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

Я подготовил небольшой тестовый проект, чтобы вы могли сами попробовать все описанное в этой статье: https://github.com/DmitrySikorsky/AspNet5Views .



Авторам

Друзья, если вы заинтересованы поддержать рубрику собственным материалом, пишите мне на почту [email protected] чтобы обсудить все детали.

Мы ищем авторов, которые смогут интересно рассказать об ASP.NET и других темах.



Подготовка ASP.NET Core: поговорим о нестандартных подходах при работе с представлениями



об авторе

Сикорский Дмитрий Александрович Компания «Убраянцы» (г.

http://ubrainians.com/ ) Владелец, менеджер ДмитрийСикорский

Теги: #.

NET #asp.net core #ASP.NET #ASP #ASP #Views #Views #razor ##aspnetcolumn ##aspnetcolumn

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.