Создание пользовательских тегов в Asp.net Mvc для расширенной композиции просмотра
Введение в пользовательские теги помощников в ASP.NET MVC
Современные веб-приложения требуют чистого, поддерживающегося и многоразового кода просмотра. ASP.NET Core MVC предоставляет помощники тегов в качестве мощного серверного механизма для преобразования и генерации разметки HTML непосредственно в представлениях Razor. В то время как фреймворк поставляется с богатым набором встроенных помощников тегов для форм, проверки, кэширования и рендеринга, ориентированного на среду, проекты в реальном мире часто требуют специализированных компонентов, которые инкапсулируют логику и шаблоны представления, специфичные для домена. Создание помощников тегов позволяет расширить синтаксис Razor с помощью ваших собственных элементов и атрибутов HTML, что приводит к созданию композиции просмотра, которая является одновременно экспрессивной и последовательной.
Перемещая сложное поколение HTML и условную логику в многоразовые классы помощников тегов, вы отделяете проблемы презентации от разметки просмотра, улучшаете проверяемость и уменьшаете дублирование в больших кодовых базах. Эта статья предоставляет всеобъемлющее руководство по созданию пользовательских помощников тегов в ASP.NET Core MVC, охватывая все, от базовой структуры класса и связывания атрибутов до продвинутых сценариев, таких как впрыск зависимости, асинхронная обработка и компоненты помощников тегов. Каждый раздел включает практические примеры и лучшие практики, которые помогут вам интегрировать эту технику в ваш повседневный рабочий процесс разработки.
Понять помощников тегов в ASP.NET Core
Помощники тегов - это серверные компоненты, которые участвуют в рендеринге элементов HTML в представлениях Razor. Они позволяют прикреплять код C# к конкретным элементам HTML или пользовательским именам элементов, преобразуя разметку перед отправкой клиенту. В отличие от помощников HTML (которые используют методы вызовов, такие как ), помощники тегов работают, сопоставляя с существующим синтаксисом HTML, делая представления более естественными для дизайнеров и фронтенд-разработчиков.
Например, встроенный помощник тега объединяет контроллер и атрибуты действия в правильный URL. Помощники тегов могут изменять атрибуты, заменять весь элемент, добавлять или удалять классы CSS и даже вводить дополнительный HTML. Они запускаются во время конвейера выполнения просмотра Razor и имеют полный доступ к текущему контексту запроса, данным модели и зарегистрированным службам.
Модель исполнения Server-Side
Когда скомпилируется представление Razor, помощники тегов обнаруживаются через сборки и директивы . Фреймворк оценивает каждый элемент HTML по всем зарегистрированным помощникам тегов, ссылаясь на их методы или , когда найдено совпадение. Это происходит до того, как генерируется конечный вывод HTML, что позволяет помощникам тегов динамически обогащать или заменять элементы.
Основные отличия от других видов инструментов композиции
- HTML Helpers: Требуют вызовы метода C# внутри блоков Razor (), которые могут нарушить поток, ориентированный на HTML.
- Части: Хорошо подходит для повторного использования статических фрагментов разметки, но не имеет возможности программно изменять структуру на основе логики на стороне сервера без дополнительных моделей просмотра.
- Просмотр компонентов: Идеально подходит для сложных, управляемых данными виджетов с их собственной логикой и рендерингом, но они требуют отдельного класса и синтаксиса вызова .
Зачем создавать пользовательские помощники тегов?
В то время как встроенные помощники по тегам охватывают многие распространенные сценарии, пользовательские помощники по тегам предоставляют уникальные преимущества, которые непосредственно улучшают качество кода и производительность разработчиков.
- Encapsulate Complex Markup Patterns — Повторяющийся шаблон HTML (например, структурированные компоненты карт, таблицы данных или стилизованные кнопки) может быть инкапсулирован в один пользовательский элемент. Изменения распространяются по всему приложению, обновляя один класс.
- Согласованность проектирования Enforce — пользовательский или помощник тега может обеспечить согласованные классы CSS, атрибуты доступности и шаблоны связывания данных, уменьшая вероятность несоответствий пользовательского интерфейса.
- Улучшить читаемость просмотра — Вместо вложенных и условных блоков C#, один тег с несколькими атрибутами намного проще сканировать и поддерживать.
- Возможность тестирования блоков логики просмотра — Поскольку помощники тегов — это простые классы, которые производят HTML, вы можете писать единичные тесты для проверки сгенерированного вывода для различных входов, чего трудно достичь с помощью встроенного кода Razor.
- Увеличить многоразовую возможность в проектах — библиотека пользовательских помощников тегов может быть упакована в качестве компонента NuGet и совместно использоваться в нескольких решениях, продвигая последовательный набор инструментов пользовательского интерфейса.
Создание базового помощника по пользовательским тегам
Каждый пользовательский помощник тегов наследует от класса (или реализует напрямую) и украшен атрибутом , чтобы указать, какой элемент HTML или атрибут он нацелен.Ядро логики живет внутри метода (или его асинхронного аналога ).
Шаг 1: Определите класс помощников по тегам
Создайте новый класс C# в своем проекте, как правило, внутри папки . Наследуйте от и примените атрибут с именем элемента, которое вы намерены использовать в своих представлениях.
[HtmlTargetElement("custom-card")]
public class CustomCardTagHelper : TagHelper
{
public string Title { get; set; }
public string CssClass { get; set; } = "card-default";
public override void Process(TagHelperContext context, TagHelperOutput output)
{
// Replace the custom tag with a div and add the desired structure
output.TagName = "div";
output.Attributes.SetAttribute("class", $"card {CssClass}");
// Build inner content
output.Content.SetHtmlContent(
$@"<div class=""card-header"">{Title}</div>
<div class=""card-body"">
{output.Content.GetContent()}
</div>"
);
}
}
Шаг 2: Понимание TagHelperContext и TagHelperOutput
предоставляет информацию о текущем элементе и его атрибутах. позволяет изменять имя, атрибуты и контент элемента. также можно использовать для простого текста или для исходного HTML. Для сохранения исходного контента (например, детских элементов в пользовательском теге), вы звоните , как показано выше.
Шаг 3: Зарегистрируйте помощника по тегам
Если помощники по тегу находятся в той же сборке, что и приложение, если помощники по тегу находятся в отдельной библиотеке классов, вы должны добавить директиву в :
@addTagHelper *, MyApp.TagHelpers
Формат или wildcard с , чтобы включить всех помощников тегов из этой сборки. также можно использовать, чтобы исключить конкретных помощников.
Шаг 4: Используйте тег-помощник в бритвенном виде
С регистрацией на месте вы можете использовать пользовательский элемент:
<custom-card title="Welcome" css-class="card-primary">
This is the body content
</custom-card>
Это приводит к:
<div class="card card-primary">
<div class="card-header">Welcome</div>
<div class="card-body">
This is the body content
</div>
</div>
Advanced Tag Helper Techniques (Техника помощи)
Использование атрибутов и свойств, связывающих
Помощники по пользовательскому тегу могут принимать несколько атрибутов, включая сложные типы и выражения моделей. Например, помощник по тегу, который отображает ввод формы, может связывать свойство с выражением модели:
[HtmlTargetElement("email-input")]
public class EmailInputTagHelper : TagHelper
{
[HtmlAttributeName("asp-for")]
public ModelExpression For { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "input";
output.Attributes.SetAttribute("type", "email");
output.Attributes.SetAttribute("id", For.Name);
output.Attributes.SetAttribute("name", For.Name);
output.Attributes.SetAttribute("value", For.Model?.ToString() ?? "");
}
}
атрибут отображает свойство C# на конкретное имя атрибута HTML. Использование даёт вам доступ к метаданным модели для полной интеграции с валидацией и логикой отображения.
Асинхронная обработка
Если ваш помощник по тегу должен выполнять операции ввода/вывода (например, извлекать данные из базы данных), вместо этого переопределите :
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var data = await _someService.GetDataAsync();
output.Content.SetHtmlContent(data);
}
Инъекция зависимостей в Tag Helpers
Тег-помощники поддерживают инъекцию конструктора, как и любой другой сервис MVC. Просто добавьте свою зависимость от конструктора, и контейнер DI решит ее:
public class UserProfileTagHelper : TagHelper
{
private readonly IUserService _userService;
public UserProfileTagHelper(IUserService userService)
{
_userService = userService;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var user = await _userService.GetCurrentUserAsync();
// render user profile markup
}
}
Обратите внимание, что помощники по тегам являются временными по умолчанию; для каждого использования в представлении создается новый экземпляр.
Компоненты-помощники для глобальной HTML-инъекции
Введенные в ASP.NET Core 2.1, Tag Helper Components позволяют вводить разметку в каждый ответ по всему миру, обычно используемый для объединения скриптов, стилей или аналитики. Создать класс, реализующий и зарегистрировать его в :
public class GlobalScriptTagHelperComponent : TagHelperComponent
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (output.TagName == "body" && output.Attributes.ContainsName("data-scripts"))
{
output.PostContent.AppendHtml("<script src='/js/global.js'></script>");
}
}
}
// In Startup.ConfigureServices
services.AddTransient<ITagHelperComponent, GlobalScriptTagHelperComponent>();
Практические примеры для просмотра композиции
1.Условный помощник Wrapper Tag
Обертывающее содержимое с дополнительным элементом только при условии выполнения условия, полезное для адаптивной компоновки контейнеров:
[HtmlTargetElement("if-wrapper")]
public class IfWrapperTagHelper : TagHelper
{
public bool Condition { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (!Condition)
{
// Remove the wrapping element, output only the child content
output.TagName = null;
output.Content.SetContent(output.Content.GetContent());
}
else
{
output.TagName = "div";
output.Attributes.SetAttribute("class", "wrapper");
}
}
}
2. Изображение с ленивой нагрузкой и сксетом
Создайте помощника, который генерирует теги с атрибутом и несколькими источниками:
[HtmlTargetElement("lazy-image")]
public class LazyImageTagHelper : TagHelper
{
public string Src { get; set; }
public string Srcset { get; set; }
public string Alt { get; set; }
public string CssClass { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "img";
output.Attributes.SetAttribute("src", Src);
if (!string.IsNullOrEmpty(Srcset))
output.Attributes.SetAttribute("srcset", Srcset);
output.Attributes.SetAttribute("alt", Alt);
output.Attributes.SetAttribute("loading", "lazy");
if (!string.IsNullOrEmpty(CssClass))
output.Attributes.SetAttribute("class", CssClass);
}
}
3. Резюме валидации с использованием пользовательской структуры
Вместо того, чтобы использовать встроенный помощник проверки тегов, создайте тот, который добавляет пользовательские значки и стиль:
[HtmlTargetElement("custom-validation-summary")]
public class CustomValidationSummaryTagHelper : TagHelper
{
[HtmlAttributeName("asp-validation-summary")]
public ValidationSummary ValidationSummary { get; set; }
[ViewContext]
public ViewContext ViewContext { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var viewData = ViewContext.ViewData;
var errors = viewData.ModelState.Where(s => s.Value.Errors.Count > 0).SelectMany(s => s.Value.Errors).ToList();
if (errors.Count == 0)
{
output.SuppressOutput();
return;
}
output.TagName = "div";
output.Attributes.SetAttribute("class", "alert alert-danger");
var list = new StringBuilder();
list.Append("<ul class='mb-0'>");
foreach (var error in errors)
{
list.Append($"<li><strong>Error:</strong> {error.ErrorMessage}</li>");
}
list.Append("</ul>");
output.Content.SetHtmlContent(list.ToString());
}
}
Лучшие практики для создания тегов
- Сохраняйте логику C# минимальной — помощники по тегам предназначены для преобразования презентации, а не бизнес-логики.
- Любовь для ввода/вывода — Даже если ваша текущая реализация синхронна, использование облегчает добавление вызовов асинхронизации позже без внесения изменений.
- Используйте описательные имена для пользовательских элементов — следуйте соглашению, как или , чтобы избежать столкновений с будущими стандартами HTML.
- Перенос — Для внутренних свойств, которые не должны быть установлены из разметки, пометьте их этим атрибутом.
- Проверить сгенерированный HTML — Написать единичные тесты, которые инстанцируют помощника тега, вызвать и проверить вывод с использованием утверждений.
- Рассматривайте доступность — Добавьте атрибуты ARIA и поддержку клавиатуры, где это уместно.
Общие подводные камни и устранение неполадок
- Не обнаруженный помощник тега — Убедитесь, что директива указывает на правильную сборку.
- Имена атрибутов, не соответствующие — Используйте атрибут для отображения имен свойств C# на имена атрибутов HTML.
- Контент не отображает — Если вы звоните перед извлечением содержимого для ребенка, вы теряете исходный внутренний HTML.
- Множественные помощники тегов, нацеленные на один и тот же элемент — Порядок выполнения по умолчанию следует алфавитному порядку, но может управляться свойством .
- Проблемы с инъекцией зависимости — помощники тегов не ограничены одним тегом. Если вы вводите ограниченный сервис, убедитесь, что помощник тега потребляется в том же объеме HTTP-запроса (обычно это так).
Интеграция пользовательских помощников тегов в существующую кодовую базу
Принятие пользовательских помощников тегов не требует полного переписывания. Вы можете начать с рефакторинга самых повторяющихся шаблонов - таких как кнопки, карты или таблицы данных - в помощники тегов. Со временем вы создадите библиотеку, которая станет единственным источником истины для ваших компонентов пользовательского интерфейса. объедините помощников тегов с другими инструментами композиции, такими как части и компоненты просмотра, для максимальной гибкости. Например, компонент просмотра может получать сложные данные, а затем передать его помощнику тегов для рендеринга окончательного HTML.
Внешние ресурсы и дальнейшее чтение
- Введение в тег Helpers in ASP.NET Core (официальная документация)
- Авторизация тегов Помощники (официальная документация)
- Тэг вспомогательных компонентов (официальная документация)
- Серия Эндрю Локка на пользовательских помощниках тегов
Заключение
Пользовательские помощники тегов представляют собой значительную эволюцию в том, как разработчики составляют представления в ASP.NET Core MVC. Позволив вам определить свои собственные элементы HTML и атрибуты, которые выполняют логику на стороне сервера, они преодолевают разрыв между удобной для дизайнера разметкой и управлением программистом. От простых генераторов кнопок до сложных, известных государству компонентов, которые интегрируются с впрыском зависимости, помощники тегов позволяют вам создавать поддерживаемые, тестируемые и последовательные пользовательские интерфейсы. Начните с малого - перефактор один повторяющийся шаблон в помощник тегов - и вы скоро увидите, как эта техника преобразует ваш слой просмотра в лучшую сторону.