Часть 3. Добавление представления в приложение MVC ASP.NET Core

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в статье о политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

Автор: Рик Андерсон (Rick Anderson)

В этом разделе вы внесете изменения в класс HelloWorldController для использования файлов представления Razor. Это позволяет аккуратно инкапсулировать процесс создания HTML-ответов в клиент.

Шаблоны представлений создаются с помощью Razor. Шаблоны представлений на основе Razor:

  • имеют расширение файла .cshtml;
  • реализуют удобный способ для создания выходных данных HTML с помощью C#.

Сейчас метод Index возвращает строку с сообщением в классе контроллера. В классе HelloWorldController замените метод Index следующим кодом:

public IActionResult Index()
{
    return View();
}

Предыдущий код:

  • вызывает метод View контроллера;
  • использует шаблон представления для создания HTML-ответа.

Методы контроллера:

  • называются методами действий; например, метод действия Index в предыдущем коде;
  • обычно возвращают IActionResult или класс, производный от ActionResult, а не тип, например string.

Добавить представление

Щелкните правой кнопкой мыши папку Views, а затем выберите Добавить > Новая папка. Назовите папку HelloWorld.

Щелкните правой кнопкой мыши папку Views/HelloWorld, а затем выберите Добавить > Новый элемент.

В диалоговом окне "Добавить новый элемент" выберите "Показать все шаблоны".

В диалоговом окне Добавление нового элемента MvcMovie выполните следующие действия.

  • В поле поиска в правом верхнем углу введите view (представление).
  • Выберите Представление Razor — пустое
  • Сохраните значение поля "Имя". Index.cshtml
  • Выберите Добавить

Диалоговое окно ''Добавление нового элемента''

Замените содержимое файла представления Views/HelloWorld/Index.cshtmlRazor следующим.

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>

Перейдите к https://localhost:{PORT}/HelloWorld:

  • Метод Index в HelloWorldController выполнил оператор return View();, который указал, что метод должен использовать файл шаблона представления для отображения ответа в браузере.

  • Имя файла шаблона представления не указано, MVC по умолчанию использует файл представления по умолчанию. Если имя файла представления не указано, возвращается представление по умолчанию. В этом примере представление по умолчанию имеет то же имя, что и метод действия Index. Используется шаблон /Views/HelloWorld/Index.cshtml представления.

  • На изображении ниже показана строка "Hello from our View Template!", которая жестко задана в представлении:

    Окно браузера

Изменение представлений и страниц макета

Выберите ссылки в меню (MvcMovie, Home и Privacy). Меню на каждой странице имеют одинаковый макет. Макет меню реализуется в Views/Shared/_Layout.cshtml файле.

Откройте файл Views/Shared/_Layout.cshtml.

Шаблоны макета позволяют:

  • указать макет контейнера HTML сайта в одном месте;
  • применять макета контейнера HTML на нескольких страницах сайта.

Найдите строку @RenderBody(). RenderBody — это заполнитель, в котором отображаются все создаваемые страницы для определенных представлений, упакованные на странице макета. Например, если щелкнуть ссылку Privacy, представление Views/Home/Privacy.cshtml отобразится в методе RenderBody.

Замените содержимое файла Views/Shared/_Layout.cshtml следующей разметкой: Изменения выделены:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/MvcMovie.styles.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2024 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Приведенная выше разметка вносит следующие изменения:

  • замена трех вхождений MvcMovie на Movie App;
  • Замена элемента привязки <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a> на <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>.

В приведенной выше разметке атрибут вспомогательной функции тега привязки asp-area="" и значение атрибута были опущены, так как это приложение не использует области (Areas).

Примечание. Контроллер Movies не был реализован. На этом этапе ссылка Movie App не работает.

Сохраните изменения и щелкните ссылку Privacy. Обратите внимание, что заголовок вкладки браузера отображает Privacy Политика — Приложение Movie вместо Privacy Политика — MvcMovie.

Privacy — табуляция

Выберите ссылку Home.

Обратите внимание, что в заголовке и тексте привязки также отображается Movie App. Внеся одно изменение в шаблон макета, мы изменили заголовок и текст ссылки на всех страницах сайта.

Просмотрите файл Views/_ViewStart.cshtml.

@{
    Layout = "_Layout";
}

Файл Views/_ViewStart.cshtml переносит файл в каждое Views/Shared/_Layout.cshtml представление. Свойство Layout может задавать другое представление макета или иметь значение null, при котором макет не используется.

Откройте файл представления Views/HelloWorld/Index.cshtml.

Измените заголовок и элемент <h2>, как выделено ниже:

@{
    ViewData["Title"] = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

Заголовок и элемент <h2> немного отличаются, чтобы вы видели, какой именно фрагмент кода изменяет отображение.

ViewData["Title"] = "Movie List"; в приведенном выше коде присваивает свойству Title словаря ViewData значение "Movie List". Свойство Title используется в элементе HTML <title> на странице макета:

<title>@ViewData["Title"] - Movie App</title>

Сохраните изменения и перейдите к https://localhost:{PORT}/HelloWorld.

Обратите внимание, что были изменены следующие элементы:

  • Заголовок браузера.
  • Основной заголовок.
  • Дополнительные заголовки.

Если в браузере изменения не отображаются, это может означать, что содержимое кэшировано. В этом случае нажмите в браузере клавиши CTRL+F5 для принудительной загрузки ответа сервера. Заголовок браузера создается с помощью атрибута ViewData["Title"], который задается в шаблоне представления Index.cshtml и дополнительной строки "- Movie App", добавляемой в файл макета.

Содержимое Index.cshtml шаблона представления объединяется с шаблоном Views/Shared/_Layout.cshtml представления. В браузер отправляется один HTML-ответ. Шаблоны макетов позволяют легко вносить изменения, применяемые ко всем страницам в приложении. Дополнительные сведения см. в разделе Макет.

Представление списка фильмов

Небольшой фрагмент данных (сообщение "Hello from our View Template!") все равно жестко задан в коде. Приложение MVC предоставляет представление, вы реализуете контроллер, однако модели на данный момент еще нет.

Передача данных из контроллера в представление

Действия контроллера вызываются в ответ на входящий запрос URL-адреса. Код, обрабатывающий входящие запросы браузера, добавляется в класс контроллера. Контроллер извлекает данные из источника данных и определяет тип ответа, который будет отправлен в браузер. Контроллер может использовать шаблоны представлений для создания и форматирования ответа HTML, отправляемого браузеру.

Контроллер отвечает за предоставление данных, необходимых шаблону представления для отображения ответа.

Шаблоны представлений недолжны:

  • выполнять бизнес-логику;
  • непосредственно взаимодействовать с базой данных.

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

  • очистки;
  • тестирования;
  • обслуживания.

Сейчас метод Welcome в классе HelloWorldController принимает параметры name и ID, после чего выводит значения напрямую в браузер.

Вместо отображения ответа в виде строки настройте контроллер для использования шаблона представления. Шаблон представления создает динамический ответ, для получения которого необходимо передать соответствующие данные из контроллера в представление. Для этого контроллер может поместить динамические данные (параметры), которые требуются шаблону представления, в словарь ViewData, к которому впоследствии будет обращаться этот шаблон за динамическими данными.

В HelloWorldController.cs, измените Welcome метод, чтобы добавить Message и NumTimes значение в ViewData словарь.

Словарь ViewData представляет собой динамический объект, а это означает, что можно использовать любой тип. Объект ViewData не имеет определенных свойств, пока не будет добавлен какой-либо элемент. Система привязки модели MVC автоматически сопоставляет именованные параметры name и numTimes из строки запроса с параметрами метода. Полный HelloWorldController:

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

namespace MvcMovie.Controllers;

public class HelloWorldController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    public IActionResult Welcome(string name, int numTimes = 1)
    {
        ViewData["Message"] = "Hello " + name;
        ViewData["NumTimes"] = numTimes;
        return View();
    }
}

