Просмотр компонентов в ASP.NET Core
Автор: Рик Андерсон (Rick Anderson)
Компоненты представлений
Компоненты представлений похожи на частичные представления, но при этом гораздо функциональнее. Просмотр компонентов не использует привязку модели, они зависят от данных, передаваемых при вызове компонента представления. Эта статья написана с помощью контроллеров и представлений, но компоненты просмотра работают с Razor Pages.
Компонент представлений:
- Выполняет отрисовку фрагмента, а не всего отклика.
- Включает те же преимущества разделения функций и тестирования, которые доступны между контроллером и представлением.
- Может иметь параметры и бизнес-логику.
- Обычно вызывается со страницы макета.
Компоненты представления предназначены для повторного использования логики отрисовки, которая слишком сложна для частичного представления, например:
- Динамические меню навигации
- Тег облака, где он запрашивает базу данных
- Панель входа
- Корзина для покупок
- Недавно опубликованные статьи
- Содержимое боковой панели в блоге
- Панель входа, отображаемая на каждой странице и отображающая ссылки для выхода или входа в зависимости от состояния входа пользователя
Компонент представления состоит из двух частей:
- Класс, как правило, производный от ViewComponent
- Результат, который он возвращает, как правило, представление.
Как и контроллеры, компонент представления может быть POCO, но большинство разработчиков используют методы и свойства, доступные путем производных от ViewComponentних.
При рассмотрении того, соответствуют ли компоненты представления спецификациям приложения, рекомендуется использовать Razor вместо этого компоненты. Razor компоненты также объединяют разметку с кодом C# для создания единиц пользовательского интерфейса с повторно используемыми элементами пользовательского интерфейса. Razor компоненты предназначены для повышения производительности разработчиков при предоставлении клиентской логики пользовательского интерфейса и композиции. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core. Сведения о том, как включить Razor компоненты в приложение MVC или Pages, см. в статье "Интеграция компонентов ASP.NET Core Razor с MVC или Razor Razor Pages".
Создание компонента представления
Этот раздел содержит общие требования к созданию компонента представления. Далее в этой статье мы подробно рассмотрим каждый шаг и создадим компонент представления.
Класс компонентов представлений
Класс компонентов представлений можно создать одним из следующих способов:
- Производный от ViewComponent
- Декорирование класса с помощью атрибута
[ViewComponent]
или наследование от класса с помощью атрибута[ViewComponent]
- Создание класса, в котором имя заканчивается суффиксом
ViewComponent
Как и контроллеры, компоненты представлений должны быть открытыми, невложенными и неабстрактными классами. Имя компонента представления — это имя класса с удаленным суффиксом ViewComponent
. Его можно также можно задать явно с помощью свойства Name.
Класс компонентов представлений:
- Поддерживает внедрение зависимостей конструктора
- Не участвует в жизненном цикле контроллера, поэтому фильтры нельзя использовать в компоненте представления.
Чтобы запретить классу, который имеет суффикс ViewComponent
без учета регистра, рассматриваться как компонент представления, украшайте класс атрибутом [NonViewComponent]
:
using Microsoft.AspNetCore.Mvc;
[NonViewComponent]
public class ReviewComponent
{
public string Status(string name) => JobStatus.GetCurrentStatus(name);
}
Методы компонентов представлений
Компонент представления определяет свою логику в:
InvokeAsync
метод, возвращающийTask<IViewComponentResult>
.Invoke
синхронный метод, возвращающий объект IViewComponentResult.
Параметры берутся непосредственно из вызова компонента представления, а не из привязки модели. Компонент представления никогда не обрабатывает запрос напрямую. Как правило, компонент представления инициализирует модель и передает ее в представление, вызвав метод View
. Если кратко, методы компонентов представлений:
- Определяют метод
InvokeAsync
, который возвращаетTask<IViewComponentResult>
, или синхронный методInvoke
, возвращающийIViewComponentResult
. - Обычно инициализирует модель и передает ее в представление путем вызова метода ViewComponent.View .
- Получают параметры из вызывающего метода, а не HTTP. Это связано с тем, что привязка модели отсутствует.
- Недоступны напрямую как конечная точка HTTP. Обычно они вызываются в представлении. Компонент представления никогда не обрабатывает запрос.
- Перегружаются по сигнатуре, а не по сведениям из текущего HTTP-запроса.
Путь поиска представления
Среда выполнения ищет представление по следующим путям:
- /Views/{Имя контроллера}/Components/{Имя компонента представления}/{Имя представления}
- /Views/Shared/Components/{Имя компонента представления}/{Имя представления}
- /Pages/Shared/Components/{Имя компонента представления}/{Имя представления}
- /Area/{Имя области}/Views/Shared/Components/{View Component Name}/{View Component Name}/{View Name}
Путь поиска применяется к проектам с помощью контроллеров и представлений и Razor страниц.
Имя представления по умолчанию для компонента представления — Default
это означает, что файлы представления обычно будут называться Default.cshtml
. При создании результата компонента представления или при вызове View
метода можно указать другое имя представления.
Рекомендуется именовать файл Default.cshtml
представления и использовать путь views/Shared/Components/{View Component Name}/{View Name} (Имя представления). Компонент представления, используемый PriorityList
в этом примере, используется Views/Shared/Components/PriorityList/Default.cshtml
для представления компонента представления.
Настройка пути поиска представления
Чтобы настроить путь поиска представления, измените RazorViewLocationFormats коллекцию. Например, чтобы найти представления в пути /Components/{View Component Name}/{View Name}
, добавьте новый элемент в коллекцию:
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
});
builder.Services.AddDbContext<ToDoContext>(options =>
options.UseInMemoryDatabase("db"));
var app = builder.Build();
// Remaining code removed for brevity.
В предыдущем коде заполнитель {0}
представляет путь Components/{View Component Name}/{View Name}
.
Вызов компонента представления
Чтобы использовать компонент представления, вызовите следующий код внутри представления:
@await Component.InvokeAsync("Name of view component",
{Anonymous Type Containing Parameters})
Параметры передаются методу InvokeAsync
. Компонент PriorityList
представления, разработанный в статье, вызывается из Views/ToDo/Index.cshtml
файла представления. В следующем коде InvokeAsync
метод вызывается с двумя параметрами:
</table>
<div>
Maximum Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Вызов компонента представления в качестве вспомогательной функции тегов
Компонент представления можно вызвать как вспомогательный элемент тега:
<div>
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@{
int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
bool isDone = Convert.ToBoolean(ViewData["isDone"]);
}
<vc:priority-list max-priority=maxPriority is-done=isDone>
</vc:priority-list>
</div>
Параметры методов и классов, указанные в стиле Pascal, для вспомогательных функций тегов преобразуются в кебаб-стиль. Вспомогательная функция тегов для вызова компонента представления использует элемент <vc></vc>
. Компонент представления задан следующим образом:
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
Чтобы использовать компонент представления в качестве вспомогательного приложения тегов, зарегистрируйте с помощью директивы @addTagHelper
сборку, содержащую этот компонент представления. Если компонент представления находится в сборке MyWebApp
, добавьте следующую директиву в _ViewImports.cshtml
файл:
@addTagHelper *, MyWebApp
Компонент представления можно зарегистрировать в качестве вспомогательного элемента тега для любого файла, ссылающегося на компонент представления. Раздел Управление областью вспомогательной функции тегов содержит дополнительные сведения о том, как зарегистрировать вспомогательные функции тегов.
Метод InvokeAsync
, используемый в этом учебнике:
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
В предыдущей разметке PriorityList
компонент представления становится priority-list
. Параметры передаются в компонент представления как атрибуты в кебаб-стиле.
Вызов компонента представления непосредственно с контроллера
Компоненты представления обычно вызываются из представления, но их можно вызывать непосредственно из метода контроллера. Хотя компоненты представления не определяют конечные точки, такие как контроллеры, действие контроллера, возвращающее содержимое ViewComponentResult
можно реализовать.
В следующем примере компонент представления вызывается непосредственно из контроллера:
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
Создание базового компонента представления
Скачайте начальный код и выполните его сборку и тестирование. Это базовый проект с контроллером ToDo
, который отображает список элементов ToDo .
Обновление контроллера для передачи состояния приоритета и завершения
Index
Обновите метод для использования параметров состояния приоритета и завершения:
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
private readonly ToDoContext _ToDoContext;
public ToDoController(ToDoContext context)
{
_ToDoContext = context;
_ToDoContext.Database.EnsureCreated();
}
public IActionResult Index(int maxPriority = 2, bool isDone = false)
{
var model = _ToDoContext!.ToDo!.ToList();
ViewData["maxPriority"] = maxPriority;
ViewData["isDone"] = isDone;
return View(model);
}
Добавление класса ViewComponent
Добавление класса ViewComponent в ViewComponents/PriorityListViewComponent.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context) => db = context;
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
Примечания к коду:
Классы компонентов представлений могут находиться в любой папке проекта.
Так как имя класса PriorityListViewComponent заканчивается суффиксом ViewComponent, среда выполнения использует строку
PriorityList
при ссылке на компонент класса из представления.Атрибут
[ViewComponent]
может изменить имя, используемое для ссылки на компонент представления. Например, класс может быть названXYZ
следующим[ViewComponent]
атрибутом:[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
Атрибут
[ViewComponent]
в приведенном выше коде сообщает селектору компонентов представления:- Имя
PriorityList
при поиске представлений, связанных с компонентом - Строка PriorityList при ссылке на компонент класса из представления.
- Имя
Компонент использует внедрение зависимостей для предоставления контекста данных.
InvokeAsync
предоставляет метод, который можно вызвать из представления, и может принимать произвольное количество аргументов.Метод
InvokeAsync
возвращает набор элементовToDo
, удовлетворяющих параметрамisDone
иmaxPriority
.
Создание представления компонента Razor представления
Создайте папку Views/Shared/Components. Она должна называться Components.
Создайте папку Views/Shared/Components/PriorityList. Это имя папки должно совпадать с именем класса компонента представления или именем класса минус суффикс.
ViewComponent
Если используется атрибут, имя класса потребуется сопоставить с обозначением атрибута.Views/Shared/Components/PriorityList/Default.cshtml
Razor Создайте представление:@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
Представление Razor принимает список
TodoItem
и отображает их. Если метод компонентаInvokeAsync
представления не передает имя представления, значение по умолчанию используется для имени представления по соглашению . Чтобы переопределить стиль по умолчанию для определенного контроллера, добавьте представление в папку соответствующего контроллера (например, Views/ToDo/Components/PriorityList/Default.cshtml).Если компонент представления зависит от контроллера, его можно добавить в папку для конкретного контроллера. Например,
Views/ToDo/Components/PriorityList/Default.cshtml
зависит от контроллера.div
Добавьте вызов компонента списка приоритетов в нижней частиViews/ToDo/index.cshtml
файла:</table> <div> Maximum Priority: @ViewData["maxPriority"] <br /> Is Complete: @ViewData["isDone"] @await Component.InvokeAsync("PriorityList", new { maxPriority = ViewData["maxPriority"], isDone = ViewData["isDone"] } ) </div>
@await Component.InvokeAsync
в разметке показывает синтаксис для вызова компонентов представлений. Первым аргументом является имя компонента, который требуется вызвать. Последующие параметры передаются в компонент. InvokeAsync
может занять произвольное число аргументов.
Тестирование приложения. Следующий рисунок показывает список дел и элементы с приоритетом:
Компонент представления можно вызвать непосредственно из контроллера:
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
Указание имени компонента представления
Сложному представлению компонента в некоторых условиях может потребоваться указать нестандартное представление. Ниже показано, как указать представление "PVC" из метода InvokeAsync
. Обновите метод InvokeAsync
в классе PriorityListViewComponent
.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
Скопируйте файл в Views/Shared/Components/PriorityList/Default.cshtml
представление с именем Views/Shared/Components/PriorityList/PVC.cshtml
. Добавьте заголовок, чтобы указать используемое представление PVC.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
Запустите приложение и проверьте представление PVC.
Если представление ПВХ не отрисовывается, убедитесь, что компонент представления с приоритетом 4 или выше вызывается.
Проверка пути к представлению
Задайте для параметра приоритета значение 3 или меньше, чтобы представление с приоритетом не возвращалось.
Временно переименуйте в
Views/ToDo/Components/PriorityList/Default.cshtml
1Default.cshtml
.Протестируйте приложение, возникает следующая ошибка:
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml
Скопируйте
Views/ToDo/Components/PriorityList/1Default.cshtml
вViews/Shared/Components/PriorityList/Default.cshtml
.Добавьте разметку в представление компонента представления дел Shared, чтобы указать, что это представление из папки Shared.
Протестируйте представление компонента Shared.
Избегайте жестко закодированных строк
Для обеспечения безопасности во времени компиляции замените жестко закодированное имя компонента представления именем класса. Обновите файл PriorityListViewComponent.cs, чтобы не использовать суффикс ViewComponent:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
Файл представления :
</table>
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Перегрузка Component.InvokeAsync
метода, который принимает тип СРЕДЫ CLR, использует typeof
оператор:
</table>
<div>
Testing typeof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(typeof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Выполнение синхронных задач
Платформа обрабатывает вызов синхронного Invoke
метода, если асинхронная работа не требуется. Следующий метод создает синхронный компонент представления Invoke
:
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListSync : ViewComponent
{
private readonly ToDoContext db;
public PriorityListSync(ToDoContext context)
{
db = context;
}
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToList();
return View(x);
}
}
}
Файл компонента Razor представления:
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityListSync),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Компонент представления вызывается в Razor файле (например, Views/Home/Index.cshtml
с помощью одного из следующих подходов:
Чтобы использовать подход IViewComponentHelper, вызовите Component.InvokeAsync
:
@await Component.InvokeAsync(nameof(PriorityList),
new { maxPriority = 4, isDone = true })
Чтобы использовать вспомогательное приложение тэгов зарегистрируйте с помощью директивы @addTagHelper
сборку, содержащую этот компонент представления (он находится в сборке с именем MyWebApp
):
@addTagHelper *, MyWebApp
Используйте вспомогательный элемент тега компонента представления в файле разметки Razor :
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
Сигнатура PriorityList.Invoke
метода синхронна, но Razor находит и вызывает метод в Component.InvokeAsync
файле разметки.
Дополнительные ресурсы
Компоненты представлений
Компоненты представлений похожи на частичные представления, но при этом гораздо функциональнее. Просмотр компонентов не использует привязку модели, они зависят от данных, передаваемых при вызове компонента представления. Эта статья написана с помощью контроллеров и представлений, но компоненты просмотра работают с Razor Pages.
Компонент представлений:
- Выполняет отрисовку фрагмента, а не всего отклика.
- Включает те же преимущества разделения функций и тестирования, которые доступны между контроллером и представлением.
- Может иметь параметры и бизнес-логику.
- Обычно вызывается со страницы макета.
Компоненты представления предназначены для повторного использования логики отрисовки, которая слишком сложна для частичного представления, например:
- Динамические меню навигации
- Тег облака, где он запрашивает базу данных
- Панель входа
- Корзина для покупок
- Недавно опубликованные статьи
- Содержимое боковой панели в блоге
- Панель входа, отображаемая на каждой странице и отображающая ссылки для выхода или входа в зависимости от состояния входа пользователя
Компонент представления состоит из двух частей:
- Класс, как правило, производный от ViewComponent
- Результат, который он возвращает, как правило, представление.
Как и контроллеры, компонент представления может быть POCO, но большинство разработчиков используют методы и свойства, доступные путем производных от ViewComponentних.
При рассмотрении того, соответствуют ли компоненты представления спецификациям приложения, рекомендуется использовать Razor вместо этого компоненты. Razor компоненты также объединяют разметку с кодом C# для создания единиц пользовательского интерфейса с повторно используемыми элементами пользовательского интерфейса. Razor компоненты предназначены для повышения производительности разработчиков при предоставлении клиентской логики пользовательского интерфейса и композиции. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core. Сведения о том, как включить Razor компоненты в приложение MVC или Pages, см. в статье "Интеграция компонентов ASP.NET Core Razor с MVC или Razor Razor Pages".
Создание компонента представления
Этот раздел содержит общие требования к созданию компонента представления. Далее в этой статье мы подробно рассмотрим каждый шаг и создадим компонент представления.
Класс компонентов представлений
Класс компонентов представлений можно создать одним из следующих способов:
- Производный от ViewComponent
- Декорирование класса с помощью атрибута
[ViewComponent]
или наследование от класса с помощью атрибута[ViewComponent]
- Создание класса, в котором имя заканчивается суффиксом
ViewComponent
Как и контроллеры, компоненты представлений должны быть открытыми, невложенными и неабстрактными классами. Имя компонента представления — это имя класса с удаленным суффиксом ViewComponent
. Его можно также можно задать явно с помощью свойства Name.
Класс компонентов представлений:
- Поддерживает внедрение зависимостей конструктора
- Не участвует в жизненном цикле контроллера, поэтому фильтры нельзя использовать в компоненте представления.
Чтобы запретить классу, который имеет суффикс ViewComponent
без учета регистра, рассматриваться как компонент представления, украшайте класс атрибутом [NonViewComponent]
:
using Microsoft.AspNetCore.Mvc;
[NonViewComponent]
public class ReviewComponent
{
public string Status(string name) => JobStatus.GetCurrentStatus(name);
}
Методы компонентов представлений
Компонент представления определяет свою логику в:
InvokeAsync
метод, возвращающийTask<IViewComponentResult>
.Invoke
синхронный метод, возвращающий объект IViewComponentResult.
Параметры берутся непосредственно из вызова компонента представления, а не из привязки модели. Компонент представления никогда не обрабатывает запрос напрямую. Как правило, компонент представления инициализирует модель и передает ее в представление, вызвав метод View
. Если кратко, методы компонентов представлений:
- Определяют метод
InvokeAsync
, который возвращаетTask<IViewComponentResult>
, или синхронный методInvoke
, возвращающийIViewComponentResult
. - Обычно инициализирует модель и передает ее в представление путем вызова метода ViewComponent.View .
- Получают параметры из вызывающего метода, а не HTTP. Это связано с тем, что привязка модели отсутствует.
- Недоступны напрямую как конечная точка HTTP. Обычно они вызываются в представлении. Компонент представления никогда не обрабатывает запрос.
- Перегружаются по сигнатуре, а не по сведениям из текущего HTTP-запроса.
Путь поиска представления
Среда выполнения ищет представление по следующим путям:
- /Views/{Имя контроллера}/Components/{Имя компонента представления}/{Имя представления}
- /Views/Shared/Components/{Имя компонента представления}/{Имя представления}
- /Pages/Shared/Components/{Имя компонента представления}/{Имя представления}
- /Area/{Имя области}/Views/Shared/Components/{View Component Name}/{View Component Name}/{View Name}
Путь поиска применяется к проектам с помощью контроллеров и представлений и Razor страниц.
Имя представления по умолчанию для компонента представления — Default
это означает, что файлы представления обычно будут называться Default.cshtml
. При создании результата компонента представления или при вызове View
метода можно указать другое имя представления.
Рекомендуется именовать файл Default.cshtml
представления и использовать путь views/Shared/Components/{View Component Name}/{View Name} (Имя представления). Компонент представления, используемый PriorityList
в этом примере, используется Views/Shared/Components/PriorityList/Default.cshtml
для представления компонента представления.
Настройка пути поиска представления
Чтобы настроить путь поиска представления, измените RazorViewLocationFormats коллекцию. Например, чтобы найти представления в пути /Components/{View Component Name}/{View Name}
, добавьте новый элемент в коллекцию:
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
});
builder.Services.AddDbContext<ToDoContext>(options =>
options.UseInMemoryDatabase("db"));
var app = builder.Build();
// Remaining code removed for brevity.
В предыдущем коде заполнитель {0}
представляет путь Components/{View Component Name}/{View Name}
.
Вызов компонента представления
Чтобы использовать компонент представления, вызовите следующий код внутри представления:
@await Component.InvokeAsync("Name of view component",
{Anonymous Type Containing Parameters})
Параметры передаются методу InvokeAsync
. Компонент PriorityList
представления, разработанный в статье, вызывается из Views/ToDo/Index.cshtml
файла представления. В следующем коде InvokeAsync
метод вызывается с двумя параметрами:
</table>
<div>
Maximum Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Вызов компонента представления в качестве вспомогательной функции тегов
Компонент представления можно вызвать как вспомогательный элемент тега:
<div>
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@{
int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
bool isDone = Convert.ToBoolean(ViewData["isDone"]);
}
<vc:priority-list max-priority=maxPriority is-done=isDone>
</vc:priority-list>
</div>
Параметры методов и классов, указанные в стиле Pascal, для вспомогательных функций тегов преобразуются в кебаб-стиль. Вспомогательная функция тегов для вызова компонента представления использует элемент <vc></vc>
. Компонент представления задан следующим образом:
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
Чтобы использовать компонент представления в качестве вспомогательного приложения тегов, зарегистрируйте с помощью директивы @addTagHelper
сборку, содержащую этот компонент представления. Если компонент представления находится в сборке MyWebApp
, добавьте следующую директиву в _ViewImports.cshtml
файл:
@addTagHelper *, MyWebApp
Компонент представления можно зарегистрировать в качестве вспомогательного элемента тега для любого файла, ссылающегося на компонент представления. Раздел Управление областью вспомогательной функции тегов содержит дополнительные сведения о том, как зарегистрировать вспомогательные функции тегов.
Метод InvokeAsync
, используемый в этом учебнике:
@await Component.InvokeAsync("PriorityList",
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
В предыдущей разметке PriorityList
компонент представления становится priority-list
. Параметры передаются в компонент представления как атрибуты в кебаб-стиле.
Вызов компонента представления непосредственно с контроллера
Компоненты представления обычно вызываются из представления, но их можно вызывать непосредственно из метода контроллера. Хотя компоненты представления не определяют конечные точки, такие как контроллеры, действие контроллера, возвращающее содержимое ViewComponentResult
можно реализовать.
В следующем примере компонент представления вызывается непосредственно из контроллера:
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
Создание базового компонента представления
Скачайте начальный код и выполните его сборку и тестирование. Это базовый проект с контроллером ToDo
, который отображает список элементов ToDo .
Обновление контроллера для передачи состояния приоритета и завершения
Index
Обновите метод для использования параметров состояния приоритета и завершения:
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
private readonly ToDoContext _ToDoContext;
public ToDoController(ToDoContext context)
{
_ToDoContext = context;
_ToDoContext.Database.EnsureCreated();
}
public IActionResult Index(int maxPriority = 2, bool isDone = false)
{
var model = _ToDoContext!.ToDo!.ToList();
ViewData["maxPriority"] = maxPriority;
ViewData["isDone"] = isDone;
return View(model);
}
Добавление класса ViewComponent
Добавление класса ViewComponent в ViewComponents/PriorityListViewComponent.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context) => db = context;
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
Примечания к коду:
Классы компонентов представлений могут находиться в любой папке проекта.
Так как имя класса PriorityListViewComponent заканчивается суффиксом ViewComponent, среда выполнения использует строку
PriorityList
при ссылке на компонент класса из представления.Атрибут
[ViewComponent]
может изменить имя, используемое для ссылки на компонент представления. Например, класс может быть названXYZ
следующим[ViewComponent]
атрибутом:[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
Атрибут
[ViewComponent]
в приведенном выше коде сообщает селектору компонентов представления:- Имя
PriorityList
при поиске представлений, связанных с компонентом - Строка PriorityList при ссылке на компонент класса из представления.
- Имя
Компонент использует внедрение зависимостей для предоставления контекста данных.
InvokeAsync
предоставляет метод, который можно вызвать из представления, и может принимать произвольное количество аргументов.Метод
InvokeAsync
возвращает набор элементовToDo
, удовлетворяющих параметрамisDone
иmaxPriority
.
Создание представления компонента Razor представления
Создайте папку Views/Shared/Components. Она должна называться Components.
Создайте папку Views/Shared/Components/PriorityList. Это имя папки должно совпадать с именем класса компонента представления или именем класса минус суффикс.
ViewComponent
Если используется атрибут, имя класса потребуется сопоставить с обозначением атрибута.Views/Shared/Components/PriorityList/Default.cshtml
Razor Создайте представление:@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
Представление Razor принимает список
TodoItem
и отображает их. Если метод компонентаInvokeAsync
представления не передает имя представления, значение по умолчанию используется для имени представления по соглашению . Чтобы переопределить стиль по умолчанию для определенного контроллера, добавьте представление в папку соответствующего контроллера (например, Views/ToDo/Components/PriorityList/Default.cshtml).Если компонент представления зависит от контроллера, его можно добавить в папку для конкретного контроллера. Например,
Views/ToDo/Components/PriorityList/Default.cshtml
зависит от контроллера.div
Добавьте вызов компонента списка приоритетов в нижней частиViews/ToDo/index.cshtml
файла:</table> <div> Maximum Priority: @ViewData["maxPriority"] <br /> Is Complete: @ViewData["isDone"] @await Component.InvokeAsync("PriorityList", new { maxPriority = ViewData["maxPriority"], isDone = ViewData["isDone"] } ) </div>
@await Component.InvokeAsync
в разметке показывает синтаксис для вызова компонентов представлений. Первым аргументом является имя компонента, который требуется вызвать. Последующие параметры передаются в компонент. InvokeAsync
может занять произвольное число аргументов.
Тестирование приложения. Следующий рисунок показывает список дел и элементы с приоритетом:
Компонент представления можно вызвать непосредственно из контроллера:
public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
return ViewComponent("PriorityList",
new {
maxPriority = maxPriority,
isDone = isDone
});
}
Указание имени компонента представления
Сложному представлению компонента в некоторых условиях может потребоваться указать нестандартное представление. Ниже показано, как указать представление "PVC" из метода InvokeAsync
. Обновите метод InvokeAsync
в классе PriorityListViewComponent
.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
Скопируйте файл в Views/Shared/Components/PriorityList/Default.cshtml
представление с именем Views/Shared/Components/PriorityList/PVC.cshtml
. Добавьте заголовок, чтобы указать используемое представление PVC.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
Запустите приложение и проверьте представление PVC.
Если представление ПВХ не отрисовывается, убедитесь, что компонент представления с приоритетом 4 или выше вызывается.
Проверка пути к представлению
Задайте для параметра приоритета значение 3 или меньше, чтобы представление с приоритетом не возвращалось.
Временно переименуйте в
Views/ToDo/Components/PriorityList/Default.cshtml
1Default.cshtml
.Протестируйте приложение, возникает следующая ошибка:
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml
Скопируйте
Views/ToDo/Components/PriorityList/1Default.cshtml
вViews/Shared/Components/PriorityList/Default.cshtml
.Добавьте разметку в представление компонента представления дел Shared, чтобы указать, что это представление из папки Shared.
Протестируйте представление компонента Shared.
Избегайте жестко закодированных строк
Для обеспечения безопасности во времени компиляции замените жестко закодированное имя компонента представления именем класса. Обновите файл PriorityListViewComponent.cs, чтобы не использовать суффикс ViewComponent:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents;
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
Файл представления :
</table>
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Перегрузка Component.InvokeAsync
метода, который принимает тип СРЕДЫ CLR, использует typeof
оператор:
</table>
<div>
Testing typeof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(typeof(PriorityList),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Выполнение синхронных задач
Платформа обрабатывает вызов синхронного Invoke
метода, если асинхронная работа не требуется. Следующий метод создает синхронный компонент представления Invoke
:
using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListSync : ViewComponent
{
private readonly ToDoContext db;
public PriorityListSync(ToDoContext context)
{
db = context;
}
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToList();
return View(x);
}
}
}
Файл компонента Razor представления:
<div>
Testing nameof(PriorityList) <br />
Maxium Priority: @ViewData["maxPriority"] <br />
Is Complete: @ViewData["isDone"]
@await Component.InvokeAsync(nameof(PriorityListSync),
new {
maxPriority = ViewData["maxPriority"],
isDone = ViewData["isDone"] }
)
</div>
Компонент представления вызывается в Razor файле (например, Views/Home/Index.cshtml
с помощью одного из следующих подходов:
Чтобы использовать подход IViewComponentHelper, вызовите Component.InvokeAsync
:
@await Component.InvokeAsync(nameof(PriorityList),
new { maxPriority = 4, isDone = true })
Чтобы использовать вспомогательное приложение тэгов зарегистрируйте с помощью директивы @addTagHelper
сборку, содержащую этот компонент представления (он находится в сборке с именем MyWebApp
):
@addTagHelper *, MyWebApp
Используйте вспомогательный элемент тега компонента представления в файле разметки Razor :
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
Сигнатура PriorityList.Invoke
метода синхронна, но Razor находит и вызывает метод в Component.InvokeAsync
файле разметки.
Дополнительные ресурсы
Просмотреть или скачать образец кода (описание загрузки)
Компоненты представлений
Компоненты представлений похожи на частичные представления, но при этом гораздо функциональнее. Компоненты представлений не используют привязку модели и зависят только от данных, предоставляемых при их вызове. Эта статья написана с помощью контроллеров и представлений, но компоненты просмотра также работают с Razor Pages.
Компонент представлений:
- Выполняет отрисовку фрагмента, а не всего отклика.
- Включает те же преимущества разделения функций и тестирования, которые доступны между контроллером и представлением.
- Может иметь параметры и бизнес-логику.
- Обычно вызывается со страницы макета.
Компоненты представлений предназначены для случаев, когда имеется многоразовая логика отрисовки, которая слишком сложна для частичного представления, например:
- Динамические меню навигации
- Облако тегов (где выполняется запрос к базе данных)
- Панель входа
- Корзина для покупок
- Недавно опубликованные статьи
- Содержимое боковой панели в типичном блоге
- Панель входа, которая должна отображаться на каждой странице и содержит ссылки для выхода или входа в зависимости от состояния входа пользователя
Компонент представления состоит из двух частей: класс (обычно производный от ViewComponent) и результат, который он возвращает (обычно представление). Как и контроллеры, компонент представления может быть POCO, но большинство разработчиков используют методы и свойства, доступные путем производных от ViewComponent
них.
При рассмотрении того, соответствуют ли компоненты представления спецификациям приложения, рекомендуется использовать Razor вместо этого компоненты. Razor компоненты также объединяют разметку с кодом C# для создания единиц пользовательского интерфейса с повторно используемыми элементами пользовательского интерфейса. Razor компоненты предназначены для повышения производительности разработчиков при предоставлении клиентской логики пользовательского интерфейса и композиции. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core. Сведения о том, как включить Razor компоненты в приложение MVC или Pages, см. в статье "Интеграция компонентов ASP.NET Core Razor с MVC или Razor Razor Pages".
Создание компонента представления
Этот раздел содержит общие требования к созданию компонента представления. Далее в этой статье мы подробно рассмотрим каждый шаг и создадим компонент представления.
Класс компонентов представлений
Класс компонентов представлений можно создать одним из следующих способов:
- Наследование от ViewComponent
- Декорирование класса с помощью атрибута
[ViewComponent]
или наследование от класса с помощью атрибута[ViewComponent]
- Создание класса, где имя заканчивается суффиксом ViewComponent
Как и контроллеры, компоненты представлений должны быть открытыми, невложенными и неабстрактными классами. Имя компонента представления — это имя класса с удаленным суффиксом "ViewComponent". Его можно также можно задать явно с помощью свойства ViewComponentAttribute.Name
.
Класс компонентов представлений:
- Полностью поддерживает внедрение зависимостей в конструкторе.
- Не участвует в жизненном цикле контроллера, поэтому в компоненте представления невозможно использовать фильтры.
Чтобы остановить класс с нечувствительным суффиксом ViewComponent от обработки как компонента представления, украшайте класс атрибутом [NonViewComponent] :
[NonViewComponent]
public class ReviewComponent
{
// ...
Методы компонентов представлений
Компонент представления задает свою логику в методе InvokeAsync
, возвращающем Task<IViewComponentResult>
, или в синхронном методе Invoke
, который возвращает IViewComponentResult
. Параметры берутся непосредственно из вызова компонента представления, а не из привязки модели. Компонент представления никогда не обрабатывает запрос напрямую. Как правило, компонент представления инициализирует модель и передает ее в представление, вызвав метод View
. Если кратко, методы компонентов представлений:
- Определяют метод
InvokeAsync
, который возвращаетTask<IViewComponentResult>
, или синхронный методInvoke
, возвращающийIViewComponentResult
. - Обычно инициализируют модель и передают ее в представление, вызвав метод
ViewComponent
View
. - Получают параметры из вызывающего метода, а не HTTP. Это связано с тем, что привязка модели отсутствует.
- Недоступны непосредственно в качестве конечной точки HTTP. Вызываются из кода (обычно в представлении). Компонент представления никогда не обрабатывает запрос.
- Перегружаются по сигнатуре, а не по сведениям из текущего HTTP-запроса.
Путь поиска представления
Среда выполнения ищет представление по следующим путям:
- /Views/{Имя контроллера}/Components/{Имя компонента представления}/{Имя представления}
- /Views/Shared/Components/{Имя компонента представления}/{Имя представления}
- /Pages/Shared/Components/{Имя компонента представления}/{Имя представления}
- /Area/{Имя области}/Views/Shared/Components/{View Component Name}/{View Component Name}/{View Name}
Путь поиска применяется к проектам с помощью контроллеров и представлений и Razor страниц.
Имя представления по умолчанию для компонента представления — Default, что означает, что файл представления обычно будет называться Default.cshtml
. При создании результата компонента представления или при вызове метода View
можно указать другое имя представления.
Мы рекомендуем присвоить файлу Default.cshtml
представления имя и использовать путь views/Shared/Components/{View Component Name}/{View Name} (Имя представления). Компонент представления, используемый PriorityList
в этом примере, используется Views/Shared/Components/PriorityList/Default.cshtml
для представления компонента представления.
Настройка пути поиска представления
Чтобы настроить путь поиска представления, измените RazorViewLocationFormats коллекцию. Например, чтобы найти представления в пути "/Components/{имя компонента представления}/{имя представления}", добавьте в коллекцию новый элемент:
services.AddMvc()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/{0}.cshtml");
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
В приведенном выше коде заполнитель {0} представляет путь "Components/{имя компонента представления}/{имя представления}".
Вызов компонента представления
Чтобы использовать компонент представления, вызовите следующий код внутри представления:
@await Component.InvokeAsync("Name of view component", {Anonymous Type Containing Parameters})
Эти параметры передаются в метод InvokeAsync
. Компонент PriorityList
представления, разработанный в статье, вызывается из Views/ToDo/Index.cshtml
файла представления. Следующий код вызывает метод InvokeAsync
с двумя параметрами:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
Вызов компонента представления в качестве вспомогательной функции тегов
Для ASP.NET Core 1.1 и более поздних версий можно вызвать компонент представления в качестве вспомогательной функции тегов:
<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>
Параметры методов и классов, указанные в стиле Pascal, для вспомогательных функций тегов преобразуются в кебаб-стиль. Вспомогательная функция тегов для вызова компонента представления использует элемент <vc></vc>
. Компонент представления задан следующим образом:
<vc:[view-component-name]
parameter1="parameter1 value"
parameter2="parameter2 value">
</vc:[view-component-name]>
Чтобы использовать компонент представления в качестве вспомогательного приложения тегов, зарегистрируйте с помощью директивы @addTagHelper
сборку, содержащую этот компонент представления. Если компонент представления находится в сборке MyWebApp
, добавьте следующую директиву в _ViewImports.cshtml
файл:
@addTagHelper *, MyWebApp
Зарегистрировать компонент представления в качестве вспомогательной функции тегов можно в любом файле, который ссылается на этот компонент представления. Раздел Управление областью вспомогательной функции тегов содержит дополнительные сведения о том, как зарегистрировать вспомогательные функции тегов.
Метод InvokeAsync
, используемый в этом учебнике:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
В разметке вспомогательной функции тегов:
<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>
В предыдущем примере компонент представления PriorityList
становится priority-list
. Параметры передаются в компонент представления как атрибуты в кебаб-стиле.
Вызов компонента представления непосредственно из контроллера
Компоненты представлений обычно вызываются из представления, но их можно вызывать непосредственно из метода контроллера. Если компоненты представлений не определяют конечные точки, например контроллеры, можно легко реализовать действие контроллера, возвращающее содержимое ViewComponentResult
.
В этом примере компонент представления вызывается непосредственно из контроллера:
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
Пошаговое руководство. Создание простого компонента представления
Скачайте начальный код и выполните его сборку и тестирование. Это простой проект с контроллером ToDo
, который отображает список элементов дел.
Добавление класса ViewComponent
Создайте папку ViewComponents и добавьте следующий класс PriorityListViewComponent
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityListViewComponent : ViewComponent
{
private readonly ToDoContext db;
public PriorityListViewComponent(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
Примечания к коду:
Классы компонентов представлений могут находиться в любой папке проекта.
Так как имя класса PriorityListViewComponent заканчивается суффиксом ViewComponent, среда выполнения использует строку
PriorityList
при ссылке на компонент класса из представления.Атрибут
[ViewComponent]
может изменить имя, используемое для ссылки на компонент представления. Например, класс мог быть названXYZ
атрибутомViewComponent
:[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
Атрибут
[ViewComponent]
в приведенном выше коде сообщает селектору компонентов представления:- Имя
PriorityList
при поиске представлений, связанных с компонентом - Строка PriorityList при ссылке на компонент класса из представления.
- Имя
Компонент использует внедрение зависимостей для предоставления контекста данных.
InvokeAsync
предоставляет метод, который возможно вызывать из представления и который может принять произвольное число аргументов.Метод
InvokeAsync
возвращает набор элементовToDo
, удовлетворяющих параметрамisDone
иmaxPriority
.
Создание представления компонента Razor представления
Создайте папку Views/Shared/Components. Эта папка должна быть названа
Components
.Создайте папку Views/Shared/Components/PriorityList. Ее имя должно соответствовать имени класса представлений компонентов или имени класса без суффикса (если мы следовали соглашению и использовали суффикс ViewComponent в имени класса). Если вы использовали атрибут
ViewComponent
, имя класса должно соответствовать его обозначению.Views/Shared/Components/PriorityList/Default.cshtml
Razor Создайте представление:@model IEnumerable<ViewComponentSample.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Name</li> } </ul>
Представление Razor принимает список
TodoItem
и отображает их. Если методInvokeAsync
компонента представления не передает имя представления (как в нашем примере), по соглашению используется имя Default. Далее в этом учебнике я покажу, как передать имя представления. Чтобы переопределить стиль по умолчанию для определенного контроллера, добавьте представление в папку соответствующего контроллера (например, Views/ToDo/Components/PriorityList/Default.cshtml).Если компонент представления зависит от контроллера, его можно добавить в папку для конкретного контроллера (
Views/ToDo/Components/PriorityList/Default.cshtml
).div
Добавьте вызов компонента списка приоритетов в нижней частиViews/ToDo/index.cshtml
файла:</table> <div> @await Component.InvokeAsync("PriorityList", new { maxPriority = 2, isDone = false }) </div>
@await Component.InvokeAsync
в разметке показывает синтаксис для вызова компонентов представлений. Первым аргументом является имя компонента, который требуется вызвать. Последующие параметры передаются в компонент. InvokeAsync
может занять произвольное число аргументов.
Тестирование приложения. Следующий рисунок показывает список дел и элементы с приоритетом:
Кроме того, компонент представления можно вызвать непосредственно из контроллера:
public IActionResult IndexVC()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}
Указание имени представления
Сложному представлению компонента в некоторых условиях может потребоваться указать нестандартное представление. Ниже показано, как указать представление "PVC" из метода InvokeAsync
. Обновите метод InvokeAsync
в классе PriorityListViewComponent
.
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
Скопируйте файл в Views/Shared/Components/PriorityList/Default.cshtml
представление с именем Views/Shared/Components/PriorityList/PVC.cshtml
. Добавьте заголовок, чтобы указать используемое представление PVC.
@model IEnumerable<ViewComponentSample.Models.TodoItem>
<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
@foreach (var todo in Model)
{
<li>@todo.Name</li>
}
</ul>
Обновление Views/ToDo/Index.cshtml
:
@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })
Запустите приложение и проверьте представление PVC.
Если представление PVC не отображается, убедитесь, что вы вызываете компонент представления с приоритетом 4 или выше.
Проверка пути к представлению
Задайте для параметра приоритета значение 3 или меньше, чтобы представление с приоритетом не возвращалось.
Временно переименуйте в
Views/ToDo/Components/PriorityList/Default.cshtml
1Default.cshtml
.Проверьте приложение, при этом происходит следующая ошибка:
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched: /Views/ToDo/Components/PriorityList/Default.cshtml /Views/Shared/Components/PriorityList/Default.cshtml EnsureSuccessful
Скопируйте
Views/ToDo/Components/PriorityList/1Default.cshtml
вViews/Shared/Components/PriorityList/Default.cshtml
.Добавьте разметку в представление компонента представления дел Shared, чтобы указать, что это представление из папки Shared.
Протестируйте представление компонента Shared.
Как избежать жестко запрограммированных строк
Чтобы обеспечить безопасность во время компиляции, можно заменить жестко заданное имя компонента представления на имя класса. Создайте компонент представления без суффикса "ViewComponent":
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;
namespace ViewComponentSample.ViewComponents
{
public class PriorityList : ViewComponent
{
private readonly ToDoContext db;
public PriorityList(ToDoContext context)
{
db = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
var items = await GetItemsAsync(maxPriority, isDone);
return View(items);
}
private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return db.ToDo.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority).ToListAsync();
}
}
}
Добавьте инструкцию using
nameof
в Razor файл представления и используйте оператор:
@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>
<h2>ToDo nameof</h2>
<!-- Markup removed for brevity. -->
<div>
@*
Note:
To use the below line, you need to #define no_suffix in ViewComponents/PriorityList.cs or it won't compile.
By doing so it will cause a problem to index as there will be multiple viewcomponents
with the same name after the compiler removes the suffix "ViewComponent"
*@
@*@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })*@
</div>
Вы можете использовать перегрузку Component.InvokeAsync
метода, который принимает тип CLR. Не забудьте использовать typeof
оператор в этом случае:
@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>
<h2>ToDo typeof</h2>
<!-- Markup removed for brevity. -->
<div>
@await Component.InvokeAsync(typeof(PriorityListViewComponent), new { maxPriority = 4, isDone = true })
</div>
Выполнение синхронных задач
Платформа обрабатывает вызов синхронного метода Invoke
, если не требуется асинхронное выполнение работы. Следующий метод создает синхронный компонент представления Invoke
:
public class PriorityList : ViewComponent
{
public IViewComponentResult Invoke(int maxPriority, bool isDone)
{
var items = new List<string> { $"maxPriority: {maxPriority}", $"isDone: {isDone}" };
return View(items);
}
}
Файл компонента Razor представления содержит строки, передаваемые методу Invoke
(Views/Home/Components/PriorityList/Default.cshtml
):
@model List<string>
<h3>Priority Items</h3>
<ul>
@foreach (var item in Model)
{
<li>@item</li>
}
</ul>
Компонент представления вызывается в Razor файле (например, Views/Home/Index.cshtml
с помощью одного из следующих подходов:
Чтобы использовать подход IViewComponentHelper, вызовите Component.InvokeAsync
:
@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })
Чтобы использовать вспомогательное приложение тэгов зарегистрируйте с помощью директивы @addTagHelper
сборку, содержащую этот компонент представления (он находится в сборке с именем MyWebApp
):
@addTagHelper *, MyWebApp
Используйте вспомогательный элемент тега компонента представления в файле разметки Razor :
<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>
Сигнатура PriorityList.Invoke
метода синхронна, но Razor находит и вызывает метод в Component.InvokeAsync
файле разметки.
Все параметры компонентов представления обязательны
Каждый параметр в компоненте представления является обязательным атрибутом. Также см. эту проблему в GitHub. Если какой-либо параметр отсутствует:
- Сигнатура метода
InvokeAsync
не совпадет, поэтому метод не будет выполняться. - Компонент ViewComponent не отобразит никакой разметки.
- Не будут выдаваться ошибки.
Дополнительные ресурсы
ASP.NET Core