View Component может извне получаит различные данные. Во-первых, View Component может принимать некоторые параметры, которые ему передаются при вызове компонента. Во-вторых, класс View Component, также как и другие классы в ASP.NET Core, может получать зависимости из провайдера сервисов через механизм dependency injection. Рассмотрим, оба случая передачи данных.
Через параметры метода Invoke/InvokeAsync мы можем получать извне некоторые данные. Например, определим следующий компонент:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Components { [ViewComponent] public class Timer { public string Invoke(bool includeSeconds) { if (includeSeconds) return $"Текущее время: {DateTime.Now.ToString("hh:mm:ss")}"; else return $"Текущее время: {DateTime.Now.ToString("hh:mm")}"; } } }
В методе Invoke компонент принимает один параметр - includeSeconds, который представляет тип bool. Если этот параметр равен true, то строка со временем также содерджит секунды, если параметр равен false - секунды опускаются.
Теперь обратимся к этому компоненту в представлении:
@addTagHelper *, MvcApp <p>С секундами: <br /> @await Component.InvokeAsync("Timer", new { includeSeconds=true}) </p> <p>Без секунд: <br /> <vc:timer include-seconds="false"></vc:timer> </p>
Для передачи значений параметрам метода Invoke/InvokeAsync в методе Component.InvokeAsync()
в качестве второго аргумента указывается
анонимный объект, который устанавливает значения всех параметров.
При использовании тег-хелпера параметры компонента определяются как атрибуты тега, которым присваивается необходимое значение. Причем если у нас исползуется camelcase, при котором каждое подслово в составе составного слова пишется с большой буквы, например, includeSeconds, то в названии атрибута все подслова разделяются дефисом и начинаются со строчной буквы.
Результат выполнения:
Подобным образом мы можем использовать и больщее количество параметров. Например, изменим код компонента следующим образом:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Components { [ViewComponent] public class Timer { public string Invoke(bool includeSeconds, bool format24) { string time; DateTime now = DateTime.Now; if (format24) // если 24-часовой формат time = now.ToString("HH:mm"); else // если 12-часовой формат time = now.ToString("hh:mm"); if (includeSeconds) // если надо добавить секунды time = $"{time}:{now.Second}"; return $"Текущее время: {time}"; } } }
Новый параметр format24
указывает в каком формате будет выводиться время - в 24-часовом или в 12 часовом.
Обратимся к компоненту в представлении:
@addTagHelper *, MvcApp <p>24 часовой формат с секундами: <br /> @await Component.InvokeAsync("Timer", new { includeSeconds=true, format24=true}) </p> <p>12 часовой формат без секунд: <br /> <vc:timer include-seconds="false" format24="false"></vc:timer> </p> <p> 24 часовой формат без секунд: <br /> <vc:timer include-seconds="false" format24="true"></vc:timer> </p>
При необходимости для параметров во View Component можно устанавить значения по умолчанию:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Components { [ViewComponent] public class Timer { public string Invoke(bool includeSeconds = false, bool format24 = true) { string time; DateTime now = DateTime.Now; if (format24) // если 24-часовой формат time = now.ToString("HH:mm"); else // если 12-часовой формат time = now.ToString("hh:mm"); if (includeSeconds) // если надо добавить секунды time = $"{time}:{now.Second}"; return $"Текущее время: {time}"; } } }
То есть по умолчанию применяется 24-часовой формат, а секунды не включаются.
Попробуем при обращении к компоненту опустить некоторые параметры (ведь теперь они имеют значения по умолчанию):
<p> Все значения по умолчанию: <br /> @await Component.InvokeAsync("Timer") </p> <p> 12-часовой формат: <br /> @await Component.InvokeAsync("Timer", new { format24 = false }) </p> <p> С секундами: <br /> @await Component.InvokeAsync("Timer", new { includeSeconds = true }) </p>
При этом View Component может принимать более сложные данные. Например, определим в проекте папку Models следующий класс Person:
namespace MvcApp.Models { public record class Person(string Name, int Age); }
В папке Components определим новый View Component - класс PersonInfoViewComponent:
using MvcApp.Models; // пространство имен класса Person namespace MvcApp.Components { public class PersonInfoViewComponent { public string Invoke(Person Person) { return $"Name: {Person.Name} Age: {Person.Age}"; } } }
Данный компонент принимает объкт Person и возвращает его данные в виде строки.
Теперь применим данный компонент в представлении:
@addTagHelper *, MvcApp @using MvcApp.Models <!-- пространство имен модели Person--> @{ Person tom = new("Tom", 37); Person alice = new("Alice", 32); } <p> @await Component.InvokeAsync("PersonInfo", new { person = tom}) </p> <p> <vc:person-info person="alice"></vc:person-info> </p>
Результат работы приложения:
Как и другие классы, View Component может получать внеденные в приложение зависимости.
Например, в файле Program.cs определен следующий код:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddTransient<ITimeService, SimpleTimeService>(); builder.Services.AddControllersWithViews(); var app = builder.Build(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run(); public interface ITimeService { string GetTime(); } public class SimpleTimeService : ITimeService { public string GetTime() => DateTime.Now.ToString("HH:mm:ss"); }
Здесь добавляется сервис ITimeService в виде класса SimpleTimeService.
Используем этот сервис и для этого изменим код компонента Timer:
using Microsoft.AspNetCore.Mvc; namespace MvcApp.Components { [ViewComponent] public class Timer { ITimeService timeService; public Timer(ITimeService service) { timeService = service; } public string Invoke() { return $"Текущее время: {timeService.GetTime()}"; } } }
При запуске приложения и вызове компонента ему автоматически будет передаваться нужный объект ITimeService. И также в представлении мы сможем его использовать:
@addTagHelper *, MvcApp <div> @await Component.InvokeAsync("Timer") </div> <div> <vc:timer /> </div>