До сих пор мы использовали компоненты представлений, которые в качестве результата выводили обычную строку string
, что, строго говоря, не совсем корректно. Обычно, в качестве результата метода Invoke()
/InvokeAsync()
возвращается объект, реализующий интерфейс IViewComponentResult
или, в случае использования асинхронного метода, Task<IViewComponentResult>
. Здесь можно провести аналогию с контроллерами — технически, действие контроллера может возвращать и обычные строки, однако на практике контроллеры всё же возвращают один из объектов, реализующих IActionResult
. Сегодня рассмотрим варианты использования классов, реализующих этот интерфейс для вывода результатов компонента представлений.
IViewComponentResult
В ASP.NET Core MVC содержатся три готовых класса, реализующих интерфейс IViewComponentResult
:
ViewComponentResult
— этот класс используется для генерации представления Razor с возможностью передачи модели. Этот класс мы рассмотрим отдельно в одной из следующих частей.ContentViewComponentResult
— используется для отправки обычного текста, а для создания объекта этого класса может использоваться методContent()
HtmlContentViewComponentResult
— используется для вставки HTML-кода в веб-станицу.
Для демонстрации работы с этими классами используем компонент, который мы написали в предыдущей части. Вот как он должен выглядеть на данный момент:
namespace AspNetMvcComponents.Components { public class DayInfoOptions { public string StartString { get; set; } = string.Empty; public bool FullName { get; set; } = true; } public class DayInfoViewComponent { readonly ILogger<DayInfoViewComponent> _logger; public DayInfoViewComponent(ILogger<DayInfoViewComponent> logger) { _logger = logger; } public string Invoke(DayInfoOptions options) { _logger.LogInformation($"Вызван метод Invoke компонента DayInfo"); string content = options?.StartString ?? string.Empty; if ((options != null)&&(options.FullName == false)) { return $"{content} {DateTime.Now:ddd}"; } else { return $"{content} {DateTime.Now:dddd}"; } } } }
ViewComponentResult
Объекты этого класса возвращают обычный текст. Чтобы им воспользоваться внесем в класс компонента следующие изменения:
public class DayInfoViewComponent { readonly ILogger<DayInfoViewComponent> _logger; public DayInfoViewComponent(ILogger<DayInfoViewComponent> logger) { _logger = logger; } public IViewComponentResult Invoke(DayInfoOptions options) { _logger.LogInformation($"Вызван метод Invoke компонента DayInfo"); string content = options?.StartString ?? string.Empty; if ((options != null) && (options.FullName == false)) { content = $"{content} {DateTime.Now:ddd}"; } else { content = $"{content} {DateTime.Now:dddd}"; } return new ContentViewComponentResult(content); } }
Здесь мы, по ути, поменяли только тип возвращаемого результата методом Invoke()
со string
на IViewComponentResult
. Соответственно, и в самом методе мы передаем не строку, а новый объект типа ContentViewComponentResult
:
return new ContentViewComponentResult(content);
В остальном, работа компонента будет такая же, как и была раньше — на главной странице приложения появится информация о дне недели:
@addTagHelper *, AspMvcComponents @using AspMvcComponents.Components <vc:day-info options="@(new DayInfoOptions(){StartString="День недели:", FullName=true})"> </vc:day-info>
Для того, чтобы воспользоваться методом Content()
для создания объекта типа ContentViewComponentResult
необходимо, чтобы наш компонент был наследником класса ViewComponent
. Воспользуемся этим методом, а, заодно, немного сократим код нашего компонента:
public class DayInfo: ViewComponent { readonly ILogger<DayInfo> _logger; public DayInfo(ILogger<DayInfo> logger) { _logger = logger; } public IViewComponentResult Invoke(DayInfoOptions options) { _logger.LogInformation($"Вызван метод Invoke компонента DayInfo"); string content = options?.StartString ?? string.Empty; if ((options != null) && (options.FullName == false)) { content = $"{content} {DateTime.Now:ddd}"; } else { content = $"{content} {DateTime.Now:dddd}"; } return Content(content); } }
В принципе, можно было бы не менять название компонента, но зачем нам лишний текст? ASP.NET Core MVC и так прекрасно поймет, что DayInfo
— это компонент ViewComponent
. Опять же, на результат вызова компонента в приложении это никак не повлияет.
HtmlContentViewComponentResult
Объекты этого класса возвращают HTML-содержимое. В отличие от предыдущего класса, для создания объектов типа HtmlContentViewComponentResult
у базового класса ViewComponent
не предусмотрено специальных методов. Однако, проблем из-за этого не возникает. Перепишем код метода Invoke()
следующим образом:
public class DayInfo: ViewComponent { readonly ILogger<DayInfo> _logger; public DayInfo(ILogger<DayInfo> logger) { _logger = logger; } public IViewComponentResult Invoke(DayInfoOptions options) { _logger.LogInformation($"Вызван метод Invoke компонента DayInfo"); string content = options?.StartString ?? string.Empty; if ((options != null) && (options.FullName == false)) { content = $"<b>{content}</b> <span style=\"color:red\">{DateTime.Now:ddd}</span>"; } else { content = $"<b>{content}</b> <span style=\"color:red\">{DateTime.Now:dddd}</span>"; } return new HtmlContentViewComponentResult(new HtmlString(content)); } }
Конструктор HtmlContentViewComponentResult
в качестве параметра принимает объект класса, реализующего интерфейс IHtmlContent
. Одним из таких классов является класс HtmlString
, объект которого мы и передаем в конструктор. В итоге, после запуска приложения мы увидим следующий результат:
Итого
Несмотря на то, что методы Invoke()
и InvokeAsync()
могут возвращать результат любого типа, для генерации контента желательно использовать классы, реализующие интерфейс IViewComponentResult
. В ASP.NET Core MVC такими классами являются ViewComponentResult
, ContentViewComponentResult
и HtmlContentViewComponentResult.