Объект словаря ViewData содержит данные, которые будут передаваться в представление.

Создайте шаблон представления приветствия с именем Views/HelloWorld/Welcome.cshtml.

В шаблоне представления Welcome.cshtml создайте цикл, который будет отображать строку "Hello" NumTimes. Замените все содержимое Views/HelloWorld/Welcome.cshtml следующим:

@{
    ViewData["Title"] = "Welcome";
}

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < (int)ViewData["NumTimes"]!; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

Сохраните изменения и перейдите по следующему URL-адресу:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

Данные извлекаются по URL-адресу и передаются в контроллер с помощью средства привязки модели MVC. Контроллер упаковывает данные в словарь ViewData и передает этот объект в представление. Представление отображает данные в формате HTML в браузере.

Privacy представление с меткой приветствия и фразой Hello Rick, показанной четыре раза

В примере выше мы использовали словарь ViewData для передачи данных из контроллера в представление. Далее в этом руководстве для передачи данных из контроллера в представление мы будем использовать модель представления. Подход к передаче данных на основе модели представления является предпочтительным относительно применения словаря ViewData.

В следующем руководстве создается база данных фильмов.

В этом разделе вы внесете изменения в класс HelloWorldController для использования файлов представления Razor. Это позволяет аккуратно инкапсулировать процесс создания HTML-ответов в клиент.

Шаблоны представлений создаются с помощью Razor. Шаблоны представлений на основе Razor:

  • имеют расширение файла .cshtml;
  • реализуют удобный способ для создания выходных данных HTML с помощью C#.

Сейчас метод Index возвращает строку с сообщением в классе контроллера. В классе HelloWorldController замените метод Index следующим кодом:

public IActionResult Index()
{
    return View();
}

Предыдущий код:

  • вызывает метод View контроллера;
  • использует шаблон представления для создания HTML-ответа.

Методы контроллера:

  • называются методами действий; например, метод действия Index в предыдущем коде;
  • обычно возвращают IActionResult или класс, производный от ActionResult, а не тип, например string.

Добавить представление

Щелкните правой кнопкой мыши папку Views, а затем выберите Добавить > Новая папка. Назовите папку HelloWorld.

Щелкните правой кнопкой мыши папку Views/HelloWorld, а затем выберите Добавить > Новый элемент.

В диалоговом окне "Добавить новый элемент" выберите "Показать все шаблоны".

В диалоговом окне Добавление нового элемента MvcMovie выполните следующие действия.

  • В поле поиска в правом верхнем углу введите view (представление).
  • Выберите Представление Razor — пустое
  • Сохраните значение поля "Имя". Index.cshtml
  • Выберите Добавить

Диалоговое окно ''Добавление нового элемента''

Замените содержимое файла представления Views/HelloWorld/Index.cshtmlRazor следующим.

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>

Перейдите к https://localhost:{PORT}/HelloWorld:

  • Метод Index в HelloWorldController выполнил оператор return View();, который указал, что метод должен использовать файл шаблона представления для отображения ответа в браузере.

  • Имя файла шаблона представления не указано, MVC по умолчанию использует файл представления по умолчанию. Если имя файла представления не указано, возвращается представление по умолчанию. В этом примере представление по умолчанию имеет то же имя, что и метод действия Index. Используется шаблон /Views/HelloWorld/Index.cshtml представления.

  • На изображении ниже показана строка "Hello from our View Template!", которая жестко задана в представлении:

    Окно браузера

Изменение представлений и страниц макета

Выберите ссылки в меню (MvcMovie, Home и Privacy). Меню на каждой странице имеют одинаковый макет. Макет меню реализуется в Views/Shared/_Layout.cshtml файле.

Откройте файл Views/Shared/_Layout.cshtml.

Шаблоны макета позволяют:

  • указать макет контейнера HTML сайта в одном месте;
  • применять макета контейнера HTML на нескольких страницах сайта.

Найдите строку @RenderBody(). RenderBody — это заполнитель, в котором отображаются все создаваемые страницы для определенных представлений, упакованные на странице макета. Например, если щелкнуть ссылку Privacy, представление Views/Home/Privacy.cshtml отобразится в методе RenderBody.

Замените содержимое файла Views/Shared/_Layout.cshtml следующей разметкой: Изменения выделены:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2023 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Приведенная выше разметка вносит следующие изменения:

  • замена трех вхождений MvcMovie на Movie App;
  • Замена элемента привязки <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a> на <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>.

В приведенной выше разметке атрибут вспомогательной функции тега привязки asp-area="" и значение атрибута были опущены, так как это приложение не использует области (Areas).

Примечание. Контроллер Movies не был реализован. На этом этапе ссылка Movie App не работает.

Сохраните изменения и щелкните ссылку Privacy. Обратите внимание, что заголовок вкладки браузера отображает Privacy Политика — Приложение Movie вместо Privacy Политика — MvcMovie.

Privacy — табуляция

Выберите ссылку Home.

Обратите внимание, что в заголовке и тексте привязки также отображается Movie App. Внеся одно изменение в шаблон макета, мы изменили заголовок и текст ссылки на всех страницах сайта.

Просмотрите файл Views/_ViewStart.cshtml.

@{
    Layout = "_Layout";
}

Файл Views/_ViewStart.cshtml переносит файл в каждое Views/Shared/_Layout.cshtml представление. Свойство Layout может задавать другое представление макета или иметь значение null, при котором макет не используется.

