ASP.NET MVC для начинающих. Часть 2. Работа с формами.
В экшене Index() контроллера HomeController напишем такой код:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MvcApplication1.Models; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ViewResult Index() { int hour = DateTime.Now.Hour; ViewData["greeting"] = (hour < 12 ? "Доброе утро" : "Добрый вечер"); return View(); } } }
Ничего сложного, в зависимости от времени суток выводится определенное приветствие. Код вьюхи Index выглядит так:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Index</title> </head> <body> <h1>Сейшен !</h1> <%= ViewData["greeting"] %>! Для участия в вечеринке, ты должен сообщить о себе. <%= Html.ActionLink("Перейти к регистрации", "RegForm") %> </body> </html>
Запускаем, проверяем ссылку. Вьюхи RegForm пока нет, сейчас мы ее создадим. Нам понадобятся три ТекстБокса (имя, мыло, телефон), один ДропДаунЛист и кнопка отправки данных.
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Форма регистрации</title> </head> <body> <h1>Регистрация</h1> <% using(Html.BeginForm()) { %> Твое имя: <%= Html.TextBox("Name") %> Твое мыло: <%= Html.TextBox("Email")%> Твой телефон: <%= Html.TextBox("Phone")%> Будет весело. Ты решился ? <%= Html.DropDownList("WillAttend", new[] { new SelectListItem { Text = "Да, я готов", Value = bool.TrueString }, new SelectListItem { Text = "Наверное нет", Value = bool.FalseString } }, "Выбирай") %> <input type="submit" value="Зарегиться" /> <% } %> </body> </html>
С введенными данными нужно что-то делать, независимо от того, что именно, работать с данными должна модель. Правильнее было бы наверное сначала спроектировать модель, а затем вьюху, но мы сделали так. У нас имеется четыре контрола, которые предоставят нам свои данные, соответственно для каждого из них создадим по свойству – все предельно просто:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcApplication1.Models { public class GuestResponseModel { public string Name { get; set; } public string Email { get; set; } public string Phone { get; set; } public bool? WillAttend { get; set; } } }
Мы подошли к месту, где нужно немного включить мозг, поэтому, если вы устали, отчаялись и уже хотите забить – отдохните :D, хотя ничего сложного не предвидится, если вы намерены идти дальше – следуйте за мной :D.
Небольшое подведение итогов: у нас есть модель в кол-ве 1шт, есть вьюхи в кол-ве 2шт, есть экшен контроллера в кол-ве 1шт. Видите нестыковку ? Не хватает экшена RegForm(). Сделаем его как делали раньше, т.е. метод нам просто возвратит View():
public ViewResult RegForm() { return View(); }
Запускаем проект, вводим регистрационные данные, отправляем их. После нажатия на кнопку отправки, наши контролы возвращаются пустыми. HTTP-протокол не поддерживает состояния между запросами, при каждой новой загрузке страницы, все контролы создаются заново (чистыми), в Webforms эта проблема решается использованием Viewstate и Postback (это один из вариантов), информация Viewstate хранит в себе данные о состоянии объекта до его отправки на сервер, вновь создаваемый объект восстанавливает свое состояние из Viewstate. За эти прелести приходится платить – Viewstate гоняется на сервер и обратно при каждом запросе, следовательно растет объем передаваемых данных, и появляется SEO-кошмар в коде HTML. В ASP.NET MVC отсутствует Viewstate, поэтому будем делать как в старые добрые времена – методами GET и POST. Методом GET мы запрашиваем страницу RegForm, отсылать данные мы будем методом POST, поэтому нам нужны два варианта экшена RegForm() контроллера HomeController:
[AcceptVerbs(HttpVerbs.Get)] public ViewResult RegForm() { return View(); } [AcceptVerbs(HttpVerbs.Post)] public ViewResult RegForm(MvcApplication1.Models.GuestResponseModel guestResponse) { return View(guestResponse); }
Теперь все должно работать как надо. То, как входные данные связываются с моделью и контроллером объясняется работой ASP.NET MVC. Познакомимся теперь с Strongly Typed Views. Для этого перепишем код последнего экшена:
[AcceptVerbs(HttpVerbs.Post)] public ViewResult RegForm(MvcApplication1.Models.GuestResponseModel guestResponse) { return View("Thanks", guestResponse); }
ASP.NET MVC теперь должна находить и отрисовывать вьюху Thanks, снабжая ее объектом guestResponse. Создадим Strongly Typed View с именем Thanks, для этого в появившемся модальном окне Add View отметим пункт Create a strongly typed view и из выпадающего списка выберем MvcApplication1.Models.GuestResponseModel, пункт “View content” поставим в Empty. Созданная вьюха будет строго типизирована для работы с GuestResponse, поэтому у нас будет возможность работать с Model класса GuestResponseModel:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<mvcApplication1.Models.GuestResponseModel>" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Спасибо</title> </head> <body> <h1>Привет, <%= Html.Encode(Model.Name) %>!</h1> <% if(Model.WillAttend == true) { %> Отлично, что ты придешь ! <% } else { %> Очень жаль. <% } %> </body> </html>
Кроме точного определения типа данных для рендеринга, используя Strongly Typed Views, мы получаем полную поддержку IntelliSense для нашего типа данных.
Добавим валидацию. Не забываем, что мы используем паттерн MVC, а следовательно валидация должна быть частью модели, а не чего-либо еще. Перепишем код модели:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.ComponentModel; namespace MvcApplication1.Models { public class GuestResponseModel : IDataErrorInfo { public string Name { get; set; } public string Email { get; set; } public string Phone { get; set; } public bool? WillAttend { get; set; } public string Error { get { return null; } } public string this[string propName] { get { if ((propName == "Name") && string.IsNullOrEmpty(Name)) return "Имя не введено"; else if ((propName == "Email") && string.IsNullOrEmpty(Email)) return "Некорректный е-майл"; else if ((propName == "Phone") && string.IsNullOrEmpty(Phone)) return "Телефон не введен"; else if ((propName == "WillAttend") && !WillAttend.HasValue) return "Никак не определишься ?"; return null; } } } }
Теперь нам необходимо немного переписать экшен RegForm:
[AcceptVerbs(HttpVerbs.Post)] public ViewResult RegForm(MvcApplication1.Models.GuestResponseModel guestResponse) { if (ModelState.IsValid) { return View("Thanks", guestResponse); } else return View(); }
и добавить сообщение о валидации на страницу RegForm:
<%= Html.ValidationSummary() %>
Как вы заметили, валидация довольно простенькая, без регулярок и т.п., в этом уроке у нас другая цель — познакомиться с формами.
где то я уже видел этот пример;))в одной книге
Даешь копипаст в народ!
Добрый день!
Будьте добры подскажите почему в данном коде возникает ошибка в месте где else (ошибка — недопустимый элемент «else» в выражении)
Заранее признателен!
@Kiril1
В каком конкретно месте ? Код, насколько я помню, тестировал сам, когда разбирался с MVC, и подобных ошибок не помню.
@alessandro
Тем не менее, многие почему-то ленятся читать книги и задают вопросы на форумах/сайтах, поэтому, чтобы не высасывать из пальца, порой проще скопипастить.
Не подскажит назвние книги?
Я уже нашел.