Обычно при обращении к веб-приложению пользователь ожидает получить веб-страницу с какими-нибудь данными. В MVC для этого, как правило, используются представления, которые определяют внешний вид приложения и на основе которых потом формируется веб-страница. В ASP.NET MVC Core представления - это файлы с расширением cshtml, которые содержат код пользовательского интерфейса в основном на языке html, а также конструкции Razor - специального движка представлений, который позволяет переходить от кода html к коду на языке C#.
Для хранения представлений в проекте ASP.NET Core предназначена папка Views. Например, если мы возьмем проект по типу ASP.NET Core Web App (Model-View-Controller), то мы увидим, что он содержит ряд представлений.
Структура каталога Views:
Во-первых, как правило, для каждого контроллера в проекте создается подкаталог в папке Views, который называется по имени контроллера и который хранит представления, используемые методами данного контроллера. Так, по умолчанию имеется контроллер HomeController и для него в папке Views есть подкаталог Home с представлениями для методов контроллера HomeController - в нашем случае это файлы Index.cshtml и Privacy.cshtml.
Также здесь есть папка Shared, которая хранит общие представления для всех контроллеров. По умолчанию это файлы _Layout.cshtml (используется в качестве мастер-страницы), Error.cshtml (использутся для отображения ошибок) и _ValidationScripsPartial.cshtml (частичное представление, которое подключает скрипты валидации формы).
И в корне каталога Views также можно найти два файла _ViewImports.cshtml и _ViewStart.cshtml. Эти файлы содержат код, который автоматически добавляется ко всем представлениям. _ViewImports.cshtml устанавливает некоторые общие для всех представлений пространства имен, а _ViewStart.cshtml устанавливает общую мастер-страницу.
Вспомним, как выглядел метод, реализующий действие в контроллере
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
За работу с представлениями отвечает объект ViewResult. Он производит рендеринг представления в веб-страницу и возвращает ее в виде ответа клиенту. Чтобы возвратить объект ViewResult, в методе контроллера вызывается метод View.
Вызов метода View возвращает объект ViewResult. Затем уже ViewResult производит рендеринг определенного представления в ответ. По умолчанию контроллер производит поиск представления в проекте по следующим путям:
/Views/Имя_контроллера/Имя_представления.cshtml
/Views/Shared/Имя_представления.cshtml
Согласно настройкам по умолчанию, если название представления не указано явным образом, то в качестве представления будет использоваться то, имя которого совпадает с именем действия контроллера. Например, вышеопределенное действие Index по умолчанию будет производить поиск представления Index.cshtml в папке /Views/Home/.
Метод View() имеет четыре перегруженных версии:
Вторая версия метода позволяет переопределить используемое представление. Если представление находится в той же папке, которая предназначена для данного контроллера, то в метод View() достаточно передать название представления без расширения:
public IActionResult Index()
{
return View("About");
}
В этом случае метод Index будет использовать представление по пути Views/Home/About.cshtml. Если же представление находится в другой папке, то нам надо передать полный путь к представлению:
public IActionResult Index()
{
return View("~/Views/Some/About.cshtml");
}
В данном случае предполагается, что представление располагается по пути Views/Some/About.cshtml
Напомню как выглядит представление Index.cshtml:
@{ViewData["Title"] = "Заголовок нашего MVC приложения";}
<div class="text-center">
<h1 class="display-4">Привет ЙОТК!</h1>
</div>
А где же теги <head> и <body>? Внимательно перечитываем текущий параграф и видим, что есть еще какая-то мастер-страница _ViewStart.cshtml - посмотрим что в ней:
@{
Layout = "_Layout";
}
Блок кода @{} содержит вставку кода C#, в которой задается Layout. _Layout это название файла, который лежит в каталоге Shared (не привязан к какому-то контроллеру, так как используется во всех контроллерах приложения) и содержит шаблон для верстки:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - asp_net_mvc</title>
<script type="importmap"></script>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/asp_net_mvc.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="Home" asp-action="Index">asp_net_mvc</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 вернет текстовое представление текущего представления -->
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2025 - asp_net_mvc - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Это уже похоже на нормальный html. Содержимое представления вставляется вместо вызова @RenderBody().
Представления в ASP.NET Core MVC может содержать не только стандартный код html, но и также вставки кода на языке C#. Для обработки кода, который содержит как элементы html, так и конструкции языка C#, применяется движок представлений.
В действительности при вызове метода View контроллер не производит рендеринг представления и не генерирует разметку html. Контроллер только готовит данные и выбирает, какое представление надо возвратить в качестве объекта ViewResult. Затем уже объект ViewResult обращается к движку представления для рендеринга представления в выходной ответ.
По умолчанию в ASP.NET Core MVC применяется один движок представлений - Razor. Хотя при желании мы можем также использовать какие-то другие сторонние движки или создать свой движок представлений самостоятельно. Цель движка представлений Razor - определить переход от разметки html к коду C#.
Синтаксис Razor довольно прост - все его конструкции предваряются символом @, после которого происходит переход к коду C#.
Например, в файле _Layout.cshtml есть такие вставки:
тут в тег title вставляется содержимое словаря ViewData (мы это значение заполняли в файле Index.cshtml)
<title>@ViewData["Title"] - asp_net_mvc</title>
а тут вызывается функция RenderBody
<main role="main" class="pb-3">
@RenderBody()
</main>
Все конструкции Razor можно условно разделить на два вида: однострочные выражения и блоки кода.
Пример применения однострочных выражений:
<p>Date: @DateTime.Now.ToLongDateString()</p>
В данном случае используется объект DateTime и его метод ToLongDateString()
Или еще один пример:
<p>@(20 + 30)</p>
Так как перед скобками стоит знак @, то выражение в скобках будет интерпретироваться как выражение на языке C#. Поэтому браузер выведет число 50, а не строку "20 + 30".
Но если вдруг мы создаем код html, в котором присутствует символ @ не как часть синтаксиса Razor, а сам по себе, то, чтобы его отобразить, нам надо его дублировать:
<p>@@DateTime.Now = @DateTime.Now.ToLongDateString()</p>
Блоки кода могут иметь несколько выражений. Блок кода заключается в фигурные скобки, а каждое выражение завершается точкой с запятой аналогично блокам кода и выражениям на C#:
@{
ViewData["Title"] = "Home Page";
}
В блоках кода мы можем определить обычные переменные и потом их использовать в представлении.
В Razor могут использоваться комментарии. Они располагаются между символами @* *@:
@* текст комментария *@
Также мы можем использовать условные конструкции:
@{
string morning = "Good Morning";
string evening = "Good Evening";
string hello = "Hello";
int hour = DateTime.Now.Hour;
}
@if (hour < 12)
{
<h2>@morning</h2>
}
else if (hour > 17)
{
<h2>@evening</h2>
}
else
{
<h2>@hello</h2>
}
Конструкция switch:
@{
string language = "german";
}
@switch(language)
{
case "russian":
<h3>Привет мир!</h3>
break;
case "german":
<h3>Hallo Welt!</h3>
break;
default:
<h3>Hello World!</h3>
break;
}
Кроме того, мы можем использовать все возможные циклы. Цикл for:
@{
string[] people = { "Tom", "Sam", "Bob" };
}
<ul>
@for (var i = 0; i < people.Length; i++)
{
<li>@people[i]</li>
}
</ul>
Цикл foreach:
@{
string[] people = { "Tom", "Sam", "Bob" };
}
<ul>
@foreach (var person in people)
{
<li>@person</li>
}
</ul>
Цикл while:
@{
string[] people = { "Tom", "Sam", "Bob" };
var i = 0;
}
<ul>
@while ( i < people.Length)
{
<li>@people[i++]</li>
}
</ul>
Цикл do..while:
@{
var i = 0;
}
<ul>
@do
{
<li>@(i * i)</li>
}
while ( i++ < 5);
</ul>
Конструкция try...catch...finally, как и в C#, позволяет обработать исключение, которое может возникнуть при выполнение кода:
@try
{
throw new InvalidOperationException("Something wrong");
}
catch (Exception ex)
{
<p>Exception: @ex.Message</p>
}
finally
{
<p>finally</p>
}
Если в блоке try выбрасывается исключение, то выполняется блок catch. И в любом случае в конце блока try и catch выполняется блок finaly.
Обычный текст в блоке кода мы не сможем вывести:
@{
bool isEnabled = true;
}
@if (isEnabled)
{
Hello World
}
В этом случае Razor будет рассматривать строку "Hello World" как набор операторов языка C#, которых, естественно в C# нет, поэтому мы получим ошибку. И чтобы вывести текст как есть в блоке кода, нам надо использовать выражение @::
@{
bool isEnabled = true;
}
@if (isEnabled)
{
@: Hello
}
Директива @functions позволяет определить функции, которые могут применяться в представлении. Например:
@functions
{
public int Sum(int a, int b)
{
return a + b;
}
public int Square(int n) => n * n;
}
<p>Sum of 5 and 4: <b> @Sum(5, 4)</b></p>
<p>Square of 4: <b>@Square(4)</b></p>
Существуют различные способы передачи данных из контроллера в представление:
ViewData представляет словарь из пар ключ-значение:
public IActionResult Index()
{
ViewData["Message"] = "Hello METANIT.COM";
return View();
}
Здесь динамически определяется во ViewData объект с ключом "Message" и значением "Hello METANIT.COM". При этом в качестве значения может выступать любой объект. И после этому мы можем его использовать в представлении:
@{
ViewData["Title"] = "ASP.NET Core MVC";
}
<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>
Причем не обязательно устанавливать все объекты во ViewData в контроллере. Так, в данном случае объект с ключом "Title" устанавливается непосредственно в представлении.
ViewBag во многом подобен ViewData. Он позволяет определить различные свойства и присвоить им любое значение. Так, мы могли бы переписать предыдущий пример следующим образом:
public IActionResult Index()
{
ViewBag.Message = "Hello METANIT.COM";
return View();
}
И таким же образом нам надо было бы изменить представление:
@{
ViewBag.Title = "ASP.NET Core MVC";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
И не важно, что изначально объект ViewBag не содержит никакого свойства Message, оно определяется динамически. При этом свойства ViewBag могут содержать не только простые объекты типа string или int, но и сложные данные. Например, передадим список:
public IActionResult Index()
{
ViewBag.People = new List<string> { "Tom", "Sam", "Bob" };
return View();
}
И также в представлении мы можем получить этот список:
<h2>Count: @ViewBag.People.Count</h2>
<ul>
@foreach(string person in ViewBag.People)
{
<li>@person</li>
}
</ul>
Модель представления является во многих случаях более предпочтительным способом для передачи данных в представление. Для передачи данных в представление используется одна из версий метода View:
public IActionResult Index()
{
var people = new List<string> { "Tom", "Sam", "Bob" };
return View(people);
}
В метод View передается список, поэтому моделью представления Index.cshtml будет тип List (либо IEnumerable). И теперь в представлении мы можем написать так:
@model List<string>
<h2>Count: @Model.Count</h2>
<ul>
@foreach(string person in Model)
{
<li>@person</li>
}
</ul>
В самом начале представления с помощью директивы @model устанавливается модель представления. Тип модели должен совпадать с типом объекта, который передается в метод View() в контроллере.
Установка модели указывает, что объект Model теперь будет представлять объект List<string> или список. И мы сможем использовать Model в качестве списка.
Мастер-страницы или layout позволяют задать единый шаблон для представлений и применяются для создания единообразного, унифицированного вида сайта. По сути мастер-страницы - это те же самые представления, которе могут включать в себя другие представления. Например, можно определить на мастер-странице общие для всех остальных представлений меню, а также подключить общие стили и скрипты. В итоге нам не придется на каждом отдельном представлении прописывать путь к файлам стилей, а потом при необходимости его изменять. А специальные теги позволяют вставлять в определенное место на мастер-страницах другие представления.
Код мастер-страницы напоминает полноценную веб-страницу: здесь присутствуют основные теги <html>, <head>, <body> и так далее. И также здесь могут использоваться конструкции Razor. Фактически это то же самое представление. Например, через выраженеи @ViewBag.Title из каждого отдельного представления будет передаваться значение для заголовка веб-страницы.
Главное же отличие от обычных представлений состоит в использовании метода @RenderBody(), который является плейсхолдером и на место которого потом будут подставляться другие представления, использующие данную мастер-страницу. В итоге мы сможем легко установить для всех представлений веб-приложения единообразный стиль оформления.
В каждом представлении через синтаксис Razor доступно свойство Layout, которое хранит ссылку на мастер-страницу. В качестве мастер страницы устанавливается файл _Layout.cshtml, но мы, при желании, можем поменять файл шаблона, переписав свойство Layout в контроллере или представлении.
Если вдруг мы хотим глобально по всему проекту поменять мастер-страницу на другой файл, который расположен в какой-то другой папке, например, в корне каталога Views, то нам надо использовать полный путь к файлу в _ViewStart.cshtml:
@{
Layout = "~/Views/_Layout.cshtml";
}
Код из _ViewStart.cshtml выполняется до любого кода в представлении. И чтобы переопределить мастер-страницу, в представлении доcтаточно установить свойство Layout.
Естественно также мы можем переопределить мастер-страницу в каждом отдельном представлении с помощью свойства Layout.
@{
ViewBag.Title = "Home Page";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Представление Index.cshtml</h2>
Мы можем вообще не использовать мастер-страницу, тогда в представлении свойству Layout надо присвоить значение null:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Home Page</title>
</head>
<body>
<h2>Представление Index.cshtml</h2>
</body>
</html>
Кроме метода RenderBody(), который вставляет основное содержимое представлений, мастер-страниц может также использовать специальный метод RenderSection() для вставки секций. Мастер-страница может иметь несколько секций, куда представления могут поместить свое содержимое. Например, добавим к мастер-странице _Layout.cshtml секцию с именем "footer":
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>METANIT.COM | @ViewBag.Title</title>
</head>
<body>
<h2>@ViewBag.Title</h2>
<div><a href="/Home/Index">Home</a> | <a href="/Home/About">About</a></div>
<div>
@RenderBody()
</div>
<footer>@RenderSection("Footer")</footer>
</body>
</html>
Теперь при запуске предыдущего представления Index мы получим ошибку, так как секция Footer не определена. По умолчанию представление должно передавать содержание для каждой секции мастер-страницы. Поэтому добавим вниз представления Index секцию footer. Это мы можем сделать с помощью выражения @section:
@{
ViewBag.Title = "Index";
}
</h3>Index Content</h3>
@section Footer {
Copyright© Metanit.com, @DateTime.Now.Year. All rights reserved
}
Но при таком подходе, если у нас есть куча представлений, и мы вдруг захотели определить новую секцию на мастер-странице, нам придется изменить все имеющиеся представления, что не очень удобно. В этом случае мы можем воспользоваться одним из вариантов гибкой настройки секций.
Первый вариант заключается в использовании перегруженной версии метода RenderSection, которая позволяет указать, что данную секцию не обязательно определять в представлении. Чтобы отметить секцию Footer в качестве необязательной, надо передать в метод в качестве второго параметра значение false:
<footer>@RenderSection("Footer", false)</footer>
Второй вариант позволяет задать содержание секции по умолчанию, если данная секция не определена в представлении:
<footer>
@if (IsSectionDefined("Footer"))
{
@RenderSection("Footer")
}
else
{
<span>Содержание элемента footer по умолчанию.</span>
}
</footer>
Файл _ViewImports.cshtml позволяет по умолчанию подключить в представления некоторый функционал. Сначала рассмотрим ситуацию, с которой мы можем столкнуться. Пусть у нас в проекте есть некоторый класс Person:
namespace MvcApp
{
public record class Person(string Name, int Age);
}
Допустим, мы хотим использовать тип Person в представлении Index.cshtml:
@using MvcApp @* Подключаем пространство имен класса Person *@
@{
Layout = null;
Person tom = new Person("Tom", 37);
}
<h2>Person Data</h2>
<h3>Name: @tom.Name</h3>
<h3>Age: @tom.Age</h3>
Чтобы использовать тип Person в представлении, мы вынуждены импортировать с помощью директивы using пространство имен, где этот тип определен. В данном случае ничего сложного нет, однако если у нас куча представлений, где мы хотим использовать этот же тип Person, то мы будем вынуждены определить то же самое выражение импорта во всех представлениях. Это может создавать некоторые неудобства. Во-первых, мы повторяем один и тот же код. Во-вторых, если пространство имен изменится, то мы вынуждены будем менять все представления. В-третьих, возможно, мы захотим подключить еще какие-то пространства имен, что увеличит работу, если будут какие-то изменения. Файл _ViewImports.cshtml решает эту проблему
Содержимое файла _ViewImports.cshtml в моем проекте:
@using asp_net_mvc
@using asp_net_mvc.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Для каждой группы представлений в одной папке мы можем определить свой файл _ViewImports.cshtml. Например, если мы хотим отдельно подключать ряд пространств имен в только в представления контроллера HomeController, тогда нам надо добавить файл _ViewImports.cshtml в каталог Views/Home
Кроме обычных представлений и мастер-страниц в ASP.NET Core MVC также можно использовать частичные представления или partial views. Их отличительной особенностью является то, что их можно встраивать в другие обычные представления. Частичные представления могут использоваться также как и обычные, однако наиболее удобной областью их использования является рендеринг результатов AJAX-запроса. По своему действию частичные представления похожи на секции, которые использовались в прошлой теме, только их код выносится в отдельные файлы.
Частичные представления полезны для создания различных панелей веб-страницы, например, панели меню, блока входа на сайт, каких-то других блоков.
За рендеринг частичных представлений отвечает объект PartialViewResult, который возвращается методом PartialView(). Этот метод имеет четыре версии:
Итак, определим в контроллере HomeController действие Hello, которое будет использовать частичное представление:
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Hello()
{
return PartialView();
}
}
Теперь добавим в папку Views/Home новое представление Hello.cshtml, в котором будет простенькое содержимое:
<h2>Hello View</h2>
Теперь обратимся к методу Hello как к обычному действию контроллера, и оно нам вернет частичное представление
По своему действию частичное представление похоже на обычное, только для него по умолчанию не определяется мастер-страница (то есть в ответе на запрос не будет ни заголовков ни шаблона, а только тот html, который есть в частичном представлении).
Теперь рассмотрим, как мы можем встраивать частичные представления в обычные. Для этого изменим представление Index.cshtml:
<h1>Index View</h1>
@await Html.PartialAsync("Hello")
Метод Html.PartialAsync() встраивает код частичного представления в обычное. Он является асинхронным и возвращает объект IHtmlContent, который представляет html-содержимое и который обернут в объект Task<TResult>.
Обращения к методу Hello() в контроллере при этом не происходит.
Кроме метода Html.PartialAsync() частичное представление можно встроить с помощью другого метода - Html.RenderPartialAsync. Этот метод также принимает имя представления, только он используется не в строчных выражениях кода Razor, а в блоке кода, то есть обрамляется фигурными скобками:
@{
await Html.RenderPartialAsync("Hello");
}
Html.RenderPartialAsync напрямую пишет вывод в выходной поток в асинхронном режиме, поэтому может работать чуть быстрее, чем Html.PartialAsync.
Одна из перегруженных версий методов Html.PartialAsync / Html.RenderPartialAsync позволяет передать модель в частичное представление. В итоге у нас получится стандартное строго типизированное представление. Например, в качестве второго параметра список строк:
<h1>Welcome</h1>
@await Html.PartialAsync("Hello", new List<string>{"Hello", "Привет", "Hallo", "Salut"})
Поскольку здесь в частичное представление передается список строк, то мы можем использовать модель List<string>, чтобы получить этот список. Теперь изменим частичное представление Hello.cshtml:
@model IEnumerable<string>
<ul>
@foreach(string s in Model)
{
<li>@s</li>
}
</ul>
Формы html представляют одну из форм передачи наборов данных на сервер. Обычно для создания форм и их элементов в MVC применяются либо html-хелперы, либо tag-хелперы, которые рассматриваются далее. Однако в данном случае мы рассмотрим взаимодействие на примере стандартных тегов html, которые создают элементы формы.
В одной из прошлых тем было рассмотрено, как MVC связывает отправленные значения формы с параметрами метода. Например, у нас есть действие Index:
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index() => View();
[HttpPost]
public string Index(string username) => $"User Name: {username}";
}
Одно действие разделено на два метода: GET-версию, которая отдает представление с формой ввода, и POST-версию, которая принимает введенные в эту форму данные.
Теперь создадим само представление. Создайье в папке Views/Home представление Index.cshtml со следующим кодом:
<h2>User Name Form</h2>
<form method="post">
<label>User Name:</label><br />
<input type="text" name="username" /><br />
<input type="submit" value="Send" />
</form>
Чтобы инфраструктура MVC могла автоматически связать данные из формы с параметрами метода, значения атрибутов name у полей формы совпадают с именами параметров.
Таким образом, когда форма отправится на сервер, при обработке запроса фреймворк MVC автоматически свяжет значения полей формы с параметрами:
В HTML мы можем использовать ряд встроенных элементов. Для ввода строк используется элементы <input type="text" /> (для однострочного текста) и textarea (для многострочного текста).
Для ввода парольной информации можно применять элемент <input type="password" />
Для ввода чисел (которые соответствуют типа int, short, byte, long, float, double) используется элемент <input type="number" />
Например, метод принимает ряд значений:
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index() => View();
[HttpPost]
public string Index(string username, string password, int age, string comment)
{
return $"User Name: {username} Password: {password} Age: {age} Comment: {comment}";
}
}
Тогда форма в представлении могла бы выглядеть следующим образом:
<h2>User Form</h2>
<form method="post">
<p>
<label>User Name:</label><br />
<input type="text" name="username" />
</p>
<p>
<label>Password:</label><br />
<input type="password" name="password" />
</p>
<p>
<label>Age:</label><br />
<input type="number" name="age" />
</p>
<p>
<label>Comment:</label><br />
<textarea name="comment"></textarea>
</p>
<p>
<input type="submit" value="Send" />
</p>
</form>
Для передачи логических значений true или false удобно использовать элемент <input type="checkbox" />. Например, пусть метод принимает объект типа bool:
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index() => View();
[HttpPost]
public string Index(bool isMarried) => $"isMarried: {isMarried}";
}
Тогда мы могли бы определить следующий элемент input:
<form method="post">
<label>Is Married:</label>
<input type="checkbox" name="isMarried" value="true"/><br /><br />
<input type="submit" value="Send" />
</form>
Для связи с параметром метода элемент input называется по имени параметра - isMarried. И, кроме того, это поле имеет по умолчанию значение true.
Радиокнопки или переключатели позволяют выбрать один из нескольких вариантов. Для их создания используется элемент <input type="radio" />:
<form method="post">
<input name="color" type="radio" value="red" />
<span>red</span> <br />
<input name="color" type="radio" value="blue" />
<span>blue</span> <br />
<input checked="checked" name="color" type="radio" value="green" />
<span>green</span>
<p>
<input type="submit" value="Send" />
</p>
</form>
Все радиокнопки имеют одинаковое имя - color и отличаются только значением, которое хранится в атрибуте value. В контроллере мы могли бы получить выбранное значение в виде обычной строки:
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index() => View();
[HttpPost]
public string Index(string color) => $"color: {color}";
}
Элемент select предназначен для создания двух видов списков - выпадающих и развернутых.
В выпадающем списке мы можем выбрать один элемент:
<form method="post">
<p>
<label for="language">Выберите язык:</label>
<select name="language">
<option value="csharp">C#</option>
<option value="vbnet">Visual Basic.NET</option>
<option value="fsharp">F#</option>
<option value="typescript">TypeScript</option>
</select>
</p>
<p>
<input type="submit" value="Отправить" />
</p>
</form>
При этом отображаемый текст элемента списка необязательно должен совпадать с его значением. Например:
<option value="csharp">C#</option>
Здесь текст "C#" - это то, что мы увидим в списке, а "csharp" - это значение, которое при выборе данного элемента отправится на сервер.
Чтобы получить выбранный в этом списке элемент, параметр метода контроллера должен называться также, как и элемент select:
[HttpPost]
public string Index(string language) => $"Language: {language}";
Для создания списка со множественным выбором к элементу select добавляется атрибут multiple:
<form method="post">
<p>
<label for="language">Выберите язык:</label>
<select
multiple
^^^^^^^^
name="languages"
>
<option value="csharp">C#</option>
<option value="vbnet">Visual Basic.NET</option>
<option value="fsharp">F#</option>
<option value="typescript">TypeScript</option>
</select>
</p>
<p>
<input type="submit" value="Отправить" />
</p>
</form>
Но теперь, чтобы получить все выбранные значения в этом списке, метод контроллера должен в качестве параметра принимать массив или список:
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index() => View();
[HttpPost]
public string Index(string[] languages)
{
string result = "Вы выбрали:";
foreach (string lang in languages)
{
result = $"{result} {lang};";
}
return result;
}
}
Сделать репозиторий - конспект, то есть создать приложение и в конспекте привести блоки кода и скриншоты для всех примеров из лекции.