До сих пор мы использовали компоненты представлений, которые в качестве результата выводили обычную строку 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.