Откройте файл представления Views/HelloWorld/Index.cshtml.

Измените заголовок и элемент <h2>, как выделено ниже:

@{
    ViewData["Title"] = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

Заголовок и элемент <h2> немного отличаются, чтобы вы видели, какой именно фрагмент кода изменяет отображение.

ViewData["Title"] = "Movie List"; в приведенном выше коде присваивает свойству Title словаря ViewData значение "Movie List". Свойство Title используется в элементе HTML <title> на странице макета:

<title>@ViewData["Title"] - Movie App</title>

Сохраните изменения и перейдите к https://localhost:{PORT}/HelloWorld.

Обратите внимание, что были изменены следующие элементы:

  • Заголовок браузера.
  • Основной заголовок.
  • Дополнительные заголовки.

Если в браузере изменения не отображаются, это может означать, что содержимое кэшировано. В этом случае нажмите в браузере клавиши CTRL+F5 для принудительной загрузки ответа сервера. Заголовок браузера создается с помощью атрибута ViewData["Title"], который задается в шаблоне представления Index.cshtml и дополнительной строки "- Movie App", добавляемой в файл макета.

Содержимое Index.cshtml шаблона представления объединяется с шаблоном Views/Shared/_Layout.cshtml представления. В браузер отправляется один HTML-ответ. Шаблоны макетов позволяют легко вносить изменения, применяемые ко всем страницам в приложении. Дополнительные сведения см. в разделе Макет.

Представление списка фильмов

Небольшой фрагмент данных (сообщение "Hello from our View Template!") все равно жестко задан в коде. Приложение MVC предоставляет представление, вы реализуете контроллер, однако модели на данный момент еще нет.

Передача данных из контроллера в представление

Действия контроллера вызываются в ответ на входящий запрос URL-адреса. Код, обрабатывающий входящие запросы браузера, добавляется в класс контроллера. Контроллер извлекает данные из источника данных и определяет тип ответа, который будет отправлен в браузер. Контроллер может использовать шаблоны представлений для создания и форматирования ответа HTML, отправляемого браузеру.

Контроллер отвечает за предоставление данных, необходимых шаблону представления для отображения ответа.

Шаблоны представлений недолжны:

  • выполнять бизнес-логику;
  • непосредственно взаимодействовать с базой данных.

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

  • очистки;
  • тестирования;
  • обслуживания.

Сейчас метод Welcome в классе HelloWorldController принимает параметры name и ID, после чего выводит значения напрямую в браузер.

Вместо отображения ответа в виде строки настройте контроллер для использования шаблона представления. Шаблон представления создает динамический ответ, для получения которого необходимо передать соответствующие данные из контроллера в представление. Для этого контроллер может поместить динамические данные (параметры), которые требуются шаблону представления, в словарь ViewData, к которому впоследствии будет обращаться этот шаблон за динамическими данными.

В HelloWorldController.cs, измените Welcome метод, чтобы добавить Message и NumTimes значение в ViewData словарь.

Словарь ViewData представляет собой динамический объект, а это означает, что можно использовать любой тип. Объект ViewData не имеет определенных свойств, пока не будет добавлен какой-либо элемент. Система привязки модели MVC автоматически сопоставляет именованные параметры name и numTimes из строки запроса с параметрами метода. Полный HelloWorldController:

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

namespace MvcMovie.Controllers;

public class HelloWorldController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    public IActionResult Welcome(string name, int numTimes = 1)
    {
        ViewData["Message"] = "Hello " + name;
        ViewData["NumTimes"] = numTimes;
        return View();
    }
}

Объект словаря ViewData содержит данные, которые будут передаваться в представление.

Создайте шаблон представления приветствия с именем Views/HelloWorld/Welcome.cshtml.

В шаблоне представления Welcome.cshtml создайте цикл, который будет отображать строку "Hello" NumTimes. Замените все содержимое Views/HelloWorld/Welcome.cshtml следующим:

@{
    ViewData["Title"] = "Welcome";
}

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < (int)ViewData["NumTimes"]!; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

Сохраните изменения и перейдите по следующему URL-адресу:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

Данные извлекаются по URL-адресу и передаются в контроллер с помощью средства привязки модели MVC. Контроллер упаковывает данные в словарь ViewData и передает этот объект в представление. Представление отображает данные в формате HTML в браузере.

Privacy представление с меткой приветствия и фразой Hello Rick, показанной четыре раза

В примере выше мы использовали словарь ViewData для передачи данных из контроллера в представление. Далее в этом руководстве для передачи данных из контроллера в представление мы будем использовать модель представления. Подход к передаче данных на основе модели представления является предпочтительным относительно применения словаря ViewData.

В следующем руководстве создается база данных фильмов.

В этом разделе вы внесете изменения в класс HelloWorldController для использования файлов представления Razor. Это позволяет аккуратно инкапсулировать процесс создания HTML-ответов в клиент.

Шаблоны представлений создаются с помощью Razor. Шаблоны представлений на основе Razor:

  • имеют расширение файла .cshtml;
  • реализуют удобный способ для создания выходных данных HTML с помощью C#.

Сейчас метод Index возвращает строку с сообщением в классе контроллера. В классе HelloWorldController замените метод Index следующим кодом:

public IActionResult Index()
{
    return View();
}

Предыдущий код:

  • вызывает метод View контроллера;
  • использует шаблон представления для создания HTML-ответа.

Методы контроллера:

  • называются методами действий; например, метод действия Index в предыдущем коде;
  • обычно возвращают IActionResult или класс, производный от ActionResult, а не тип, например string.

Добавить представление

Щелкните правой кнопкой мыши папку Views, а затем выберите Добавить > Новая папка. Назовите папку HelloWorld.

Щелкните правой кнопкой мыши папку Views/HelloWorld, а затем выберите Добавить > Новый элемент.

В диалоговом окне Добавление нового элемента MvcMovie выполните следующие действия.

  • В поле поиска в правом верхнем углу введите view (представление).
  • Выберите Представление Razor — пустое
  • Сохраните значение поля "Имя". Index.cshtml
  • Выберите Добавить

Диалоговое окно ''Добавление нового элемента''

Замените содержимое файла представления Views/HelloWorld/Index.cshtmlRazor следующим.

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>

Перейдите к https://localhost:{PORT}/HelloWorld:

  • Метод Index в HelloWorldController выполнил оператор return View();, который указал, что метод должен использовать файл шаблона представления для отображения ответа в браузере.

  • Имя файла шаблона представления не указано, MVC по умолчанию использует файл представления по умолчанию. Если имя файла представления не указано, возвращается представление по умолчанию. В этом примере представление по умолчанию имеет то же имя, что и метод действия Index. Используется шаблон /Views/HelloWorld/Index.cshtml представления.

  • На изображении ниже показана строка "Hello from our View Template!", которая жестко задана в представлении:

    Окно браузера

Изменение представлений и страниц макета

Выберите ссылки в меню (MvcMovie, Home и Privacy). Меню на каждой странице имеют одинаковый макет. Макет меню реализуется в Views/Shared/_Layout.cshtml файле.

Откройте файл Views/Shared/_Layout.cshtml.

Шаблоны макета позволяют:

  • указать макет контейнера HTML сайта в одном месте;
  • применять макета контейнера HTML на нескольких страницах сайта.

Найдите строку @RenderBody(). RenderBody — это заполнитель, в котором отображаются все создаваемые страницы для определенных представлений, упакованные на странице макета. Например, если щелкнуть ссылку Privacy, представление Views/Home/Privacy.cshtml отобразится в методе RenderBody.

Замените содержимое файла Views/Shared/_Layout.cshtml следующей разметкой: Изменения выделены:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2022 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Приведенная выше разметка вносит следующие изменения:

  • замена трех вхождений MvcMovie на Movie App;
  • Замена элемента привязки <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a> на <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>.

В приведенной выше разметке атрибут вспомогательной функции тега привязки asp-area="" и значение атрибута были опущены, так как это приложение не использует области (Areas).

Примечание. Контроллер Movies не был реализован. На этом этапе ссылка Movie App не работает.

Сохраните изменения и щелкните ссылку Privacy. Обратите внимание, что заголовок вкладки браузера отображает Privacy Политика — Приложение Movie вместо Privacy Политика — MvcMovie.

Privacy — табуляция

Выберите ссылку Home.

Обратите внимание, что в заголовке и тексте привязки также отображается Movie App. Внеся одно изменение в шаблон макета, мы изменили заголовок и текст ссылки на всех страницах сайта.

Просмотрите файл Views/_ViewStart.cshtml.

@{
    Layout = "_Layout";
}

Файл Views/_ViewStart.cshtml переносит файл в каждое Views/Shared/_Layout.cshtml представление. Свойство Layout может задавать другое представление макета или иметь значение null, при котором макет не используется.

Откройте файл представления Views/HelloWorld/Index.cshtml.

Измените заголовок и элемент <h2>, как выделено ниже:

@{
    ViewData["Title"] = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

Заголовок и элемент <h2> немного отличаются, чтобы вы видели, какой именно фрагмент кода изменяет отображение.

ViewData["Title"] = "Movie List"; в приведенном выше коде присваивает свойству Title словаря ViewData значение "Movie List". Свойство Title используется в элементе HTML <title> на странице макета:

<title>@ViewData["Title"] - Movie App</title>

Сохраните изменения и перейдите к https://localhost:{PORT}/HelloWorld.

Обратите внимание, что были изменены следующие элементы:

  • Заголовок браузера.
  • Основной заголовок.
  • Дополнительные заголовки.

Если в браузере изменения не отображаются, это может означать, что содержимое кэшировано. В этом случае нажмите в браузере клавиши CTRL+F5 для принудительной загрузки ответа сервера. Заголовок браузера создается с помощью атрибута ViewData["Title"], который задается в шаблоне представления Index.cshtml и дополнительной строки "- Movie App", добавляемой в файл макета.

Содержимое Index.cshtml шаблона представления объединяется с шаблоном Views/Shared/_Layout.cshtml представления. В браузер отправляется один HTML-ответ. Шаблоны макетов позволяют легко вносить изменения, применяемые ко всем страницам в приложении. Дополнительные сведения см. в разделе Макет.

Представление списка фильмов

Небольшой фрагмент данных (сообщение "Hello from our View Template!") все равно жестко задан в коде. Приложение MVC предоставляет представление, вы реализуете контроллер, однако модели на данный момент еще нет.

Передача данных из контроллера в представление

Действия контроллера вызываются в ответ на входящий запрос URL-адреса. Код, обрабатывающий входящие запросы браузера, добавляется в класс контроллера. Контроллер извлекает данные из источника данных и определяет тип ответа, который будет отправлен в браузер. Контроллер может использовать шаблоны представлений для создания и форматирования ответа HTML, отправляемого браузеру.

Контроллер отвечает за предоставление данных, необходимых шаблону представления для отображения ответа.

Шаблоны представлений недолжны:

  • выполнять бизнес-логику;
  • непосредственно взаимодействовать с базой данных.

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

  • очистки;
  • тестирования;
  • обслуживания.

Сейчас метод Welcome в классе HelloWorldController принимает параметры name и ID, после чего выводит значения напрямую в браузер.

Вместо отображения ответа в виде строки настройте контроллер для использования шаблона представления. Шаблон представления создает динамический ответ, для получения которого необходимо передать соответствующие данные из контроллера в представление. Для этого контроллер может поместить динамические данные (параметры), которые требуются шаблону представления, в словарь ViewData, к которому впоследствии будет обращаться этот шаблон за динамическими данными.

В HelloWorldController.cs, измените Welcome метод, чтобы добавить Message и NumTimes значение в ViewData словарь.

Словарь ViewData представляет собой динамический объект, а это означает, что можно использовать любой тип. Объект ViewData не имеет определенных свойств, пока не будет добавлен какой-либо элемент. Система привязки модели MVC автоматически сопоставляет именованные параметры name и numTimes из строки запроса с параметрами метода. Полный HelloWorldController:

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

namespace MvcMovie.Controllers;

public class HelloWorldController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    public IActionResult Welcome(string name, int numTimes = 1)
    {
        ViewData["Message"] = "Hello " + name;
        ViewData["NumTimes"] = numTimes;
        return View();
    }
}

Объект словаря ViewData содержит данные, которые будут передаваться в представление.

Создайте шаблон представления приветствия с именем Views/HelloWorld/Welcome.cshtml.

В шаблоне представления Welcome.cshtml создайте цикл, который будет отображать строку "Hello" NumTimes. Замените все содержимое Views/HelloWorld/Welcome.cshtml следующим:

@{
    ViewData["Title"] = "Welcome";
}

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < (int)ViewData["NumTimes"]!; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

Сохраните изменения и перейдите по следующему URL-адресу:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

Данные извлекаются по URL-адресу и передаются в контроллер с помощью средства привязки модели MVC. Контроллер упаковывает данные в словарь ViewData и передает этот объект в представление. Представление отображает данные в формате HTML в браузере.

Privacy представление с меткой приветствия и фразой Hello Rick, показанной четыре раза

