4.1. Макеты Layout в .NET Core

Та информация, которая остается неизменной от страницы к странице, должна идти в файлы макета, или Layout. Если посмотреть на мой сайт Flenov.info, то это будет шапка (включая большую страницу наверху), рекламу и конечно подвал.

Файл шаблона – это такой же cshtml файл, как и уже знакомые нам. Для него обычно используют имя _Layout.cshtml. Символ подчеркивания указывает на то, что это специальный файл, который не вызывался в контроллере, и не является результатом работы какого-то кода.

Остальные страницы могут отображаться внутри основного шаблона. Следующее изображение показывает мой сайт blo.moe, который использует классическую разметку. Красным прямоугольником выделен блок страницы, который приходит из конкретной страницы View, а все остальное – это макет, хотя правая часть приходит на страницу из подключаемого файла.

Итак, с именем файла мы уже определились, а теперь нужно определиться с расположением. В главе 2.5. Представления мы знакомились с представлениями и тогда в случае неверного указания файла в тексте ошибки были пути, по которым фреймворк ищет эти файлы представлений. И имена папок были – такая же, как имя контроллера и Shared. Вторая – это как раз папка, в которой хранятся файлы, к которым можно получить доступ из любого места. Это как раз то, что нам нужно и именно здесь нужно создать файл макета.

Сейчас в нашем проекте нет такой папки, поэтому ее нужно создать. Кликаем правой кнопкой по View и выбираем Add -> New Folder.

Создав папку, внутри создаем файл макета, кликая правой кнопкой по папке Shared и выбираем File -> New File. Тут снова можно выбрать совершенно любое тип файла и указать в качестве имени _Layout.cshtml, а можно выбрать уже заранее подготовленный шаблон, который просто наполнит файл базовым смыслом. Имя шаблона MVC View Layout Page:

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

<!DOCTYPE html>

<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>@ViewBag.Title</title>
    </head>
    <body>
        <div>
            @RenderBody()
        </div>
    </body>
</html>

Расширение файла cshtml снова указывает на то, что это смесь CS и HTML файла и здесь мы можем писать абсолютно все то же самое. Просто модели как таковой нет. Здесь уже есть два вызова CS кода.

@RenderBody() – в этом месте будет отображено содержимое View, которое мы вызовем из контроллера. То есть если мы скажем, что представление rezortest/index.cshtml должно использовать этот макет, то содержимое index.cshtml будет размещено как раз в месте вызова RenderBody()

@ViewBag.Title – указывает на то, что мы хотим отобразить свойство Title от ViewBag. Мы с ViewBag еще не знакомились, поэтому я хотел бы представить вас этому прекрасному динамической структуре данных - dynamic. Она динамическая, потому что для создания нового поля достаточно просто написать его имя и присвоить значение, например, мы можем создать поле Test:

 ViewBag.Test = "Это строка";

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

Стопарики – скажет злопамятный алкоголик. Я же утверждал, что для передачи информации из контроллера в представления нужно использовать классы-модели. Да, именно так. Если вам нужно передать информацию, ваши помыслы должны быть в первую очередь направлены именно на модель. Только в крайних случаях, когда другого выхода нет, можно использовать ViewBag и заголовок – это как раз может быть таким случаем, потому что в макете у нас нет модели.

Есть еще один способ, но о нем мы пока говорить не будем, а раз уж VS подкинул нам такую подлянку и включил ViewBag в макет, с ним пришлось познакомится.

Я не могу сказать, что в использовании ViewBag есть что-то криминальное. Нет, его можно использовать, но лучше все же стараться обходить его стороной по мере возможности. На мой взгляд тогда код будет даже чище.

В некоторых других фреймворках в качестве модели можно передать более одного параметра, например, так работает популярный Symfony для PHP. Тут у нас такой гибкости нет, только одна модель и практически глобальная динамическая фигня в виде ViewBag.

Вернемся к нашему шаблону. Чтобы он был более наглядным, я добавил к нему заголовок и подвал:

<!DOCTYPE html>

<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>@ViewBag.Title</title>
    </head>
    <body>
        <div style="background:#eee; font-size:200%; padding:30px">
            Logo
        </div>
        <div>
            @RenderBody()
        </div>
        <div style="background:#eee; padding:30px">
            Copyright: www.flenov.info
        </div>
    </body>
</html>

Я знаю, устанавливать стили через атрибут style для каждого элемента в отдельности не очень эффективно, но это всего лишь пример и мы пока не будем усложнять жизнь отдельным CSS файлом, а все в одном месте, чтобы вы могли тут же видеть, что я изменил. В реальных приложениях конечно же стили будут отдельно, HTML отдельно, котлеты в холодильнике.

Теперь открываем файл Views/razortest/Index.cshtml и в нем убираем тэги типа html, body и все техническое, а оставляем только самое необходимое, что мы хотим отобразить в теле страницы внутри макета. А в самом начале добавляем такой код:

@{
    ViewBag.Title = "This is my index page";
    Layout = "~/Views/Shared/_Layout.cshtml";
} 

В первой строке мы устанавливаем заголовок страницы, присваивая строковое значение свойству ViewBag.Title. Как мы уже выяснили, макет потом сможет прочитать эту строку.

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

Итак, файл Index.cshtml должен выглядеть так:

@model MyWebSite.Model.Person

@{
    ViewBag.Title = "This is my index page";
    Layout = "~/Views/Shared/_Layout.cshtml";
}


<h1>Hello</h1>
<p>First Name: @("Mr. " + Model.FirstName.ToUpper())</p>
<p>Last Name: @Model.LastName</p>
<p>Age: @(Model.Age * 2)</p>
<p>Число: @(Int32.Parse("4"))</p>
<p>
    @if (Model.Age < 15)
    {
    <p>Классно быть молодым, но сайт только для старше 15</p>
}
else
{
    <p> отлично </p>
    int index = 10;
    <p> index = @index</p>
}
</p>

Если запустить этот пример, то в результате в браузере мы должны увидеть эту страницу:

Лого и футер пришли к нам из макета, а центральная часть уникальна для этой страницы.

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

Предыдущая глава

4.0. Представления в .NET

О блоге

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

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

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

Пишите мне