Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
В View Component при необходимости можно передавать данные. Во-первых, View Component может принимать некоторые параметры, которые ему передаются при вызове компонента. Во-вторых, класс View Component, также как и другие классы в ASP.NET Core, может получать зависимости из провайдера сервисов через механизм dependency injection. Рассмотрим, оба случая передачи данных.
Через параметры метода Invoke/InvokeAsync мы можем получать извне некоторые данные. Например, определим следующий компонент:
using Microsoft.AspNetCore.Mvc; using System; namespace ViewComponentsApp.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 - секунды опускаются.
Теперь обратимся к этому компоненту в представлении:
<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; using System; namespace ViewComponentsApp.Components { [ViewComponent] public class Timer { public string Invoke(bool includeSeconds, bool format24) { string time = String.Empty; 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 часовом.
Обратимся к компоненту в представлении:
<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 через метод Component.InvokeAsync или через tag-хелпер, тем не менее при передаче параметров между этими способами есть различия. В частности, при использовании тег-хелпера мы должны определить все параметры для View Component. Но рассмотрим следующую ситуацию. View Component устанавливает значения по умолчанию для своих параметров:
public string Invoke(bool includeSeconds = false, bool format24 = true) { // остальное содержание метода
То есть по умолчанию применяется 24-часовой формат, а секунды не включаются.
Попробуем при обращении к компоненту опустить некоторые параметры (ведь теперь они имеют значения по умолчанию):
<p> Html-хелпер. Все значения по умолчанию: <br /> @await Component.InvokeAsync("Timer") </p> <p> Html-хелпер. 12-часовой формат: <br /> @await Component.InvokeAsync("Timer", new { format24 = false }) </p> <p> Html-хелпер. С секундами: <br /> @await Component.InvokeAsync("Timer", new { includeSeconds = true }) </p> <p> Тег-хелпер. Все значения по умолчанию: <br /> <vc:timer></vc:timer> </p> <p> Тег-хелпер. С секундами: <br /> <vc:timer include-seconds="true"></vc:timer> </p>
При запуске приложения мы увидим, что метод Component.InvokeAsync сработал как надо, а тег-хелпер нет.
При этом View Component может принимать более сложные данные. Например, определим в проекте в папке Models новый класс User:
public class User { public string Name { get; set; } public int Age { get; set; } }
В папке Components определим новый View Component - класс PersonViewComponent:
using ViewComponentsApp.Models; namespace ViewComponentsApp.Components { public class PersonViewComponent { public string Invoke(User user) { return $"Name: {user.Name} Age: {user.Age}"; } } }
Данный компонент принимает объкт User и возвращает его данные в виде строки.
Теперь применим данный компонент в представлении:
@using ViewComponentsApp.Models <!-- пространство имен модели User--> @{ User tom = new User { Name = "Tom", Age = 35 }; User alice = new User { Name = "Alice", Age = 29 }; } <div> @await Component.InvokeAsync("Person", new { user = tom}) </div> <div> <vc:person user="alice"></vc:person> </div>
Результат работы приложения:
Как и другие классы, View Component может получать внеденные в приложение зависимости.
Например, определим в проекте интерфейс и класс сервиса:
public interface ITimeService { public string GetTime(); } public class TimeService : ITimeService { public string GetTime() { return DateTime.Now.ToString("HH:mm:ss"); } }
Зарегистрируем зависимость от ITimeService в классе Startup:
using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using ViewComponentsApp.Services; namespace ViewComponentsApp { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddTransient<ITimeService, TimeService>(); } public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
Изменим код компонента Timer:
using Microsoft.AspNetCore.Mvc; using ViewComponentsApp.Services; namespace ViewComponentsApp.Components { [ViewComponent] public class Timer { ITimeService timeService; public Timer(ITimeService service) { timeService = service; } public string Invoke() { return $"Текущее время: {timeService.GetTime()}"; } } }
При запуске приложения и вызове компонента ему автоматически будет передаваться нужный объект ITimeService. И также в представлении мы сможем его использовать:
<div> @await Component.InvokeAsync("Timer") </div> <div> <vc:timer /> </div>