Передача данных во View Component

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

Последнее обновление: 27.11.2019

В View Component при необходимости можно передавать данные. Во-первых, View Component может принимать некоторые параметры, которые ему передаются при вызове компонента. Во-вторых, класс View Component, также как и другие классы в ASP.NET Core, может получать зависимости из провайдера сервисов через механизм dependency injection. Рассмотрим, оба случая передачи данных.

Передача параметров в View Component

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

Результат выполнения:

Параметры в View Component в ASP.NET Core

Подобным образом мы можем использовать и больщее количество параметров. Например, изменим код компонента следующим образом:

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>
Parameters in View Component in ASP.NET Core

Несмотря на то, что мы вроде равным образом можем обращаться к 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 в ASP.NET Core

При этом 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 в ASP.NET Core MVC

Внедрение зависимостей

Как и другие классы, 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>
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850