В примере выше мы использовали словарь ViewData для передачи данных из контроллера в представление. Далее в этом руководстве для передачи данных из контроллера в представление мы будем использовать модель представления. Подход к передаче данных на основе модели представления является предпочтительным относительно применения словаря ViewData.

В следующем руководстве создается база данных фильмов.

В этом разделе вы внесете изменения в класс HelloWorldController для использования файлов представления Razor. Это позволяет аккуратно инкапсулировать процесс создания HTML-ответов в клиент.

Шаблоны представлений создаются с помощью Razor. Шаблоны представлений на основе Razor:

  • имеют расширение файла .cshtml;
  • реализуют удобный способ для создания выходных данных HTML с помощью C#.

Сейчас метод Index возвращает строку с сообщением в классе контроллера. В классе HelloWorldController замените метод Index следующим кодом:

public IActionResult Index()
{
    return View();
}

Предыдущий код:

  • вызывает метод View контроллера;
  • использует шаблон представления для создания HTML-ответа.

Методы контроллера:

  • называются методами действий; например, метод действия Index в предыдущем коде;
  • обычно возвращают IActionResult или класс, производный от ActionResult, а не тип, например string.

Добавить представление

Щелкните правой кнопкой мыши папку Views, а затем выберите Добавить > Новая папка. Назовите папку HelloWorld.

Щелкните правой кнопкой мыши папку Views/HelloWorld, а затем выберите Добавить > Новый элемент.

В диалоговом окне Добавление нового элемента MvcMovie выполните следующие действия.

  • В поле поиска в правом верхнем углу введите view (представление).
  • Выберите Представление Razor — пустое
  • Сохраните значение поля "Имя". Index.cshtml
  • Выберите Добавить

Диалоговое окно ''Добавление нового элемента''

Замените содержимое файла представления Views/HelloWorld/Index.cshtmlRazor следующим.

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>

Перейдите к https://localhost:{PORT}/HelloWorld:

  • Метод Index в HelloWorldController выполнил оператор return View();, который указал, что метод должен использовать файл шаблона представления для отображения ответа в браузере.

  • Имя файла шаблона представления не указано, MVC по умолчанию использует файл представления по умолчанию. Если имя файла представления не указано, возвращается представление по умолчанию. В этом примере представление по умолчанию имеет то же имя, что и метод действия Index. Используется шаблон /Views/HelloWorld/Index.cshtml представления.

  • На изображении ниже показана строка "Hello from our View Template!", которая жестко задана в представлении:

    Окно браузера

Изменение представлений и страниц макета

Выберите ссылки в меню (MvcMovie, Home и Privacy). Меню на каждой странице имеют одинаковый макет. Макет меню реализуется в Views/Shared/_Layout.cshtml файле.

Откройте файл Views/Shared/_Layout.cshtml.

Шаблоны макета позволяют:

  • указать макет контейнера HTML сайта в одном месте;
  • применять макета контейнера HTML на нескольких страницах сайта.

Найдите строку @RenderBody(). RenderBody — это заполнитель, в котором отображаются все создаваемые страницы для определенных представлений, упакованные на странице макета. Например, если щелкнуть ссылку Privacy, представление Views/Home/Privacy.cshtml отобразится в методе RenderBody.

Замените содержимое файла Views/Shared/_Layout.cshtml следующей разметкой: Изменения выделены:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2021 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Приведенная выше разметка вносит следующие изменения:

  • замена трех вхождений MvcMovie на Movie App;
  • Замена элемента привязки <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a> на <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>.

В приведенной выше разметке атрибут вспомогательной функции тега привязки asp-area="" и значение атрибута были опущены, так как это приложение не использует области (Areas).

Примечание. Контроллер Movies не был реализован. На этом этапе ссылка Movie App не работает.

Сохраните изменения и щелкните ссылку Privacy. Обратите внимание, что заголовок вкладки браузера отображает Privacy Политика — Приложение Movie вместо Privacy Политика — MvcMovie.

Privacy — табуляция

Выберите ссылку Home.

Обратите внимание, что в заголовке и тексте привязки также отображается Movie App. Внеся одно изменение в шаблон макета, мы изменили заголовок и текст ссылки на всех страницах сайта.

Просмотрите файл Views/_ViewStart.cshtml.

@{
    Layout = "_Layout";
}

Файл Views/_ViewStart.cshtml переносит файл в каждое Views/Shared/_Layout.cshtml представление. Свойство Layout может задавать другое представление макета или иметь значение null, при котором макет не используется.

Откройте файл представления Views/HelloWorld/Index.cshtml.

Измените заголовок и элемент <h2>, как выделено ниже:

@{
    ViewData["Title"] = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

Заголовок и элемент <h2> немного отличаются, чтобы вы видели, какой именно фрагмент кода изменяет отображение.

ViewData["Title"] = "Movie List"; в приведенном выше коде присваивает свойству Title словаря ViewData значение "Movie List". Свойство Title используется в элементе HTML <title> на странице макета:

<title>@ViewData["Title"] - Movie App</title>

Сохраните изменения и перейдите к https://localhost:{PORT}/HelloWorld.

Обратите внимание, что были изменены следующие элементы:

  • Заголовок браузера.
  • Основной заголовок.
  • Дополнительные заголовки.

Если в браузере изменения не отображаются, это может означать, что содержимое кэшировано. В этом случае нажмите в браузере клавиши CTRL+F5 для принудительной загрузки ответа сервера. Заголовок браузера создается с помощью атрибута ViewData["Title"], который задается в шаблоне представления Index.cshtml и дополнительной строки "- Movie App", добавляемой в файл макета.

Содержимое Index.cshtml шаблона представления объединяется с шаблоном Views/Shared/_Layout.cshtml представления. В браузер отправляется один HTML-ответ. Шаблоны макетов позволяют легко вносить изменения, применяемые ко всем страницам в приложении. Дополнительные сведения см. в разделе Макет.

Представление списка фильмов

Небольшой фрагмент данных (сообщение "Hello from our View Template!") все равно жестко задан в коде. Приложение MVC предоставляет представление, вы реализуете контроллер, однако модели на данный момент еще нет.

Передача данных из контроллера в представление

Действия контроллера вызываются в ответ на входящий запрос URL-адреса. Код, обрабатывающий входящие запросы браузера, добавляется в класс контроллера. Контроллер извлекает данные из источника данных и определяет тип ответа, который будет отправлен в браузер. Контроллер может использовать шаблоны представлений для создания и форматирования ответа HTML, отправляемого браузеру.

Контроллер отвечает за предоставление данных, необходимых шаблону представления для отображения ответа.

Шаблоны представлений недолжны:

  • выполнять бизнес-логику;
  • непосредственно взаимодействовать с базой данных.

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

  • очистки;
  • тестирования;
  • обслуживания.

Сейчас метод Welcome в классе HelloWorldController принимает параметры name и ID, после чего выводит значения напрямую в браузер.

Вместо отображения ответа в виде строки настройте контроллер для использования шаблона представления. Шаблон представления создает динамический ответ, для получения которого необходимо передать соответствующие данные из контроллера в представление. Для этого контроллер может поместить динамические данные (параметры), которые требуются шаблону представления, в словарь ViewData, к которому впоследствии будет обращаться этот шаблон за динамическими данными.

В HelloWorldController.cs, измените Welcome метод, чтобы добавить Message и NumTimes значение в ViewData словарь.

Словарь ViewData представляет собой динамический объект, а это означает, что можно использовать любой тип. Объект ViewData не имеет определенных свойств, пока не будет добавлен какой-либо элемент. Система привязки модели MVC автоматически сопоставляет именованные параметры name и numTimes из строки запроса с параметрами метода. Полный HelloWorldController:

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

namespace MvcMovie.Controllers
{
    public class HelloWorldController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Welcome(string name, int numTimes = 1)
        {
            ViewData["Message"] = "Hello " + name;
            ViewData["NumTimes"] = numTimes;

            return View();
        }
    }
}

Объект словаря ViewData содержит данные, которые будут передаваться в представление.

Создайте шаблон представления приветствия с именем Views/HelloWorld/Welcome.cshtml.

В шаблоне представления Welcome.cshtml создайте цикл, который будет отображать строку "Hello" NumTimes. Замените все содержимое Views/HelloWorld/Welcome.cshtml следующим:

@{
    ViewData["Title"] = "Welcome";
}

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < (int)ViewData["NumTimes"]!; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

Сохраните изменения и перейдите по следующему URL-адресу:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

Данные извлекаются по URL-адресу и передаются в контроллер с помощью средства привязки модели MVC. Контроллер упаковывает данные в словарь ViewData и передает этот объект в представление. Представление отображает данные в формате HTML в браузере.

Privacy представление с меткой приветствия и фразой Hello Rick, показанной четыре раза

В примере выше мы использовали словарь ViewData для передачи данных из контроллера в представление. Далее в этом руководстве для передачи данных из контроллера в представление мы будем использовать модель представления. Подход к передаче данных на основе модели представления является предпочтительным относительно применения словаря ViewData.

В следующем руководстве создается база данных фильмов.

В этом разделе вы внесете изменения в класс HelloWorldController для использования файлов представления Razor. Это позволяет аккуратно инкапсулировать процесс создания HTML-ответов в клиент.

Шаблоны представлений создаются с помощью Razor. Шаблоны представлений на основе Razor:

  • имеют расширение файла .cshtml;
  • реализуют удобный способ для создания выходных данных HTML с помощью C#.

Сейчас метод Index возвращает строку с сообщением в классе контроллера. В классе HelloWorldController замените метод Index следующим кодом:

public IActionResult Index()
{
    return View();
}

Предыдущий код:

  • вызывает метод View контроллера;
  • использует шаблон представления для создания HTML-ответа.

Методы контроллера:

  • называются методами действий; например, метод действия Index в предыдущем коде;
  • обычно возвращают IActionResult или класс, производный от ActionResult, а не тип, например string.

Добавить представление

Щелкните правой кнопкой мыши папку Views, а затем выберите Добавить > Новая папка. Назовите папку HelloWorld.

Щелкните правой кнопкой мыши папку Views/HelloWorld, а затем выберите Добавить > Новый элемент.

В диалоговом окне Добавление нового элемента MvcMovie выполните следующие действия.

  • В поле поиска в правом верхнем углу введите view (представление).
  • Выберите Представление Razor — пустое
  • Сохраните значение поля "Имя". Index.cshtml
  • Выберите Добавить

Диалоговое окно ''Добавление нового элемента''

Замените содержимое файла представления Views/HelloWorld/Index.cshtmlRazor следующим.

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>

Перейдите к https://localhost:{PORT}/HelloWorld:

  • Метод Index в HelloWorldController выполнил оператор return View();, который указал, что метод должен использовать файл шаблона представления для отображения ответа в браузере.

  • Имя файла шаблона представления не указано, MVC по умолчанию использует файл представления по умолчанию. Если имя файла представления не указано, возвращается представление по умолчанию. В этом примере представление по умолчанию имеет то же имя, что и метод действия Index. Используется шаблон /Views/HelloWorld/Index.cshtml представления.

  • На изображении ниже показана строка "Hello from our View Template!", которая жестко задана в представлении:

    Окно браузера

Изменение представлений и страниц макета

Выберите ссылки в меню (MvcMovie, Home и Privacy). Меню на каждой странице имеют одинаковый макет. Макет меню реализуется в Views/Shared/_Layout.cshtml файле.

Откройте файл Views/Shared/_Layout.cshtml.

Шаблоны макета позволяют:

  • указать макет контейнера HTML сайта в одном месте;
  • применять макета контейнера HTML на нескольких страницах сайта.

Найдите строку @RenderBody(). RenderBody — это заполнитель, в котором отображаются все создаваемые страницы для определенных представлений, упакованные на странице макета. Например, если щелкнуть ссылку Privacy, представление Views/Home/Privacy.cshtml отобразится в методе RenderBody.

Замените содержимое файла Views/Shared/_Layout.cshtml следующей разметкой: Изменения выделены:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Приведенная выше разметка вносит следующие изменения:

  • замена трех вхождений MvcMovie на Movie App;
  • Замена элемента привязки <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a> на <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>.

В приведенной выше разметке атрибут вспомогательной функции тега привязки asp-area="" и значение атрибута были опущены, так как это приложение не использует области (Areas).

Примечание. Контроллер Movies не был реализован. На этом этапе ссылка Movie App не работает.

Сохраните изменения и щелкните ссылку Privacy. Обратите внимание, что заголовок вкладки браузера отображает Privacy Политика — Приложение Movie вместо Privacy Политика — MvcMovie.

Privacy — табуляция

Выберите ссылку Home.

Обратите внимание, что в заголовке и тексте привязки также отображается Movie App. Внеся одно изменение в шаблон макета, мы изменили заголовок и текст ссылки на всех страницах сайта.

Просмотрите файл Views/_ViewStart.cshtml.

@{
    Layout = "_Layout";
}

Файл Views/_ViewStart.cshtml переносит файл в каждое Views/Shared/_Layout.cshtml представление. Свойство Layout может задавать другое представление макета или иметь значение null, при котором макет не используется.

Откройте файл представления Views/HelloWorld/Index.cshtml.

Измените заголовок и элемент <h2>, как выделено ниже:

@{
    ViewData["Title"] = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

Заголовок и элемент <h2> немного отличаются, чтобы вы видели, какой именно фрагмент кода изменяет отображение.

ViewData["Title"] = "Movie List"; в приведенном выше коде присваивает свойству Title словаря ViewData значение "Movie List". Свойство Title используется в элементе HTML <title> на странице макета:

<title>@ViewData["Title"] - Movie App</title>

Сохраните изменения и перейдите к https://localhost:{PORT}/HelloWorld.

Обратите внимание, что были изменены следующие элементы:

  • Заголовок браузера.
  • Основной заголовок.
  • Дополнительные заголовки.

Если в браузере изменения не отображаются, это может означать, что содержимое кэшировано. В этом случае нажмите в браузере клавиши CTRL+F5 для принудительной загрузки ответа сервера. Заголовок браузера создается с помощью атрибута ViewData["Title"], который задается в шаблоне представления Index.cshtml и дополнительной строки "- Movie App", добавляемой в файл макета.

Содержимое Index.cshtml шаблона представления объединяется с шаблоном Views/Shared/_Layout.cshtml представления. В браузер отправляется один HTML-ответ. Шаблоны макетов позволяют легко вносить изменения, применяемые ко всем страницам в приложении. Дополнительные сведения см. в разделе Макет.

Представление списка фильмов

Небольшой фрагмент данных (сообщение "Hello from our View Template!") все равно жестко задан в коде. Приложение MVC предоставляет представление, вы реализуете контроллер, однако модели на данный момент еще нет.

Передача данных из контроллера в представление

Действия контроллера вызываются в ответ на входящий запрос URL-адреса. Код, обрабатывающий входящие запросы браузера, добавляется в класс контроллера. Контроллер извлекает данные из источника данных и определяет тип ответа, который будет отправлен в браузер. Контроллер может использовать шаблоны представлений для создания и форматирования ответа HTML, отправляемого браузеру.

Контроллер отвечает за предоставление данных, необходимых шаблону представления для отображения ответа.

Шаблоны представлений недолжны:

  • выполнять бизнес-логику;
  • непосредственно взаимодействовать с базой данных.

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

  • очистки;
  • тестирования;
  • обслуживания.

Сейчас метод Welcome в классе HelloWorldController принимает параметры name и ID, после чего выводит значения напрямую в браузер.

Вместо отображения ответа в виде строки настройте контроллер для использования шаблона представления. Шаблон представления создает динамический ответ, для получения которого необходимо передать соответствующие данные из контроллера в представление. Для этого контроллер может поместить динамические данные (параметры), которые требуются шаблону представления, в словарь ViewData, к которому впоследствии будет обращаться этот шаблон за динамическими данными.

В HelloWorldController.cs, измените Welcome метод, чтобы добавить Message и NumTimes значение в ViewData словарь.

Словарь ViewData представляет собой динамический объект, а это означает, что можно использовать любой тип. Объект ViewData не имеет определенных свойств, пока не будет добавлен какой-либо элемент. Система привязки модели MVC автоматически сопоставляет именованные параметры name и numTimes из строки запроса с параметрами метода. Полный HelloWorldController:

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

namespace MvcMovie.Controllers
{
    public class HelloWorldController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Welcome(string name, int numTimes = 1)
        {
            ViewData["Message"] = "Hello " + name;
            ViewData["NumTimes"] = numTimes;

            return View();
        }
    }
}

Объект словаря ViewData содержит данные, которые будут передаваться в представление.

Создайте шаблон представления приветствия с именем Views/HelloWorld/Welcome.cshtml.

В шаблоне представления Welcome.cshtml создайте цикл, который будет отображать строку "Hello" NumTimes. Замените все содержимое Views/HelloWorld/Welcome.cshtml следующим:

@{
    ViewData["Title"] = "Welcome";
}

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < (int)ViewData["NumTimes"]; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

Сохраните изменения и перейдите по следующему URL-адресу:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

Данные извлекаются по URL-адресу и передаются в контроллер с помощью средства привязки модели MVC. Контроллер упаковывает данные в словарь ViewData и передает этот объект в представление. Представление отображает данные в формате HTML в браузере.

Privacy представление с меткой приветствия и фразой Hello Rick, показанной четыре раза

В примере выше мы использовали словарь ViewData для передачи данных из контроллера в представление. Далее в этом руководстве для передачи данных из контроллера в представление мы будем использовать модель представления. Подход к передаче данных на основе модели представления является предпочтительным относительно применения словаря ViewData.

В следующем руководстве создается база данных фильмов.

В этом разделе вы внесете изменения в класс HelloWorldController для использования файлов представления Razor. Это позволяет аккуратно инкапсулировать процесс создания HTML-ответов в клиент.

Шаблоны представлений создаются с помощью Razor. Шаблоны представлений на основе Razor:

  • имеют расширение файла .cshtml;
  • реализуют удобный способ для создания выходных данных HTML с помощью C#.

Сейчас метод Index возвращает строку с сообщением в классе контроллера. В классе HelloWorldController замените метод Index следующим кодом:

public IActionResult Index()
{
    return View();
}

Предыдущий код:

  • вызывает метод View контроллера;
  • использует шаблон представления для создания HTML-ответа.

Методы контроллера:

  • называются методами действий; например, метод действия Index в предыдущем коде;
  • обычно возвращают IActionResult или класс, производный от ActionResult, а не тип, например string.

Добавить представление

Щелкните правой кнопкой мыши папку Views, а затем выберите Добавить > Новая папка. Назовите папку HelloWorld.

Щелкните правой кнопкой мыши папку Views/HelloWorld, а затем выберите Добавить > Новый элемент.

В диалоговом окне Добавление нового элемента MvcMovie выполните следующие действия.

  • В поле поиска в правом верхнем углу введите view (представление).
  • Выберите Представление Razor — пустое
  • Сохраните значение поля "Имя". Index.cshtml
  • Выберите Добавить

Диалоговое окно ''Добавление нового элемента''

Замените содержимое файла представления Views/HelloWorld/Index.cshtmlRazor следующим.

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>

Перейдите к https://localhost:{PORT}/HelloWorld:

  • Метод Index в HelloWorldController выполнил оператор return View();, который указал, что метод должен использовать файл шаблона представления для отображения ответа в браузере.

  • Имя файла шаблона представления не указано, MVC по умолчанию использует файл представления по умолчанию. Если имя файла представления не указано, возвращается представление по умолчанию. В этом примере представление по умолчанию имеет то же имя, что и метод действия Index. Используется шаблон /Views/HelloWorld/Index.cshtml представления.

  • На изображении ниже показана строка "Hello from our View Template!", которая жестко задана в представлении:

    Окно браузера

Изменение представлений и страниц макета

Выберите ссылки в меню (MvcMovie, Home и Privacy). Меню на каждой странице имеют одинаковый макет. Макет меню реализуется в Views/Shared/_Layout.cshtml файле.

Откройте файл Views/Shared/_Layout.cshtml.

Шаблоны макета позволяют:

  • указать макет контейнера HTML сайта в одном месте;
  • применять макета контейнера HTML на нескольких страницах сайта.

Найдите строку @RenderBody(). RenderBody — это заполнитель, в котором отображаются все создаваемые страницы для определенных представлений, упакованные на странице макета. Например, если щелкнуть ссылку Privacy, представление Views/Home/Privacy.cshtml отобразится в методе RenderBody.

Замените содержимое файла Views/Shared/_Layout.cshtml следующей разметкой: Изменения выделены:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
</body>
</html>

Приведенная выше разметка вносит следующие изменения:

  • замена трех вхождений MvcMovie на Movie App;
  • Замена элемента привязки <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a> на <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>.

В приведенной выше разметке атрибут вспомогательной функции тега привязки asp-area="" и значение атрибута были опущены, так как это приложение не использует области (Areas).

Примечание. Контроллер Movies не был реализован. На этом этапе ссылка Movie App не работает.

Сохраните изменения и щелкните ссылку Privacy. Обратите внимание, что заголовок вкладки браузера отображает Privacy Политика — Приложение Movie вместо Privacy Политика — MvcMovie.

Privacy — табуляция

Выберите ссылку Home.

Обратите внимание, что в заголовке и тексте привязки также отображается Movie App. Внеся одно изменение в шаблон макета, мы изменили заголовок и текст ссылки на всех страницах сайта.

Просмотрите файл Views/_ViewStart.cshtml.

@{
    Layout = "_Layout";
}

Файл Views/_ViewStart.cshtml переносит файл в каждое Views/Shared/_Layout.cshtml представление. Свойство Layout может задавать другое представление макета или иметь значение null, при котором макет не используется.

Откройте файл представления Views/HelloWorld/Index.cshtml.

Измените заголовок и элемент <h2>, как выделено ниже:

@{
    ViewData["Title"] = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

Заголовок и элемент <h2> немного отличаются, чтобы вы видели, какой именно фрагмент кода изменяет отображение.

ViewData["Title"] = "Movie List"; в приведенном выше коде присваивает свойству Title словаря ViewData значение "Movie List". Свойство Title используется в элементе HTML <title> на странице макета:

<title>@ViewData["Title"] - Movie App</title>

Сохраните изменения и перейдите к https://localhost:{PORT}/HelloWorld.

Обратите внимание, что были изменены следующие элементы:

  • Заголовок браузера.
  • Основной заголовок.
  • Дополнительные заголовки.

Если в браузере изменения не отображаются, это может означать, что содержимое кэшировано. В этом случае нажмите в браузере клавиши CTRL+F5 для принудительной загрузки ответа сервера. Заголовок браузера создается с помощью атрибута ViewData["Title"], который задается в шаблоне представления Index.cshtml и дополнительной строки "- Movie App", добавляемой в файл макета.

Содержимое Index.cshtml шаблона представления объединяется с шаблоном Views/Shared/_Layout.cshtml представления. В браузер отправляется один HTML-ответ. Шаблоны макетов позволяют легко вносить изменения, применяемые ко всем страницам в приложении. Дополнительные сведения см. в разделе Макет.

Представление списка фильмов

Небольшой фрагмент данных (сообщение "Hello from our View Template!") все равно жестко задан в коде. Приложение MVC предоставляет представление, вы реализуете контроллер, однако модели на данный момент еще нет.

Передача данных из контроллера в представление

Действия контроллера вызываются в ответ на входящий запрос URL-адреса. Код, обрабатывающий входящие запросы браузера, добавляется в класс контроллера. Контроллер извлекает данные из источника данных и определяет тип ответа, который будет отправлен в браузер. Контроллер может использовать шаблоны представлений для создания и форматирования ответа HTML, отправляемого браузеру.

Контроллер отвечает за предоставление данных, необходимых шаблону представления для отображения ответа.

Шаблоны представлений недолжны:

  • выполнять бизнес-логику;
  • непосредственно взаимодействовать с базой данных.

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

  • очистки;
  • тестирования;
  • обслуживания.

Сейчас метод Welcome в классе HelloWorldController принимает параметры name и ID, после чего выводит значения напрямую в браузер.

Вместо отображения ответа в виде строки настройте контроллер для использования шаблона представления. Шаблон представления создает динамический ответ, для получения которого необходимо передать соответствующие данные из контроллера в представление. Для этого контроллер может поместить динамические данные (параметры), которые требуются шаблону представления, в словарь ViewData, к которому впоследствии будет обращаться этот шаблон за динамическими данными.

В HelloWorldController.cs, измените Welcome метод, чтобы добавить Message и NumTimes значение в ViewData словарь.

Словарь ViewData представляет собой динамический объект, а это означает, что можно использовать любой тип. Объект ViewData не имеет определенных свойств, пока не будет добавлен какой-либо элемент. Система привязки модели MVC автоматически сопоставляет именованные параметры name и numTimes из строки запроса с параметрами метода. Полный HelloWorldController:

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

namespace MvcMovie.Controllers
{
    public class HelloWorldController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Welcome(string name, int numTimes = 1)
        {
            ViewData["Message"] = "Hello " + name;
            ViewData["NumTimes"] = numTimes;

            return View();
        }
    }
}

Объект словаря ViewData содержит данные, которые будут передаваться в представление.

Создайте шаблон представления приветствия с именем Views/HelloWorld/Welcome.cshtml.

В шаблоне представления Welcome.cshtml создайте цикл, который будет отображать строку "Hello" NumTimes. Замените все содержимое Views/HelloWorld/Welcome.cshtml следующим:

@{
    ViewData["Title"] = "Welcome";
}

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < (int)ViewData["NumTimes"]; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

Сохраните изменения и перейдите по следующему URL-адресу:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

Данные извлекаются по URL-адресу и передаются в контроллер с помощью средства привязки модели MVC. Контроллер упаковывает данные в словарь ViewData и передает этот объект в представление. Представление отображает данные в формате HTML в браузере.

Privacy представление с меткой приветствия и фразой Hello Rick, показанной четыре раза

В примере выше мы использовали словарь ViewData для передачи данных из контроллера в представление. Далее в этом руководстве для передачи данных из контроллера в представление мы будем использовать модель представления. Подход к передаче данных на основе модели представления является предпочтительным относительно применения словаря ViewData.

В следующем руководстве создается база данных фильмов.