Теоретическая часть.
Контроллеры часто нуждаются в доступе к данным из входящего запроса, таким как значения строки запроса, значения формы и параметры, извлеченные из URL системой маршрутизации. Существуют три основных способа доступа к таким данным:
В этой статье мы рассмотрим подходы к получению исходных данных для методов действий, концентрируя основное внимание на объектах контекста и параметрах методов действий.
Когда вы создаете контроллер путем его наследования от базового класса Controller, то получаете в свое распоряжение набор удобных свойств для доступа к информации, касающейся запроса. К таким свойствам относятся Request, Response, RouteData, HttpContext и Server. Каждое перечисленное свойство отвечает за конкретный аспект запроса. Мы называем их удобными свойствами, поскольку каждое из них извлекает определенный тип данных из экземпляра ControllerContext для запроса (который доступен через свойство Controller.ControllerContext).
Наиболее часто используемые объекты контекста и свойства описаны в таблице ниже:
Свойство | Тип | Описание |
---|---|---|
Request.QueryString | NameValueCollection | Переменные GET, отправленные с этим запросом |
Request.Form | NameValueCollection | Переменные POST, отправленные с этим запросом |
Request.Cookies | HttpCookieCollection | Cookie-наборы, отправленные браузером с этим запросом |
Request.HttpMethod | string | Метод HTTP (команда наподобие GET или POST), используемый для этого запроса |
Request.Headers | NameValueCollection | Полный набор заголовков HTTP, отправленных с этим запросом |
Request.Url | Uri | Элемент RouteTable.Routes, выбранный для этого запроса |
Request.UserHostAddress | string | IP-адрес пользователя, сделавшего этот запрос |
RouteData.Route | RouteBase | Элемент Routetable.Routes, выбранный для этого запроса |
RouteData.Values | RouteValueDictionary | Активные параметры маршрута (либо извлеченные из URL, либо стандартные значения) |
HttpContext.Application | HttpApplicationStateBase | Хранилище состояния приложения |
HttpContext.Cache | Cache | Хранилище кеша приложения |
HttpContext.Items | IDictionary | Хранилище состояния для текущего запроса |
HttpContext.Session | HttpSessionStateBase | Хранилище состояния для сеанса посетителя |
User | IPrincipal | Аутентификационная информация о вошедшем пользователе |
TempData | TempDataDictionary | Временные элементы данных, сохраненные для текущего пользователя |
Отдельные свойства, которые здесь упоминались — Request, HttpContext и т.д. — предоставляют объекты контекста. Здесь они подробно не рассматриваются (поскольку являются частью платформы ASP.NET), но следует знать, что такие объекты предоставляют доступ к полезной информации и средствам, и более подробно вы можете прочитать о них в разделе, посвященном
Метод действия может использовать любой из этих объектов контекста для получения информации о запросе, как демонстрируется в примере ниже:
Давайте попробуем получить данные описанные выше. Для этого нам понадобиться создать MVC проект.
В HomeController вывести данные из объектов контекста.
// Получить доступ к разнообразным свойствам из объектов контекста
ViewBag.userName = User.Identity.Name;
ViewBag.serverName = Server.MachineName;
ViewBag.clientIP = Request.UserHostAddress;
ViewBag.dateStamp = HttpContext.Timestamp;
// Параметры адресной строки
ViewBag.QueryString = Request.QueryString;
ViewBag.myURL = Request.Url.AbsoluteUri;
Вывести их в представлении Index.
<h1>Параметры проекта</h1>
Имя пользователя:
@ViewBag.userName
<br/>
Имя сервера:
@ViewBag.serverName
<br />
IP адрес:
@ViewBag.clientIP
<br />
dateStamp:
@ViewBag.dateStamp
<br />
QueryString:
@ViewBag.QueryString
<br>
URL:
@ViewBag.myURL
<br />
Зарегистрировать пользователя и посмотреть отобразится ли его имя в параметрах контекста.
public ActionResult Index(string city)
Добавим в индекс метод параметр string city
Изменим адресную строку и добавим GET параметр
http://localhost:3509/Home/Index?city=city
Выведем его в Index представлении через ViewBag
<form method='post'> <div class="form-group"> <label for="email">Email address:</label> <input type="email" name='email' class="form-control" id="email"> </div> <div class="form-group"> <label for="pwd">Password:</label> <input type="password" name='password' class="form-control" id="pwd"> </div> <div class="checkbox"> <label><input type="checkbox"> Remember me</label> </div> <button type="submit" class="btn btn-default">Submit</button> </form>
В контроллере добавьте метод для обработки post данных
[HttpPost] public ActionResult Index() { // Получить доступ к разнообразным свойствам из объектов контекста ViewBag.email = Request.Form["email"]; ViewBag.password = Request.Form["password"]; return View(); }
Отобразите в представлении пароль и емайл
email: @ViewBag.email <br> password: @ViewBag.password
Задать значение куки
var userCookie =new HttpCookie(«user», «Алексей»);
userCookie.Expires.AddDays(365);
HttpContext.Response.Cookies.Add(userCookie);
Стереть куки
var user = new HttpCookie("user") { Expires = DateTime.Now.AddDays(-1), Value = null }; Response.Cookies.Add(user);
ViewBag.CookieEmail = Request.Cookies[«email»].Value;
Отобразите значение куки email.
Session[«name»] = «Tom»;
Казалось бы, зачем в данном случае Ajax, если мы можем, например, в форму вводить имя автора и отправлять на сервер, а сервер в качестве ответа возвратит нам страницу с нужным результатом. Но, как выше уже говорилось, AJAX поможет нам избежать перезагрузки всей страницы и выполнить загрузку данных в асинхронном режиме, что несомненно повышает производительность приложения.
Установим AJAX
Install-Package Microsoft.jQuery.Unobtrusive.Ajax
Добавим AJAX форму.
<div class="jumbotron"> <h1>Параметры проекта</h1> @using (Ajax.BeginForm("myAJAX", new AjaxOptions { UpdateTargetId = "results" })) { <input type="text" name="name" /> <input type="submit" value="Поиск" /> } <div id="results"></div> </div> @Scripts.Render("~/scripts/jquery-1.10.2.min.js") @Scripts.Render("~/scripts/jquery.unobtrusive-ajax.min.js")
Добавим код для обработки AJAX в Home контроллер
[HttpPost] public ActionResult myAJAX(string name) { ViewBag.Message = name; return PartialView(""); }
Добавим частичное представление для отображения результатов AJAX
Протестируем форму.
]]>@{ ViewBag.Title = "Index"; } <h3>Выберите файл для загрузки</h3> @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { <input type="file" name="upload" /><br> <input type="submit" value="Загрузить" /> }
public class HomeController : Controller { // GET: Home [HttpGet] public ActionResult Index() { return View(); } [HttpPost] public ActionResult Upload(HttpPostedFileBase upload) { if (upload != null) { // получаем имя файла string fileName = System.IO.Path.GetFileName(upload.FileName); // сохраняем файл в папку Files в проекте upload.SaveAs(Server.MapPath("~/Files/" + fileName)); } return RedirectToAction("Index"); } }
ViewBag.Files = Directory.GetFiles(Server.MapPath("/Files/" ));
Добавим код отображения в представлении под формой загрузки файлов.
<div class="row"> @foreach (var File in ViewBag.Files) { <div class="col-md-4"> <div class="thumbnail"> <div style="background-image:url('@Url.Content("~/Files/" + System.IO.Path.GetFileName(File))'); width:100%;height:200px;background-size:cover;background-position:center;"> </div> </div> </div> } </div>
@{ ViewBag.Title = "Index"; } <head> <link href="~/Content/bootstrap.css" rel="stylesheet" /> <script src="~/Scripts/jquery-1.10.2.js"></script> <script src="~/Scripts/bootstrap.js"></script> <style> .modal-dialog { width: 70%; height: 100%; margin: auto; } .modal-body{ width: 100%; height: 100%; margin: 0; padding: 0; } .modal-content { min-height: 100%; border-radius: 0; } </style> <script> $(document).ready(function () { $(".col-md-4").mouseenter(function () { $("#modal_mimg").attr("src", $(this).attr("data-mimg")); }); }); </script> </head> <body> <div class="container"> <h3>Выберите файл для загрузки</h3> <p> @ViewBag.File </p> <p> @ViewBag.File1 </p> @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { <input type="file" name="upload" /><br> <input type="submit" value="Загрузить" /> } <div class="row"> @foreach (var File in ViewBag.Files) { <div class="col-md-4" data-toggle="modal" data-target="#myModal" style="cursor: pointer;" data-mimg="@Url.Content("~/Files/" + System.IO.Path.GetFileName(File))"> <div class="thumbnail"> <div style="background-image:url('@Url.Content("~/Files/" + System.IO.Path.GetFileName(File))'); width:100%;height:200px;background-size:cover;background-position:center;"> </div> </div> </div> } </div> <!-- Trigger the modal with a button --> <!-- Modal --> <div id="myModal" class="modal fade" role="dialog" > <div class="modal-dialog "> <!-- Modal content--> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h4 class="modal-title">Просмотр изображения в полном размере</h4> </div> <div class="modal-body"> <img id="modal_mimg" src="" style="width:100%;max-height:100%"> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button> </div> </div> </div> </div> </div> </body>
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; namespace WebApplication21.Controllers { public class HomeController : Controller { // GET: Home [HttpGet] public ActionResult Index() { ViewBag.Files = Directory.GetFiles(Server.MapPath("/Files/")); return View(); } [HttpPost] public ActionResult Upload(HttpPostedFileBase upload) { if (upload != null) { // получаем имя файла string fileName = System.IO.Path.GetFileName(upload.FileName); // сохраняем файл в папку Files в проекте if (System.IO.File.Exists((Server.MapPath("/Files/" + fileName)))) { ViewBag.File = "Файл с таким именем уже существует " + fileName; } else { upload.SaveAs(Server.MapPath("/Files/" + fileName)); ViewBag.File = "Файл успешно загружен " + fileName; } } ViewBag.Files = Directory.GetFiles(Server.MapPath("/Files/" )); return View("Index"); // return RedirectToAction("Index?file="+); } } }
Вот что у нас получилось в итоге. Отображение картинок из галереи в полном размере.
Пагинация или постраничный вывод позволяет разбить набор объектов на несколько страниц и установить ссылки на упрощенного доступа к конкретным страницам. В ASP.NET MVC пагинацию сделать очень легко. Можно, конечно, самим попробовать определить логику постраничного вывода. Однако мы можем упростить себе работу, воспользовавшись имеющимися плагинами. Один из таких плагинов представляет пакет PagedList.Mvc.
Итак, добавим этот пакет в проект ASP.NET MVC 5: Для этого откройте меню Сервис->Диспетчер пакетов NuGet
После установки в проект в узел References будут добавлены две новые библиотеки PagedList и PagedList.Mvc. Кроме того, в узел Content будет добавлен файл стилей PagedList.css, который будет использоваться при создании постраничного вывода.
Создадим простую модель для хранения наших изображений.
public class MyImage { public int Id { get; set; } public string File { get; set; } }
Модифицируем homecontroller следующим образом
using PagedList; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; using WebApplication21.Models; namespace WebApplication21.Controllers { public class HomeController : Controller { private string[] files; List<MyImage> images; // GET: Home public void setupfiles() { int cnt = 0; files = Directory.GetFiles(Server.MapPath("/Files/")); images = new List<MyImage>(); foreach (var file in files) { images.Add(new MyImage { Id = cnt++, File = file }); } } [HttpGet] public ActionResult Index(int? page) { setupfiles(); int pageSize = 3; int pageNumber = (page ?? 1); return View(images.ToPagedList(pageNumber, pageSize)); } [HttpPost] public ActionResult Upload(HttpPostedFileBase upload) { if (upload != null) { // получаем имя файла string fileName = System.IO.Path.GetFileName(upload.FileName); // сохраняем файл в папку Files в проекте if (System.IO.File.Exists((Server.MapPath("/Files/" + fileName)))) { ViewBag.File = "Файл с таким именем уже существует " + fileName; } else { upload.SaveAs(Server.MapPath("/Files/" + fileName)); ViewBag.File = "Файл успешно загружен " + fileName; } } return RedirectToAction("Index"); } } }
Обратите внимание на следующие функции
public ActionResult Index(int? page) { setupfiles(); int pageSize = 3; int pageNumber = (page ?? 1); return View(images.ToPagedList(pageNumber, pageSize)); }
page ?? 1
Двойной вопрос означает что в случае если page=NULL то мы присваиваем page значение 1
Модифицируем индекс представление следующим образом
@model PagedList.IPagedList<WebApplication21.Models.MyImage> @using PagedList.Mvc; @{ ViewBag.Title = "Index"; } <head> <link href="~/Content/PagedList.css" rel="stylesheet" /> <link href="~/Content/bootstrap.css" rel="stylesheet" /> <script src="~/Scripts/jquery-1.10.2.js"></script> <script src="~/Scripts/bootstrap.js"></script> <style> .modal-dialog { width: 70%; height: 100%; margin: auto; } .modal-body{ width: 100%; height: 100%; margin: 0; padding: 0; } .modal-content { min-height: 100%; border-radius: 0; } </style> <script> $(document).ready(function () { $(".col-md-4").mouseenter(function () { $("#modal_mimg").attr("src", $(this).attr("data-mimg")); }); }); </script> </head> <body> <div class="container"> <h3>Выберите файл для загрузки</h3> <p> @ViewBag.File </p> <p> @ViewBag.File1 </p> @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { <input type="file" name="upload" /><br> <input type="submit" value="Загрузить" /> } <div class="row"> @foreach (var item in Model) { <div class="col-md-4" data-toggle="modal" data-target="#myModal" style="cursor: pointer;" data-mimg="@Url.Content("~/Files/" + System.IO.Path.GetFileName(item.File))"> <div class="thumbnail"> <div style="background-image:url('@Url.Content("~/Files/" + System.IO.Path.GetFileName(item.File))'); width:100%;height:200px;background-size:cover;background-position:center;"> </div> </div> </div> } </div> <!-- Trigger the modal with a button --> Страница @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) из @Model.PageCount @Html.PagedListPager(Model, page => Url.Action("Index", new { page })) <!-- Modal --> <div id="myModal" class="modal fade" role="dialog" > <div class="modal-dialog "> <!-- Modal content--> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h4 class="modal-title">Просмотр изображения в полном размере</h4> </div> <div class="modal-body"> <img id="modal_mimg" src="" style="width:100%;max-height:100%"> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button> </div> </div> </div> </div> </div> </body>
Не забудьте подключить модель для пагинации
@model PagedList.IPagedList<WebApplication21.Models.MyImage> @using PagedList.Mvc;
Вывод кнопок пагинации осуществляет следующий код
Страница @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) из @Model.PageCount @Html.PagedListPager(Model, page => Url.Action("Index", new { page }))
]]>
public class Profile { public string Name { get; set; } public string patronymic { get; set; } public string Surname { get; set; } public DateTime DOB { get; set; } public string Photo { get; set; } public string Gender { get; set; } public string City { get; set; } }
CREATE TABLE [dbo].[City] ( [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, [City] NVARCHAR(50) NULL )
TRUNCATE TABLE [socialDB].[dbo].[City]; insert into [socialDB].[dbo].[City] ([City]) values ('Актау'), ('Актобе'), ('Алматы'), ('Астана'), ('Атырау'), ('Байконур'), ('Балхаш'), ('Караганда'), ('Кустанай'), ('Павлодар'), ('Семей'), ('Уральск'), ('УстьКаменогорск'), ('Шымкент');
using WebApplication19.Models; namespace WebApplication19.Controllers { public class HomeController : Controller { private socialDBEntities db = new socialDBEntities(); // GET: Home public ActionResult Index() { return View(); } public ViewResult myProfile() { ViewBag.City = db.City.ToList(); return View(); } } }
Обратите внимание на то что мы подключили классы из контроллера
using WebApplication19.Models;
Создали объект по работе с базой данных
private socialDBEntities db = new socialDBEntities();
поместили во viewbag список городов
ViewBag.City = db.City.ToList();
Мы сделали все это используя классы сгенерированные entity framework
public ViewResult myProfile() { Value = new City(); items = db.City.ToList(); Value.City1 = "выберите город"; Value.Id = 0; items.Insert(0, Value); ViewBag.City = items; Value = null; return View(); }
Добавим город «выберите город» по умолчанию.
Итоговый код наших файлов.
Модель профиля.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.ComponentModel.DataAnnotations; namespace WebApplication19.Models { public class Profile { [Required(ErrorMessage = "Имя обязательный параметр.")] [MaxLength(40, ErrorMessage = "Имя не может быть больше 40 символов.")] [MinLength(4, ErrorMessage = "Имя не может быть меньше 4 символов.")] public string Name { get; set; } public string patronymic { get; set; } public string Surname { get; set; } public DateTime DOB { get; set; } public string Photo { get; set; } public string Gender { get; set; } public int City { get; set; } public IEnumerable<WebApplication19.Models.City> Cities { get; set; } } }
Представление профиля
@model WebApplication19.Models.Profile @{ Layout = null; } <!DOCTYPE html> <html> <head> <link href="~/Content/bootstrap.css" rel="stylesheet" /> <meta name="viewport" content="width=device-width" /> <script src="~/Scripts/jquery-1.10.2.min.js"></script> <script src="~/Scripts/bootstrap.js"></script> <script src="~/Scripts/jquery.validate.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.js"></script> <title>Profile</title> </head> <body> <div> <body> <div class="panel-success"> <div class="panel-heading text-center"> <h4>Форма Профиля</h4> </div> <div class="panel-body"> @using (Html.BeginForm()) { @Html.ValidationSummary() <div class="form-group"> <label>Ваше имя:</label> @Html.TextBoxFor(x => x.Name, new { @class = "form-control", placeholder = "Введите ваше имя", required = "required" }) @Html.ValidationMessageFor(x => x.Name) </div> <div class="form-group"> <label>Ваш email:</label> @Html.TextBoxFor(x => x.patronymic, new { @class = "form-control" }) </div> <div class="form-group"> <label>Ваш телефон:</label> @Html.TextBoxFor(x => x.Surname, new { @class = "form-control" }) </div> <div class="form-group"> <label>Ваш телефон:</label> @Html.TextBoxFor(x => x.Gender, new { @class = "form-control" }) </div> <div class="form-group"> <label>Ваш пол</label> @Html.DropDownListFor(x => x.Gender, new[] { new SelectListItem() { Text = "Мужской", Value = Boolean.TrueString}, new SelectListItem() { Text = "Женский", Value = Boolean.FalseString} }, "Выберите пол", new { @class = "form-control" }) </div> <div class="form-group"> <label>Город</label> <div class="editor-field"> @Html.DropDownList("accountid", new SelectList(ViewBag.City, "Id", "City1"), new { @class = "form-control" }) </div> </div> <div class="text-center"> <input type="submit" value="Сохранить" class="btn btn-success" /> </div> } </div> </div> </body> </div> </body> </html>
Контроллер HomeController
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Data.Entity; using WebApplication19.Models; namespace WebApplication19.Controllers { public class HomeController : Controller { private socialDBEntities db = new socialDBEntities(); private List<City> items; public City Value { get; private set; } // GET: Home public ActionResult Index() { return View(); } public void loadCity() { Value = new City(); items = db.City.ToList(); Value.City1 = "выберите город"; Value.Id = 0; items.Insert(0, Value); ViewBag.City = items; Value = null; } [HttpGet] public ViewResult myProfile() { loadCity(); return View(); } [HttpPost] public ViewResult myProfile(Profile profile) { //if (ModelState.IsValid) loadCity(); return View(); } } }
]]>
Файл->Создать->Проект
И в открывшемся окне выберем тип проекта SQL SERVER->Проект базы данных SQL SERVER
В качестве имени проекта выберем ContosoUniversityData
Нажмем Ok.
В обозревателе решений щелкнем правой кнопкой и создадим таблицу как показано на рисунке ниже.
В открывшемся окне введем имя таблицы Student
Нажмем Добавить.
В окне Т-SQL добавим SQL запрос на создание структуры таблицы
CREATE TABLE [dbo].[Student] ( [StudentID] INT IDENTITY (1, 1) NOT NULL, [LastName] NVARCHAR (50) NULL, [FirstName] NVARCHAR (50) NULL, [EnrollmentDate] DATETIME NULL, PRIMARY KEY CLUSTERED ([StudentID] ASC) )
Обратите внимание, что окно проектирование и T-SQL взаимно синхронизировались автоматически.
Аналогично добавим таблицы указанные ниже.
CREATE TABLE [dbo].[Course] ( [CourseID] INT IDENTITY (1, 1) NOT NULL, [Title] NVARCHAR (50) NULL, [Credits] INT NULL, PRIMARY KEY CLUSTERED ([CourseID] ASC) )
CREATE TABLE [dbo].[Enrollment] ( [EnrollmentID] INT IDENTITY (1, 1) NOT NULL, [Grade] DECIMAL(3, 2) NULL, [CourseID] INT NOT NULL, [StudentID] INT NOT NULL, PRIMARY KEY CLUSTERED ([EnrollmentID] ASC) )
Добавим скрипт который выполнится после развертывания базы данных.
Оставим имя по умолчанию и добавим следующие запросы в него
MERGE INTO Course AS Target USING (VALUES (1, 'Economics', 3), (2, 'Literature', 3), (3, 'Chemistry', 4) ) AS Source (CourseID, Title, Credits) ON Target.CourseID = Source.CourseID WHEN NOT MATCHED BY TARGET THEN INSERT (Title, Credits) VALUES (Title, Credits);
Этот скрипт добавит демо данные в таблицы.
Попробуем скомпилировать наш проект.
F5
В результате получаем ошибку
------ Сборка начата: проект: ContosoUniversityData, Конфигурация: Debug Any CPU ------ Не удалось выполнить отладку этого проекта, так как SQL Server не установлен на локальном компьютере. Задайте строку подключения отладки на странице свойств проекта. Ошибка: Не удалось завершить операцию. Перетаскивание уже выполняется ========== Сборка: успешно и без изменений: 0, с ошибками: 1, пропущено: 0 ========== ========== Развертывание: успешно: 0, с ошибками: 0, пропущено: 0 ==========
Для того чтобы исправить эту ошибку необходимо открыть меню Проект->Свойства
В открывшемся окне выбрать вкладку Отладка и нажать кнопку правка для строки целевого назначения
После чего выбрать название подключения с нашей базой данных
После этого поле строка целевого назначения будет заполнено.
Data Source=DESKTOP-K15S51F;Initial Catalog=ContosoUniversityData;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True
Снова попробуем собрать наш проект F5
Теперь база данных создана вместе с таблицами и данными.
Создадим новый проект MVC
В нашем проекте мы используем Entity Framework 6.1
Нам необходимо проверить его версию в NU Get управление решениями.
Откроем это окно и проверим версию Entity Framework
У нас все отлично.
Теперь нам нужно добавить модель для работы с базами данных.
В обозревателе решений правый клик по папке Models добавить новый элемент
В открывшемся окне выбираем ADO.NET EDM
Назовем файл
ContosoModel
Далее запускаем конструктор из базы данных нажимаем далее
Выбираем MS SQL Сервер
Выбираем сервер и базу данных
Проверяем подключение
Нажимаем Ок
Строка подключения создана
Выбираем все таблицы для создания модели
Теперь вы видите модели автоматически сгенерированные из базы данных
Добавление шаблонных элементов в Controller.
Выбираем тип контроллера как на картинке
Заполняем данные как показано ниже
Теперь созданы классы. Если вы получили ошибку то нажмите F5 и повторите процесс
Создайте аналогичные контроллеры для остальных таблиц
Добавим ссылки в наш проект для открытия новых представлений сгенерированных мастером.
<div> @Html.ActionLink("List of students", "Index", "Students")<br /> @Html.ActionLink("List of enrollments", "Index", "Enrollments") </div>
Добавим этот код в Index представление.
Проверим что все работает
Теперь вы можете управлять вашими таблицами из сгенерированных контроллеров и представлений
]]>
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div> @ViewBag.Greeting (из представления) <p>Мы собираемся на захватывающую вечеринку.</p> </div> </body> </html>
Мы двигаемся в верном направлении. Если запустить приложение, отобразятся подробности о вечеринке — точнее, заполнитель для подробностей, но идея должна быть понятна.
В аббревиатуре MVC буква «M» обозначает model (модель), и она является наиболее важной частью приложения. Модель — это представление реальных объектов, процессов и правил, которые определяют сферу приложения, известную как предметная область.
Модель, которую часто называют моделью предметной области, содержит объекты C# (или объекты предметной области), которые образуют «вселенную» приложения, и методы, позволяющие манипулировать ими. Представления и контроллеры открывают предметную область клиентам в согласованной манере, и любое корректно разработанное приложение MVC начинается с хорошо спроектированной модели, которая затем служит центральным узлом при добавлении контроллеров и представлений.
Для приложения Party Invites сложная модель не требуется, поскольку оно совсем простое, и нужно создать только один класс предметной области, который будет назван GuestResponse. Этот объект будет отвечать за хранение, проверку достоверности и подтверждение ответа на приглашение (RSVP).
По соглашению MVC классы, которые образуют модель, помещаются в папку Models, которую Visual Studio создает во время начальной настройки проекта. Щелкните правой кнопкой мыши на папке Models в окне Solution Explorer и выберите в контекстном меню пункт Add, а затем пункт Class (Класс). В качестве имени файла укажите GuestResponse.cs и щелкните на кнопке Add, чтобы создать класс.
Отсутствие пункта Class в контекстном меню может означать, что вы оставили отладчик Visual Studio в выполняющемся состоянии. Среда Visual Studio ограничивает виды изменений, которые можно вносить в проект при функционирующем приложении.
Отредактируйте код класса, чтобы он соответствовал примеру ниже:
namespace PartyInvites.Models { public class GuestResponse { public string Name { get; set; } public string Email { get; set; } public string Phone { get; set; } public bool? WillAttend { get; set; } } }
Вы могли заметить, что свойство WillAttend имеет тип bool, допускающий null, т.е. оно может принимать значение true, false или null. Объяснение этого будет приведено в разделе «Добавление проверки достоверности» далее.
Одна из целей разрабатываемого приложения состоит в подключении формы RSVP, поэтому необходимо добавить ссылку на нее из представления Index.cshtml, как показано в примере ниже:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div> @ViewBag.Greeting (из представления) <p>Мы собираемся на захватывающую вечеринку.</p> @Html.ActionLink("Форма RSVP", "RsvpForm") </div> </body> </html>
Html.ActionLink() — это вспомогательный метод HTML. В MVC Framework доступен набор встроенных вспомогательных методов, которые удобны при визуализации ссылок, полей ввода текста, флажков, списков выбора и другого вида HTML-содержимого. Метод ActionLink принимает два параметра: первым является текст (анкор ссылки), который должен отображаться в ссылке, а вторым — действие, которое должно выполняться, когда пользователь щелкает на ссылке.
Просмотреть то, что создал вспомогательный метод, можно, запустив проект:
Если навести курсор мыши поверх ссылки в браузере, станет видно, что ссылка указывает на http://ваш-сервер/Home/RsvpForm. Метод Html.ActionLink() исследовал конфигурацию маршрутизации URL приложения и определил, что /Home/RsvpForm представляет собой URL действия по имени RsvpForm в контроллере HomeController.
Обратите внимание, что в отличие от традиционных приложений ASP.NET, URL-адреса MVC не соответствуют физическим файлам. У каждого метода действия имеется собственный URL, а инфраструктура MVC использует систему маршрутизации ASP.NET для трансляции этих URL в действия.
Щелчок на ссылке приводит к выдаче ошибки 404 Not Found (не найдено). Она объясняется тем, что пока еще не создан метод действия, соответствующий URL вида /Home/RsvpForm. Это делается добавлением метода RsvpForm в класс HomeController, как показано в примере ниже:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace WebApplication12.Controllers { public class HomeController : Controller { // GET: Home public ActionResult Index() { return View(); } public ViewResult RsvpForm() { return View(); } } }
Мы собираемся добавить представление для метода действия RsvpForm, но несколько другим способом — мы создадим строго типизированное представление. Строго типизированное представление предназначено для визуализации определенного типа предметной области, и если указать тип, с которым нужно работать (GuestResponse в этом случае), то MVC может создать ряд полезных сокращений, облегчающих решение задачи.
Прежде чем продолжать, удостоверьтесь, что проект MVC скомпилирован. Если код класса GuestResponse был написан, но не скомпилирован, инфраструктура MVC не сможет создать строго типизированное представление для этого типа. Чтобы скомпилировать приложение, выберите пункт Build Solution в меню Build среды Visual Studio.
Щелкните правой кнопкой мыши внутри метода RsvpForm в редакторе кода и выберите в контекстном меню пункт Add View (Добавить представление), чтобы открыть диалоговое окно Add View. Удостоверьтесь, что в поле View Name (Имя представления) указано имя RsvpForm,
выберите в списке Template (Шаблон) вариант Empty (Пустой), а в списке Model Class (Класс модели) — вариант GuestResponse. Оставьте все флажки в разделе View Options (Параметры представления) неотмеченными:
Код файла RespForm.cshtml
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>RsvpForm</title> </head> <body> <div> </div> </body> </html>
Опции, которые выбираются и отмечаются при создании представления, определяют начальное содержимое файла представления, и на этом все. Например, чтобы изменить обычное представление на строго типизированное, можно просто добавить или удалить директиву @model в редакторе кода.
Теперь, когда строго типизированное представление создано, можно дополнить содержимое файла RsvpForm.cshtml, чтобы превратить его в HTML-форму для редактирования объектов GuestResponse, как показано в примере ниже:
@model PartyInvites.Models.GuestResponse @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>RsvpForm</title> </head> <body> @using (Html.BeginForm()) { <p>Ваше имя: @Html.TextBoxFor(x => x.Name)</p> <p>Ваш email: @Html.TextBoxFor(x => x.Email)</p> <p>Ваш телефон: @Html.TextBoxFor(x => x.Phone)</p> <p>Вы придете? @Html.DropDownListFor(x => x.WillAttend, new[] { new SelectListItem() { Text = "Да, конечно я буду", Value = Boolean.TrueString}, new SelectListItem() { Text = "Нет, я не смогу", Value = Boolean.FalseString} }) </p> <input type="submit" value="Отправить форму RSVP" /> } </body> </html>
Для каждого свойства класса модели GuestResponse мы используем вспомогательный метод HTML, чтобы визуализировать подходящий элемент управления HTML типа input. Эти методы позволяют с помощью лямбда-выражения выбрать свойство, с которым связан элемент input, как показано в следующей строке:
@Html.TextBoxFor(x => x.Email)
Вспомогательный метод HTML по имени TextBoxFor генерирует HTML-разметку для элемента input, устанавливает параметр type в text, а атрибуты id и name — в Email (имя выбранного свойства класса предметной области):
<input id="Email" name="Email" type="text" value="" />
Это удобное средство работает, потому что представление RsvpForm является строго типизированным, а инфраструктуре MVC было указано, что GuestResponse — тип, который нужно визуализировать с помощью этого представления. Это снабжает вспомогательные методы HTML информацией, которая им необходима для выяснения того, из какого типа данных должны быть прочитаны свойства через выражение @model.
Альтернативой применению лямбда-выражений является ссылка на имя свойства типа модели как на строку:
@Html.TextBox("Email")
Подход с использованием лямбда-выражения предотвращает неправильный ввод имени свойства типа модели, т.к. среда Visual Studio активизирует средство IntelliSense, позволяя выбрать свойство автоматически:
Еще одним удобным вспомогательным методом является Html.BeginForm(), который генерирует HTML-элемент form, сконфигурированный на выполнение обратной отправки методу действия. Поскольку никакие аргументы вспомогательному методу не передаются, он предполагает, что требуется выполнить обратную отправку по тому же самому URL, из которого запрашивался HTML-документ. Изящный трюк заключается в том, чтобы поместить этот метод внутрь C#-оператора using, как показано ниже:
@using (Html.BeginForm()) { // сюда помещается содержимое формы... }
Обычно при таком применении оператор using гарантирует освобождение объекта, когда он покидает область действия. Такое использование распространено, например, для подключений к базам данных, чтобы гарантировать их закрытие немедленно по завершении запроса. (Это применение ключевого слова using отличается от той его разновидности, которая включает классы из пространства имен в область действия какого-то класса.)
Вместо освобождения объекта вспомогательный метод Html.BeginForm закрывает HTML-элемент form, когда тот покидает область действия. Это означает, что вспомогательный метод Html.BeginForm создает обе части элемента формы:
<form action="/Home/RsvpForm" method="post"> // ... содержимое формы </form>
Не беспокойтесь, если не знакомы с удалением объектов C#. В данном случае задача заключается в том, чтобы продемонстрировать создание формы с помощью вспомогательного метода HTML.
Стремясь быть полезной, среда Visual Studio будет выполнять запрос в браузере URL-адреса, основываясь на представлении, которое редактируется в текущий момент. Это ненадежная возможность, поскольку она не работает при редактировании файлов других видов, к тому же в сложных веб-приложениях нельзя просто переходить в произвольные точки.
Чтобы установить фиксированный URL-адрес для запроса в браузере, выберите в меню Project (Проект) среды Visual Studio пункт PartyInvites Properties (Свойства PartyInvites), перейдите в раздел Web и отметьте переключатель Specific Page (Определенная страница) в категории Start Action (Начальное действие), как показано на рисунке ниже:
Вводить значение в поле рядом с переключателем вовсе не обязательно — Visual Studio будет запрашивать стандартный URL-адрес для проекта, который указывает на метод действия Index контроллера Home.
Форму в представлении RsvpForm можно увидеть, запустив приложение и щелкнув на ссылке «Форма RSVP». Результат показан на рисунке ниже:
Инфраструктуре MVC пока еще не указано, что должно быть сделано, когда форма отправляется серверу. В нынешнем состоянии приложения щелчок на кнопке «Отправить форму RSVP» лишь очищает любые значения, введенные в форму. Причина в том, что форма осуществляет обратную отправку методу действия RsvpForm из контроллера Home, который только сообщает MVC о необходимости повторной визуализации представления.
Факт утери введенных данных при повторной визуализации представления может вас удивить. Если это так, то вам, скорее всего, приходилось разрабатывать приложения с помощью инфраструктуры ASP.NET Web Forms, которая в такой ситуации автоматически сохраняет данные. Вскоре будет показано, как добиться аналогичного эффекта в MVC.
Чтобы получить и обработать данные отправленной формы, мы собираемся воспользоваться одной интересной возможностью. Мы добавим второй метод действия RsvpForm, чтобы обеспечить перечисленные ниже аспекты.
Обработка запросов GET и POST в отдельных методах C# способствует обеспечению аккуратности кода контроллера, т.к. ответственность у этих двух методов разная. Оба метода действий вызываются через один и тот же URL, но MVC вызывает соответствующий метод в зависимости от вида запроса — GET или POST. В примере ниже показаны изменения, которые необходимо внести в класс HomeController.
К существующему методу действия RsvpForm был добавлен атрибут HttpGet. Это указывает MVC, что данный метод должен использоваться только для запросов GET.
Затем была добавлена перегруженная версия метода RsvpForm, принимающая параметр GuestResponse, к которой применен атрибут HttpPost. Этот атрибут указывает MVC, что новый метод будет иметь дело только с запросами POST. Обратите внимание, что также было импортировано пространство имен PartyInvites.Models. Это сделано для того, чтобы на тип модели GuestResponse можно было ссылаться без необходимости в указании полностью определенного имени класса. Работа всех этих добавлений к коду объясняется в последующих разделах.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using WebApplication12.Models; namespace WebApplication12.Controllers { public class HomeController : Controller { // GET: Home public ActionResult Index() { return View(); } [HttpGet] public ViewResult RsvpForm() { return View(); } [HttpPost] public ViewResult RsvpForm(GuestResponse guest) { // Нужно отправить данные нового гостя no электронной почте // организатору вечеринки. return View("Thanks", guest); } } }
Первая перегруженная версия метода действия RsvpForm визуализирует то же самое представление, что и ранее (файл RsvpForm.cshtml), для генерации формы, показанной на рисунке выше.
Вторая перегруженная версия более интересна из-за наличия параметра. Но с учетом того, что этот метод действия будет вызываться в ответ на HTTP-запрос POST, а тип GuestResponse является классом C#, каким образом они соединяются между собой?
Секрет кроется в привязке модели — чрезвычайно полезной функциональной возможности MVC, согласно которой входящие данные анализируются, а пары «ключ/значение» в HTTP-запросе используются для заполнения свойств в типах модели предметной области. Этот процесс противоположен применению вспомогательных методов HTML; т.е. при создании данных формы для отправки клиенту мы генерируем HTML-элементы input, в которых значения атрибутов id и name производятся из имен свойств класса модели.
В противоположность этому, благодаря привязке модели, имена элементов input используются для установки значений свойств в экземпляре класса модели, который затем передается методу действия, работающему с запросами POST.
Привязка модели — мощное и настраиваемое средство, которое избавляет от кропотливого и тяжелого труда по взаимодействию с HTTP-запросами напрямую и позволяет работать с объектами C#, а не иметь дело со значениями Request.Form[] и Request.QueryString[]. Объект GuestResponse, который передается в качестве параметра этому методу действия, автоматически заполняется данными из полей формы.
Вторая перегруженная версия метода действия RsvpForm также демонстрирует, как можно указать MVC, что в ответ на запрос должно визуализироваться специфическое представление, отличное от стандартного. Ниже приведен соответствующий оператор:
return View("Thanks", guestResponse);
Этот вызов метода View сообщает MVC, что нужно найти и визуализировать представление Thanks и передать ему объект GuestResponse. Чтобы создать указанное представление, щелкните правой кнопкой мыши на любом из методов класса HomeController и выберите в контекстном меню пункт Add View (Добавить представление). С помощью открывшегося диалогового окна Add View создайте строго типизированное представление по имени Thanks, в котором применяется класс модели GuestResponse и которое основано на шаблоне Empty. Среда Visual Studio создаст представление в виде файла Views/Home/Thanks.cshtml.
Отредактируйте код представления так, чтобы он соответствовал коду, приведенному в примере ниже:
@model WebApplication12.Models.GuestResponse @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Thanks</title> </head> <body> <div> <h1>Спасибо, @Model.Name!</h1> @if (Model.WillAttend == true) { @:Здорово что вы придете, напитки уже в холодильнике ;) } else { @:Жаль что вы не придете, но спасибо что дали об этом знать. } </div> </body> </html>
Представление Thanks использует механизм визуализации Razor, чтобы отображать содержимое в зависимости от значения свойства GuestResponse, переданного вызову View в методе действия RsvpForm. Выражение @model синтаксиса Razor указывает тип модели предметной области, для которого представление строго типизировано.
Для получения доступа к значению свойства в объекте предметной области применяется конструкция Model.ИмяСвойства. Например, для получения значения свойства Name используется Model.Name.
Теперь, когда создано представление Thanks, появился работающий базовый пример обработки формы с помощью MVC. Запустите приложение в Visual Studio, щелкните на ссылке «Форма RSVP», введите какие-нибудь данные внутри формы и щелкните на кнопке «Отправить форму RSVP». Отобразится результат, показанный на рисунке ниже (он может отличаться, если введено другое имя и было указано о невозможности посетить вечеринку).
Теперь пора добавить в приложение проверку достоверности вводимых данных. В отсутствие проверки достоверности пользователи смогут вводить бессмысленные данные или даже отправлять пустую форму.
В приложении MVC проверка достоверности обычно применяется в модели предметной области, а не в пользовательском интерфейсе. Это означает возможность определения в одном месте нужных критериев проверки достоверности, которые вступают в действие везде, где используется класс модели.
Инфраструктура ASP.NET MVC поддерживает декларативные правила проверки достоверности, определенные с помощью атрибутов из пространства имен System.ComponentModel.DataAnnotations, а это значит, что ограничения проверки достоверности выражаются с помощью стандартных атрибутов C#. В примере ниже показано, как применить эти атрибуты к классу модели GuestResponse:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.ComponentModel.DataAnnotations; namespace WebApplication12.Models { public class GuestResponse { [Required(ErrorMessage = "Пожалуйста, введите свое имя")] public string Name { get; set; } [Required(ErrorMessage = "Пожалуйста, введите email")] [RegularExpression(".+\\@.+\\..+", ErrorMessage = "Вы ввели некорректный email")] public string Email { get; set; } [Required(ErrorMessage = "Пожалуйста, введите телефон")] public string Phone { get; set; } [Required(ErrorMessage = "Пожалуйста, укажите, примите ли участие в вечеринке")] public bool? WillAttend { get; set; } } }
Инфраструктура MVC обнаруживает атрибуты проверки достоверности и использует их для проверки данных во время процесса приписки модели. Обратите внимание, что мы импортировали пространство имен, которое содержит средства проверки достоверности, так что к ним можно обращаться, не указывая полные имена.
Как уже отмечалось ранее, для свойства WillAttend был выбран булевский тип, допускающий значение null. Это было сделано для того, чтобы можно было применить атрибут проверки Required. В случае использования обычного булевского типа значением, получаемым посредством привязки модели, могло бы быть только true или false, и не было бы возможности определить, выбрал ли пользователь значение. Булевский тип, допускающий null, имеет три разрешенных значения: true, false и null. Значение null будет применяться, если пользователь не выбрал значение, и это вынудит атрибут Required сообщить об ошибке проверки достоверности. Это хороший пример того, насколько элегантно инфраструктура MVC Framework сочетает средства C# с HTML и HTTP.
Проверку на наличие проблемы с достоверностью данных можно выполнить с использованием свойства ModelState.IsValid в классе контроллера. В примере ниже показано, как это реализовано в методе действия RsvpForm, поддерживающем запросы POST, внутри класса контроллера Home:
public ViewResult RsvpForm(GuestResponse guest) { if (ModelState.IsValid) // Нужно отправить данные нового гостя по электронной почте // организатору вечеринки. return View("Thanks", guest); else // Обнаружена ошибка проверки достоверности return View(); }
Если ошибки проверки достоверности отсутствуют, мы указываем MVC, что нужно визуализировать представление Thanks, как это делалось ранее. В случае обнаружения ошибок проверки достоверности мы повторно визуализируем представление RsvpForm вызывая метод View() без параметров.
Простое отображение формы в ситуации, когда имеется ошибка, не особенно полезно — мы должны также предоставить пользователю информацию, в чем заключается проблема, и почему принять отправку формы невозможно. Это делается с применением вспомогательного метода Html.ValidationSummary() в представлении RsvpForm, как показано в примере ниже:
@model WebApplication12.Models.GuestResponse @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>RspForm</title> </head> <body> <div> @using (Html.BeginForm()) { @Html.ValidationSummary() <p>Ваше имя: @Html.TextBoxFor(x => x.Name)</p> <p>Ваш email: @Html.TextBoxFor(x => x.Email)</p> <p>Ваш телефон: @Html.TextBoxFor(x => x.Phone)</p> <p>Вы придете? @Html.DropDownListFor(x => x.WillAttend, new[] { new SelectListItem() { Text = "Да, конечно я буду", Value = Boolean.TrueString}, new SelectListItem() { Text = "Нет, я не смогу", Value = Boolean.FalseString} }) </p> <input type="submit" value="Отправить форму RSVP" /> } </div> </body> </html>
В отсутствие ошибок метод Html.ValidationSummary() создает скрытый элемент списка в виде заполнителя внутри формы. Инфраструктура MVC делает заполнитель видимым и добавляет сообщения об ошибках, определенные атрибутами проверки достоверности. Результирующее окно показано на рисунке:
Пользователь не увидит представление Thanks до тех пор, пока не будут удовлетворены все ограничения проверки достоверности, примененные к классу GuestResponse. Обратите внимание, что введенные в форму данные были сохранены и отображены снова при визуализации представления со сводкой проверки достоверности. Это еще одно преимущество, обеспечиваемое средством привязки модели, и оно упрощает работу с данными формы.
Если вам приходилось иметь дело с ASP.NET Web Forms, то вы знаете, что в Web Forms имеется концепция серверных элементов управления, которые сохраняют состояние, сериализуя значения в скрытое поле формы по имени _VIEWSTATE. Привязка модели ASP.NET MVC не имеет никакого отношения к концепциям серверных элементов управления, обратным отправкам или средству View State, характерным для Web Forms. Инфраструктура ASP.NET MVC не внедряет скрытое поле _VIEWSTATE в визуализированные HTML-страницы.
Вспомогательные методы HTML, которые создают текстовые поля, раскрывающиеся списки и другие элементы, обладают удобным средством, которое можно использовать в сочетании с привязкой модели. Тот же самый механизм, который сохраняет данные, введенные в форму пользователем, можно применять также для подсветки отдельных полей, которые не прошли проверку достоверности.
Если свойство класса модели не пройдет проверку достоверности, вспомогательные методы HTML будут генерировать несколько иную HTML-разметку. В качестве примера ниже приведена HTML-разметка, генерируемая в результате вызова Html.TextBoxFor(х => x.Name) при отсутствии ошибок проверки достоверности:
<input data-val="true" data-val-required="Пожалуйста, введите свое имя" id="Name" name="Name" type="text" value="" />
А вот HTML-разметка, генерируемая этим же вызовом, когда пользователь не вводит значение (что является ошибкой проверки достоверности, поскольку мы применили атрибут Required к свойству Name в классе модели GuestResponse):
<input class="input-validation-error" data-val="true" data-val-required="Пожалуйста, введите свое имя" id="Name" name="Name" type="text" value="" />
Этот вспомогательный метод добавил к элементу input класс по имени input-validation-error. Мы можем воспользоваться этой возможностью, создав таблицу стилей, которая содержит стили CSS для этого класса и другие стили, применяемые различными вспомогательными методами HTML.
Соглашение, принятое в проектах MVC, предусматривает помещение статического содержимого, такого как таблицы стилей CSS, в папку по имени Content. Создайте эту папку, щелкнув правой кнопкой мыши на элементе PartyInvites в окне Solution Explorer, выбрав в контекстном меню пункт Add —> New Folder (Добавить —> Новая папка) и указав Content в качестве имени папки.
Чтобы создать файл CSS, щелкните правой кнопкой мыши на только что созданной папке Content, выберите в контекстном меню пункт Add —> New Item (Добавить —> Новый элемент) и выберите Style Sheet (Таблица стилей) из набора шаблонов элементов. Установите имя нового файла Styles.css.
Щелкните на кнопке Add и Visual Studio создаст файл Content/Styles.css. Приведите содержимое этого файла в соответствие со следующим кодом:
.field-validation-error { color: #f00; } .field-validation-valid { display: none; } .input-validation-error { border: 1px solid #f00; background-color: #fee; } .validation-summary-errors { font-weight: bold; color: #f00; } .validation-summary-valid { display: none; }
Для использования этой таблицы стилей добавляется новая ссылка в раздел head представления RsvpForm, как показано в примере ниже. Элементы link добавляются к представлениям точно так же, как к обычным статическим файлам HTML, хотя позже будет продемонстрировано средство пакетов, которое позволяет объединять сценарии JavaScript и таблицы стилей CSS и доставлять их в браузеры с помощью единственного HTTP-запроса.
@model WebApplication12.Models.GuestResponse @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>RspForm</title> <link rel="stylesheet" type="text/css" href="~/Content/Styles.css" /> </head>
Файлы JavaScript и CSS можно перетаскивать из окна Solution Explorer в редактор кода. Среда Visual Studio создаст элементы script и link для выбранных файлов.
Если вы перешли на MVC 5 непосредственно с MVC 3, то могли ожидать, что файл CSS добавляется к представлению за счет указания атрибута href в виде @Href(«~/Content/Site.css») или @Url.Content(«~/Content/Site.css»). Начиная с MVC 4, механизм Razor обнаруживает атрибуты, начинающиеся с ~/ и автоматически вставляет вызов @Href или @Url.
После применения таблицы стилей при отправке данных, которые вызывают ошибку проверки достоверности, отображается визуально очевидное указание на причины проблем:
Базовая функциональность приложения на месте (кроме отправки электронной почты, к которой мы вскоре приступим), однако его внешний вид в целом довольно-таки непривлекателен. Несмотря на то что это руководство по MVC сосредоточено на разработке серверной стороны, полезно рассмотреть несколько библиотек с открытым кодом, которые приняты Microsoft и включены в ряд шаблонов проектов Visual Studio.
Я не являюсь большим поклонником упомянутых шаблонов, но мне нравятся некоторые из используемых ими библиотек, и одним таким примером из числа задействованных в MVC 5 является Bootstrap, которая представляет собой удобную библиотеку CSS, первоначально разработанную в Twitter и получившую широкое применение.
Разумеется, вы не обязаны применять шаблоны проектов Visual Studio, чтобы пользоваться библиотеками вроде Bootstrap. Можно загрузить файлы напрямую из веб-сайтов с нужными библиотеками или воспользоваться инструментом NuGet, интегрированным в Visual Studio и предоставляющим доступ к каталогу заранее упакованного программного обеспечения, которое может быть загружено и установлено автоматически.
Одной из лучших характеристик NuGet является то, что данный инструмент управляет зависимостями между пакетами, так что во время установки, к примеру, библиотеки Bootstrap инструмент NuGet также загрузит и установит библиотеку jQuery, от которой зависит Bootstrap.
Чтобы установить пакет Bootstrap, выберите пункт Library Package Manager —> Package Manager Console в меню Tools среды Visual Studio. Откроется окно командной строки NuGet. Введите следующую команду и нажмите клавишу <Enter>:
Команда Install-Package сообщает NuGet о необходимости загрузки пакета вместе с его зависимостями и затем добавления всего этого в проект. Нужный пакет называется bootstrap. Имена пакетов можно либо искать на веб-сайте NuGet (http://www.nuget.org), либо прибегнуть к услугам пользовательского интерфейса NuGet в Visual Studio (выберите пункт меню Tools —> Library Package Manager —> Manage NuGet Packages for Solution.
Ключ командной строки -version использовался для указания на то, что требуется версия 3 библиотеки Bootstrap, которая является последней доступной стабильной версией. Без ключа -version инструмент NuGet загрузил бы последнюю версию пакета, но для гарантии того, что вы в точности воссоздадите примеры, приведенные ниже, необходимо установить эту конкретную версию.
Инструмент NuGet загрузит все файлы, требующиеся для библиотеки Bootstrap, а также для библиотеки jQuery, на которую опирается Bootstrap. Файлы CSS помещаются в папку Content. Кроме того, создается папка Scripts (которая в MVC является стандартным местоположением для файлов JavaScript) и заполняется файлами Bootstrap и jQuery. (Также создается папка fonts — это индивидуальная особенность библиотеки Bootstrap, которая ожидает наличия файлов в определенных местах.)
Причина рассмотрения Bootstrap в этой статье — иллюстрация того, насколько легко HTML-разметка, генерируемая MVC Framework, может применяться с популярными библиотеками CSS и JavaScript. Тем не менее, основное внимание в настоящем руководстве уделяется разработке серверной стороны.
Базовые средства Bootstrap работают путем применения классов к элементам, которые соответствуют селекторам CSS, определенным внутри добавленных в папку Content файлов. Подробную информацию о классах, определенных в библиотеке Bootstrap, можно получить на веб-сайте Bootstrap, а в примере ниже демонстрируется использование ряда базовых стилей в представлении Index.cshtml:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <link href="~/Content/bootstrap.css" rel="stylesheet" /> <link href="~/Content/bootstrap-theme.css" rel="stylesheet" /> <style> .btn a { color: white; text-decoration: none; } body { background-color: #F1F1F1; } </style> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div class="text-center"> <h2>Мы собираемся на захватывающую вечеринку.</h2> <h3>И вы приглашены, нужно только заполнить форму</h3> <br /> <div class="btn btn-success"> @Html.ActionLink("Форма RSVP", "RsvpForm") </div> </div> </body> </html>
В разметку были добавлены элементы link для файлов bootstrap.css и bootstrap-theme.css из папки Content. Они являются файлами Bootstrap, требуемыми для базовой стилизации CSS, обеспечиваемой этой библиотекой. Вдобавок в папке Scripts имеется соответствующий файл JavaScript, но в данной статье он не нужен. Кроме того, определен также элемент style, который устанавливает цвет фона для элемента body и стили текста для элементов <a>.
Вы заметите, что для каждого файла Bootstrap в папке Content имеется двойник с суффиксом min — например, есть файлы bootstrap.css и bootstrap.min.css. Это распространенная практика минимизации файлов JavaScript и CSS при развертывании приложений в производственной среде, которая представляет собой процесс удаления всех пробельных символов, а также в случае файлов JavaScript замену имен функций и переменных более короткими метками. Целью минимизации является сокращение объема передаваемых данных, необходимых для доставки содержимого в браузер.
После импортирования стилей Bootstrap и определения пары собственных стилей осталось стилизовать элементы. Рассматриваемый пример прост, поэтому необходимо использовать только три класса CSS из Bootstrap: text-center, btn и btn-success.
Класс text-center центрирует содержимое элемента и его дочерних элементов. Класс btn стилизует элемент button, input или <a> в виде симпатичной кнопки, а класс btn-success указывает диапазон цветов для этой кнопки. Цвет кнопки зависит от применяемой темы — в примере используется стандартная тема (как определено в файле bootstrap-theme.css), но в Интернете доступно буквально бесконечное количество других тем.
Полученные в итоге результаты показаны на рисунке ниже:
В библиотеке Bootstrap определены классы, которые могут использоваться для стилизации форм. Я не планирую вдаваться в особые детали, но в примере ниже показано, как были применены эти классы:
@model WebApplication12.Models.GuestResponse @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>RspForm</title> <link rel="stylesheet" type="text/css" href="~/Content/Styles.css" /> <link href="~/Content/bootstrap.css" rel="stylesheet" /> <link href="~/Content/bootstrap-theme.css" rel="stylesheet" /> </head> <body> <div class="panel-success"> <div class="panel-heading text-center"> <h4>Форма RSVP</h4> </div> <div class="panel-body"> @using (Html.BeginForm()) { @Html.ValidationSummary() <div class="form-group"> <label>Ваше имя:</label> @Html.TextBoxFor(x => x.Name, new { @class = "form-control" }) </div> <div class="form-group"> <label>Ваш email:</label> @Html.TextBoxFor(x => x.Email, new { @class = "form-control" }) </div> <div class="form-group"> <label>Ваш телефон:</label> @Html.TextBoxFor(x => x.Phone, new { @class = "form-control" }) </div> <div class="form-group"> <label>Вы придете?</label> @Html.DropDownListFor(x => x.WillAttend, new[] { new SelectListItem() { Text = "Да, конечно я буду", Value = Boolean.TrueString}, new SelectListItem() { Text = "Нет, я не смогу", Value = Boolean.FalseString} }, "Выберите вариант", new { @class = "form-control" }) </div> <div class="text-center"> <input type="submit" value="Отправить форму RSVP" class="btn btn-success" /> </div> } </div> </div> </body> </html>
Классы Bootstrap в этом примере создают панель с заголовком, просто чтобы придать компоновке структурированность. Для стилизации формы используется класс form-group, который стилизует элемент, содержащий label и связанный элемент input или select.
Эти элементы созданы посредством вспомогательных методов HTML, что означает отсутствие статически определенных элементов, к которым можно было бы применить требуемый класс form-control. К счастью, вспомогательные методы принимают в качестве необязательного аргумента объект, который позволяет указывать атрибуты создаваемого элемента, например:
@Html.TextBoxFor(x => x.Email, new { @class = "form-control" })
Объект для атрибутов создается с использованием анонимных типов C# и указывает, что в элементе, генерируемом вспомогательным методом TextBoxFor, атрибут class должен быть установлен в form-control. Свойства, определяемые этим объектом, применяются для имени атрибута, добавляемого к HTML-элементу, а поскольку class является зарезервированным словом в языке C#, оно предваряется символом @. Это стандартная возможность C#, которая позволяет использовать ключевые слова в выражениях.
Результаты стилизации можно видеть на рисунке ниже:
Последним представлением, подлежащим стилизации, является Thanks.cshtml, в примере ниже показано, как это делается. Вы заметите, что добавленная разметка похожа на таковую из представления Index.cshtml. Чтобы упростить управление приложением, имеет смысл избегать дублирования кода и разметки везде, где это возможно. Позже будут рассмотрены компоновки Razor и описаны частичные представления, которые способствуют сокращению дублирования разметки.
@model PartyInvites.Models.GuestResponse @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Thanks</title> <link href="~/Content/bootstrap.css" rel="stylesheet" /> <link href="~/Content/bootstrap-theme.css" rel="stylesheet" /> <style> body { background: #f1f1f1; } </style> </head> <body> <div class="text-center"> <h1>Спасибо, @Model.Name!</h1> <div class="lead"> @if (Model.WillAttend == true) { @:Здорово что вы придете, напитки уже в холодильнике ;) } else { @:Жаль что вы не придете, но спасибо что дали об этом знать. } </div> </div> </body> </html>
]]>
Это содержимое защищено паролем. Для его просмотра введите, пожалуйста, пароль:
]]>
Когда вы впервые создаете новый проект MVC Framework, у вас есть на выбор две базовых отправных точки: шаблон Empty (Пустой) и шаблон MVC. Эти имена несколько обманчивы, так как добавить базовые папки и сборки, требуемые для MVC Framework, можно в любой проект, отметив флажок MVC в разделе Add folders and core references for (Добавить папки и основные ссылки для) диалогового окна New ASP.NET Project (Новый проект ASP.NET), как показано на рисунке ниже. В случае выбора шаблона MVC этот флажок отмечается автоматически.
Реальное отличие связано с дополнительным содержимым, которое шаблон MVC добавляет в новые проекты. Оно предоставляет готовую отправную точку, включающую стандартные контроллеры и представления, конфигурацию безопасности, ряд популярных пакетов JavaScript и CSS (таких как jQuery и Bootstrap), а также компоновку — которая применяет библиотеку Bootstrap для построения темы, оформляющей пользовательский интерфейс приложения.
Вариант Empty проекта содержит только базовые ссылки, требуемые для MVC Framework, и базовую структуру папок. Шаблон MVC добавляет довольно много содержимого, и разницу можно видеть на рисунке ниже, где показано содержимое двух созданных проектов. Проект в левой части создан с применена шаблона Empty при отмеченном флажке MVC. Проект в правой части создан с использованием шаблона MVC, и чтобы продемонстрировать все файлы в нем, пришлось открывать разные папки в окне Solution Explorer, т.к. список файлов оказался бы слишком длинным.
Дополнительные файлы, добавляемые в проект шаблоном MVC, выглядят хуже, чем есть на самом деле. Некоторые из них относятся к аутентификации, а другие представляют собой файлы JavaScript и CSS, для которых предусмотрены обычные и минимальные версии.
Среда Visual Studio собирает проект, созданный с помощью шаблона MVC, используя пакеты NuGet, а это значит, что вы можете просмотреть, какие пакеты применяются, выбрав пункт Manage NuGet Packages for Solution (Управление пакетами NuGet для решения) в меню Tools => Library Package Manager (Сервис => Диспетчер библиотечных пакетов). Это также означает возможность добавления тех же самых пакетов в любой проект, в том числе и созданный с использованием шаблона Empty.
Какой бы шаблон вы ни выбрали, вы заметите, что результирующие проекты имеют очень похожие структуры папок. Некоторые из элементов в проекте MVC играют особые роли, жестко закодированные в ASP.NET или MVC Framework. Другие имеют отношение к соглашениям об именовании. Все эти основные файлы и папки описаны в таблице ниже, причем некоторые из них по умолчанию в проектах не присутствуют.
/App_Data
В эту папку помещаются закрытые данные, такие как XML-файлы или базы данных, если используется SQL Server Express, SQLite или другие хранилища на основе файлов
/App_Start
Эта папка содержит ряд основных настроек конфигурации для проекта, в том числе определение маршрутов и фильтров, а также пакетов содержимого
Маршруты и фильтры рассматриваются позже
/Areas
Области — это способ разделения крупного приложения на меньшие части
/bin
Сюда помещается скомпилированная сборка приложения MVC вместе со всеми ссылаемыми сборками, находящимися не в GAC
Чтобы увидеть папку bin в окне Solution Explorer, понадобится щелкнуть на кнопке Show All Files (Показать все файлы). Поскольку все файлы в этой папке являются двоичными и генерируются в результате компиляции, обычно они не хранятся в системе управления исходным кодом
/Content
Сюда помещается статическое содержимое, такое как CSS-файлы и изображения
Это является необязательным соглашением. Статическое содержимое можно хранить в любом подходящем месте
/Controllers
Сюда помещаются классы контроллеров
Это является соглашением. Классы контроллеров могут размещаться где угодно, поскольку они компилируются в ту же самую сборку
/Models
Сюда помещаются классы моделей представлений и моделей предметной области, хотя все кроме простейших приложений выигрывают от определения модели предметной области в отдельном проекте
Это является соглашением. Классы моделей могут быть определены где угодно в текущем проекте или вообще вынесены в отдельный проект
/Scripts
Эта папка предназначена для хранения библиотек JavaScript, используемых в приложении. По умолчанию Visual Studio добавляет библиотеки jQuery и несколько других популярных JavaScript-библиотек
Это является соглашением. Файлы сценариев могут находиться в любом месте, т.к. в действительности они представляют собой просто другой тип статического содержимого
/Views
В этой папке хранятся представления и частичные представления, обычно сгруппированные вместе в папках с именами контроллеров, с которыми они связаны
/Views/Shared
В этой папке хранятся компоновки и представления, не являющиеся специфичными для какого-либо контроллера
/Views/Web.config
Это конфигурационный файл. В нем содержится конфигурационная информация, которая обеспечивает обработку представлений с помощью ASP.NET и предотвращает их обслуживание веб-сервером IIS, а также пространства имен, по умолчанию импортируемые в представления
Файл /Views/Web.config предотвращает обслуживание веб-сервером IIS содержимого этих папок. Представления должны визуализироваться через методы действий
/Global.asax
Это глобальный класс приложения ASP.NET. В его файле отделенного кода (Global.asax.cs) регистрируется конфигурация маршрутов, а также предоставляется любой код, который должен выполняться при запуске или завершении приложения либо в случае возникновения необработанного исключения
В приложении MVC файл Global.asax играет ту же самую роль, что и в приложении Web Forms
/Web.config
Конфигурационный файл для приложения
В приложении MVC файл Web.config играет ту же самую роль, что и в приложении Web Forms
В проекте MVC применяются два вида соглашений. Соглашения первого вида — это просто предположения о том, как может выглядеть структура проекта.
Например, общепринято размещать файлы JavaScript в папке Scripts. Здесь их рассчитывают обнаружить другие разработчики, использующие MVC, и сюда будут устанавливаться пакеты NuGet. Однако вы вольны переименовать папку Scripts или вообще удалить ее — разместив файлы сценариев где-то в другом месте. Это не помешает инфраструктуре MVC Framework запустить ваше приложение при условии, что элементы <script> внутри представлений ссылаются на местоположение, в котором находятся файлы сценариев.
Соглашения второго вида произрастают из принципа соглашения по конфигурации (convention over configuration) или соглашения над конфигурацией, если делать акцент на преимуществе соглашения перед конфигурацией, который был одним из главных аспектов, обеспечивших популярность платформе Ruby on Rails. Соглашение по конфигурации означает, что вы не должны явно конфигурировать, к примеру, ассоциации между контроллерами и их представлениями. Нужно просто следовать определенному соглашению об именовании для файлов — и все будет работать. При соглашении такого рода снижается гибкость в изменении структуры проекта. В последующих разделах объясняются соглашения, которые используются вместо конфигурации.
Классы контроллеров должны иметь имена, заканчивающиеся на Controller, например, ProductController, ShopController. При ссылке на контроллер где-либо в проекте, скажем, при вызове вспомогательного метода HTML, указывается первая часть имени (такая как Product), а инфраструктура MVC Framework автоматически добавляет к этому имени слово Controller и начинает поиск класса контроллера.
Это поведение можно изменить, создав собственную реализацию интерфейса IControllerFactory.
Представления и частичные представления располагаются в папке:
/Views/ИмяКонтроллера
Например, представление, ассоциированное с классом ProductController, находится в папке /Views/Product. Обратите внимание, что часть Controller имени класса в имени папки внутри Views не указывается, т.е. используется папка /Views/Product, а не /Views/ProductController. Поначалу такой подход может показаться нелогичным, но это очень скоро войдет в привычку.
Инфраструктура MVC Framework ожидает, что стандартное представление для метода действия должно иметь имя этого метода. Например, представление, ассоциированное с методом действия List(), должно называться List.cshtml. Таким образом, ожидается, что для метода действия List() в классе ProductController стандартным представлением будет /Views/Product/List.cshtml.
Стандартное представление используется при возвращении результата вызова метода View() в методе действия, примерно так:
View();
Можно указать имя другого представления:
View(
«MyOtherView»);
Обратите внимание, что мы не включаем в представление расширение имени файла или путь. При поиске представления MVC Framework просматривает папку, имеющую имя контроллера, и затем папку /Views/Shared. Это значит, что представления, применяемые более чем одним контроллером, можно поместить в папку /Views/Shared и инфраструктура найдет их самостоятельно.
Соглашение об именовании для компоновок предусматривает добавление к имени файла символа подчеркивания _, а сами файлы компоновки помещаются в папку /Views/Shared. Среда Visual Studio создает компоновку по имени Layout.cshtml для всех шаблонов проектов кроме Empty. Эта компоновка по умолчанию применяется ко всем стандартным представлениям через файл /Views/_ViewStart.cshtml. Если вы не хотите, чтобы стандартная компоновка применялась к представлениям, можете изменить настройки в _ViewStart.cshtml (либо вообще удалить этот файл), указав другую компоновку в представлении, например:
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; }
Или же можно отключить компоновку для заданного представления:
@{ Layout = null; }
Лучший способ для оценки инфраструктуры, предназначенной для разработки программного обеспечения, заключается в том, чтобы приступить непосредственно к ее использованию. В этой статье мы создадим простое приложение ввода данных с применением ASP.NET MVC Framework. Мы будем решать эту задачу пошагово, чтобы вы поняли, каким образом строится приложение ASP.NET MVC. Для простоты мы пока опустим некоторые технические подробности. Но не беспокойтесь — если вы только начинаете знакомство с MVC, то узнаете много интересного.
Среда Visual Studio Express содержит все средства, необходимые для создания, тестирования и развертывания приложения MVC Framework, но некоторые из этих средств скрыты до тех пор, пока вы их не запросите. Чтобы включить все средства, выберите пункт Expert Settings (Развернутые настройки) в меню Tools —> Settings (Сервис —> Настройки) среды Visual Studio.
По ряду причин в Microsoft решили, что все названия высокоуровневых меню среды Visual Studio должны быть представлены заглавными буквами, т.е. на самом деле упомянутое меню Tools в интерфейсе среды выглядит как TOOLS. Это так, на заметку.
Мы собираемся начать с создания нового проекта MVC Framework в среде Visual Studio. Выберите в меню File(Файл) пункт New Project (Проект).
Далее в открывшемся диалоговом окне вам необходимо указать имя проекта PartyInvite (Приглашение на вечеринку).
В следующем диалоговом окне выбираем пустой проект и ставим галочку MVC для создания базовой структуры проекта MVC приложения и нажимаем кнопу Ок. На этом создание нового проекта завершено.
Шаблоны проектов MVC создают проекты с разными отправными точками и конфигурациями для таких средств, как аутентификация, навигация и визуальные темы. Мы собираемся придерживаться максимальной простоты. Поэтому мы выбрали Empty (Пустой) тип проекта и для автоматического создания структуры проекта отметили флажок MVC в разделе Add folders and core references for (Добавить папки и основные ссылки для), как показано на рисунке выше. Это приведет к созданию базового проекта MVC с минимальным заранее определенным содержимым, который будет служить отправной точкой для всех примеров, рассматриваемых далее.
Другие шаблоны проектов предназначены для обеспечения более полных отправных точек в рамках проектов ASP.NET. Мне не нравятся эти шаблоны тем, что они поощряют восприятие в виде черных ящиков таких важных средств, как аутентификация. Моя цель — предоставить достаточный объем информации для понимания и управления каждым аспектом приложения MVC, вследствие чего в большинстве примеров используется шаблон Empty.
После того как среда Visual Studio создаст проект, в окне Solution Explorer отобразится набор файлов и папок. Это стандартная структура для нового проекта MVC и вы уже узнали, для чего предназначен каждый файл и каждая папка, созданные Visual Studio.
Теперь можно попробовать запустить приложение, выбрав в меню Debug (Отладка) пункт Start Debugging (Запустить отладку); если появится запрос на включение отладки, просто щелкните на кнопке ОК. Результат показан на рисунке ниже. Поскольку мы начали с шаблона проекта Empty, приложение не содержит ничего, что могло бы быть выполнено, поэтому сервер генерирует ошибку 404 Not Found (не найдено):
В архитектуре MVC входящие запросы обрабатываются контроллерами. В ASP.NET MVC контроллеры — это просто классы C# (обычно унаследованные от System.Web.Mvc.Controller, встроенного в инфраструктуру базового класса контроллера). Каждый открытый метод в контроллере называется методом действия а это значит, что его можно вызвать из веб-среды через некоторый URL-адрес для выполнения действия. В соответствии с соглашением MVC контроллеры помещаются в папку Controllers, автоматически создаваемую Visual Studio при настройке проекта.
Соблюдение этого или большинства других соглашений MVC не обязательно, но рекомендуется его придерживаться — и не в последнюю очередь потому, что это поможет уяснить примеры, приведенные далее.
Чтобы добавить контроллер в проект, щелкните правой кнопкой мыши на папке Controllers в окне Solution Explorer среды Visual Studio и выберите в контекстном меню пункт Add (Добавить), а затем Controller (Контроллер), как продемонстрировано на рисунке ниже:
Добавление первого контроллера в MVC проект ASP.NETКогда откроется диалоговое окно Add Scaffold (Добавление шаблона), выберите вариант MVC 5 Controller — Empty (Контроллер MVC 5 — Пустой), как показано на рисунке ниже, и щелкните на кнопке Add (Добавить).
Откроется диалоговое окно Add Controller (Добавление контроллера). Укажите HomeController в качестве имени контроллера и щелкните на кнопке Add (Добавить). С этим именем связано несколько соглашений: имена, выбираемые для контроллеров, должны отражать их назначение, стандартный контроллер называется Home и имена контроллеров имеют суффикс Controller.
Если вы применяли для создания приложений MVC ранние версии Visual Studio, то заметите, что процесс слегка отличается. В Microsoft изменили способ, которым Visual Studio может заполнять проект заранее сконфигурированными классами и другими элементами.
Итак, среда Visual Studio создаст в папке Controllers новый файл C# по имени HomeController.cs и откроет его для редактирования. В примере ниже приведено стандартное содержимое, которое Visual Studio помещает в этот файл класса. Как видите, класс имеет имя DefaultController и является производным от класса Controller, который находится в пространстве имен System.Web.Mvc.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace WebApplication7.Controllers { public class HomeController : Controller { // GET: Default public ActionResult Index() { return View(); } } }
Удобный способ приступить к знакомству с MVC предусматривает внесение в класс контроллера пары простых изменений. Отредактируйте код в файле HomeController.cs так, чтобы он приобрел вид, показанный в примере ниже:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace WebApplication7.Controllers { public class HomeController : Controller { // GET: Default public String Index() { return "Hello, world!"; } } }
Изменения не приводят к каким-то особо впечатляющим результатам, но их вполне достаточно для хорошей демонстрации. Метод действия по имени Index() изменен так, что теперь он возвращает строку «Hello, World». Снова запустите проект, выбрав пункт Start Debugging из меню Debug в Visual Studio. Браузер отобразит результат выполнения метода действия Index(), как показано на рисунке ниже:
Примечание: Не забывайте останавливать проект после запуска. Для остановки проекта используйте кнопку Stop
Если вы не остановите отладку то вы не сможете вносить изменения в свой проект.
Обратите внимание, что среда Visual Studio направляет браузер на порт 45361. В URL-адресе, который будет запрашивать ваш браузер, почти наверняка будет присутствовать другой номер порта, т.к. Visual Studio выделяет произвольный порт при создании проекта. Если вы заглянете в область уведомлений панели задач Windows, то найдете там значок для IIS Express. Этот значок представляет усеченную версию полного сервера приложений IIS, которая входит в состав Visual Studio и используется для доставки содержимого и служб ASP.NET во время разработки.
Кроме моделей, представлений и контроллеров приложения MVC используют систему маршрутизации ASP.NET, которая определяет, как URL отображаются на контроллеры и действия. Когда среда Visual Studio создает проект MVC, она добавляет ряд стандартных маршрутов, выступающих в качестве начальных. Можно запросить любой из следующих URL, и они будут направлены на действие Index контроллера:
/ /Home /Home/Index
Таким образом, когда браузер запрашивает http://ваш-сайт/ или http://ваш_сайт/Home, он получает вывод из метода Index() контроллера HomeController. Можете опробовать это самостоятельно, изменив URL в браузере. В настоящий момент он будет выглядеть как http://localhost:45361/, при этом часть, представляющая порт, может быть другой. Если вы добавите к URL порцию /Home или /Home/Index и нажмете клавишу <Enter>, то получите от приложения MVC тот же самый результат — строку «Hello, world».
Это хороший пример получения выгоды от соблюдения соглашений MVC. В данном случае соглашение заключается в том, что контроллер назван HomeController, и он будет служить стартовой точкой нашего приложения MVC. При создании стандартных маршрутов для нового проекта среда Visual Studio исходит из предположения, что мы будем следовать этому соглашению. И поскольку мы действительно соблюдаем соглашение, мы автоматически получаем поддержку всех URL из приведенного выше списка.
Если же не следовать соглашению, маршруты пришлось бы изменить так, чтобы они указывали на контроллер, созданный вместо стандартного. В приведенном простом примере стандартная конфигурация — это все, что требуется.
Выводом предыдущего примера была не HTML-разметка, а просто строка «Hello World». Чтобы сгенерировать HTML-ответ на запрос браузера, понадобится создать представление.
Прежде всего, необходимо вернуть метод действия Index() в исходное состояние, как показано в примере ниже:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace WebApplication7.Controllers { public class HomeController : Controller { // GET: Default public ActionResult Index() { return View(); } } }
Возвращая объект ViewResult из метода действия, мы тем самым указываем MVC, что нужно визуализировать представление. Экземпляр ViewResult создается вызовом метода View() без параметров. Это указывает инфраструктуре MVC на то, что для действия необходимо визуализировать стандартное представление.
Если запустить приложение на этом этапе, легко убедиться, что MVC Framework пытается найти для использования стандартное представление по умолчанию, как показано в сообщении об ошибке на рисунке ниже:
Данное сообщение об ошибке исключительно полезно. Оно не только поясняет, что инфраструктура MVC не смогла найти представление для метода действия, но и показывает, где производился поиск. Это еще одна хорошая иллюстрация соглашения MVC: представления ассоциируются с методами действий с помощью соглашения об именовании. Метод действия называется Index(), а контроллер — Home, и, как видно на рисунке, инфраструктура MVC пытается найти в папке Views файлы с таким именем.
Простейший способ создания представления предусматривает поручение этой работы среде Visual Studio. Щелкните правой кнопкой внутри определения метода действия Index() в окне редактора кода, в котором открыт файл HomeController.cs, и выберите в контекстном меню пункт Add View (Добавить представление), как показано на рисунке ниже:
Во вкладке View Создайте папку Home
В этой папке добавьте View
Назовите созданный View Index
Уберите галочку использовать шаблон
Не переживайте, если в настоящий момент все эти опции непонятны — они будут подробно объяснены позже. Щелкните на кнопке Add (Добавить), чтобы создать новый файл представления.
Среда Visual Studio создаст новый файл по имени Index.cshtml в папке Views/Home. Если это не то, что вам хотелось, удалите созданный файл и попробуйте проделать все заново. Это еще одно соглашение MVC Framework: представления помещаются в папку Views, организуясь внутри нее в папки, имена которых соответствуют именам ассоциированных с ними контроллеров.
Расширение файла .cshtml обозначает представление C#, которое будет обработано механизмом визуализации Razor. Ранние версии MVC полагались на механизм визуализации ASPX, файлы представлений которого имели расширение .aspx.
В результате установки опций в диалоговом окне Add View среда Visual Studio создает весьма базовое представление с содержимым, приведенным в примере ниже:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div> Привет мир (из представления) </div> </body> </html>
Добавьте внутрь тега <div> текст «Привет мир (из представления)»
Запустите проект.
Весь смысл платформы для разработки веб-приложений сводится к конструированию и отображению динамического вывода. В рамках MVC работа контроллера заключается в создании определенных данных и передаче их представлению, которое отвечает за их визуализацию в виде HTML-разметки.
Один из способов передачи данных из контроллера в представление предусматривает использование объекта ViewBag, который является членом базового класса ControllerBase.
Объект ViewBag — это динамический объект, в котором можно устанавливать произвольные свойства, делая эти значения доступными в любом визуализируемом далее представлении. В примере ниже демонстрируется передача простых динамических данных в файле HomeController.cs указанным способом.
Код контроллера с динамическим выводом
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace WebApplication7.Controllers { public class HomeController : Controller { // GET: Default public ActionResult Index() { int hour = DateTime.Now.Hour; ViewBag.Greeting = hour < 12 ? "Доброе утро" : "Доброго дня"; return View(); } } }
Код представления с динамическим выводом
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div> @ViewBag.Greeting (из представления) </div> </body> </html>
Задание.
Динамически вывести таблицу 12 на 12 ячеек и заполнить ее рамочку единицами а центральную часть нулями.