4.4. Представления - компоненты

Представления, которые мы рассматривали в предыдущей главе отлично работают, если у вас есть под рукой готовая модель, которая может отобразить себя, но это далеко не всегда эффективно. Например, у меня на сайте в правом верхнем углу отображается имя пользователя, если вы зарегистрированы. Этот кусочек страницы строится в шаблоне страницы. Неужели мне нужно передавать шаблону _Layout.cshtml какую-то модель? Это вообще возможно?

Проблема с выводом имени текущего пользователя в файле шаблона можно решить двумя методами:

1. Создать где-то в модели статичный метод и обратиться к нему. Только это должен быть именно метод, а не переменная, иначе вы сделаете очень серьезную ошибку, но это уже вопрос отдельный и связан с Web программированием в целом, а не ..NET Core фреймворком.

2. Использовать компонент

Я предпочитаю как раз второй метод, и он как раз отлично подходит для нашего случая.

Компоненты по своей идее очень похожи на частичные представления, это так же cshtml файлы, при отображении которых не будет отображаться шаблон и поэтому такие компоненты и представления являются встраиваемыми в страницу.

Разница только в том, откуда берется модель для файла представления. В случае с View, модель нужно передать в качестве параметра при вызове, потому что когда мы отображаем частичное представление partial view фреймворк сразу же идет и ищет именно view. В случае с компонентами к представлению привязан C# код в котором вы можете сформировать модель и передать ее представлению.

Получается, что компонент – это как бы независимый MVC. Вы говорите – отобразите мне в этой части странице компонент Login и фреймворк находит сначала код комппонента, который формирует модель и потом вызывает представление для отображение содержимого модели.

Убедимся, что это круть на практике.

Код компонентов живет в отдельной папке ViewComponents. У вас ее скорей всего нет, поэтому придется создать также, как мы создавали папку для контроллеров. Щелкаем правой кнопкой по имени проекта и выбираем Add / New Folder.

Теперь внутри папку ViewComponents создаем файл, назовем его UserViewComponent.cs, в котором и будет жить код. Именование очень важно, потому что если мы просим фреймворк отобразить компонент User, то он будет искать класс с именем UserViewComponent.

1. В этом файле нужно добавить пространство имен Microsoft.AspNetCore.Mvc, потому что мы будем работать с компонентом.

2. Класс должен наследовать ViewComponent, поэтому обязательно добавим это

3. Нужно реализовать метод Invoke, который должен возвращать тип IViewComponentResult

Метод Invoke работает так же, как и методы в контроллерах. Только в контроллерах один класс может обрабатывать несколько различных URL, то здесь это один класс на один компонент, поэтому нужен один метод. Полный код моего примера будет выглядеть так:

using System;
using Microsoft.AspNetCore.Mvc;
using MyWebSite.Model;
 
namespace MyWebSite.ViewComponents
{
    public class UserViewComponent: ViewComponent
    {
        public UserViewComponent()
        {
 
        }
 
        public IViewComponentResult Invoke()
        {
            var model = new UserModel()
            {
                IsLoggedIn = true,
                UserName = "mflenov"
            };
            return View("User", model);
        }
    }
}

В методе Invoke я создаю экземпляр модели UserModel с парочкой параметров и иммитирую, как будто пользователь уже вошел в систему и его имя mflenov. В реальном приложении тут может быть проверка сессии на предмет наличия индикатора, что пользователь вошел в систему.

Результат метода возвращается точно также, как и в случае методов контроллера – вызывается метод View, которому передается два параметра – имя представления (cshtml файла, в котором будет лежать html компонента) и модель.

Представления компонентов могут располагаться в разных местах, и чтобы узнать их место, достаточно встроить вызов компонента (об этом чуть ниже) в страницу и запустить приложение. Когда .NET не сможет найти файл cshtml он вылетит с ошибкой и в этой ошибке будут указаны пути, где фреймворк пытался найти представление. Это можете оставить в качестве домашнего задания, а я рекомендую располагать компоненты в:

Views/Shared/Components/ИмяКомпонента/ИмяКомпонента.cshtml.

Таким образом файлы будут хорошо сгруппированы по папочкам и фреймворк умеет работать с таким шаблоном. В нашем случае компонент называется User, а значит путь будет:

Views/Shared/Components/User/User.cshtml.

На следующем рисунке показано окно моего проекта и в нем вы можете увидеть, как я создал файлы. Создайте таким же образом представление для нашего компонента User.

В представлении компонента можно писать такой же код, который мы писали в любом другом представлении. Для теста я написал следующий код:

@model MyWebSite.Model.UserModel

@if (Model.IsLoggedIn) {
    

Welcome: @Model.UserName    

}
else {
        

Please login

}

Вот теперь компонент можно считать законченным и осталось только отобразить его на странице. Открываем шаблон _Layout и в нем добавляем:

@await Component.InvokeAsync("User") 

В месте, где мы хотим отобразить компонент просто вызываем метод Component.InvokeAsync, а в качестве параметра указываем имя компонент. Сразу в названии есть слово Async, а значит метод асинхронный и нам нужно указать еще и await.

Можно запустить приложение и убедиться, что оно работает.

Есть еще один способ вызова компонента, он считается более современным, потому что использует Тэги, и я бы рекомендовал использовать его:

<vc:user></vc:user>

Тэг vc видимо означает ViewComponent. После двоеточия указываем, какой именно компонент мы хотим отобразить.

Но если сейчас запустить сайт, то работать это не будет, потому что по умолчанию фреймворк может отображать только тэги, о которых он знает. Нужно показать ему, что у нас есть свои компоненты и для этого создайте файл _ViewImports.cshtml в папке Views. Мы уже знакомы с файлом _ViewStart.cshtml, в котором мы можем указать имя шаблона, а _ViewImports.cshtml – отличное место для того, чтобы указывать такие вещи как – какие пространства имен мы хотим подключить в свои представления. Описание тэгов так же будет круто прописать именно здесь. Итак, создали файл с таким именим и помещаем в него всего одну строку:

@addTagHelper *, MyWebSite 

В данном случае MyWebSite – это пространство имен моего приложения и если вы посмотрите класс компонента, то он был именно в этом пространстве.

Все, можно запускать сайт и теперьдолжен сработать.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне