Модель приложения ASP.NET MVC 4.0 2014 Цель • Применить модель при разработке приложений • Научиться использовать движок Razor в шаблонах страниц 2 Траектория запроса GET, POST Метод контроллера Данные, которые нужно показать HTML Шаблон представления Запрос к модели Модель Модель – система классов (описание предметной области). Запрос к модели – вызов метода одного из классов модели. Модель представления – данные, которые нужно показать 3 Задача: Сделать чат Макет страницы Протокол чата Подпись Новое сообщение Кнопка 4 Состав приложения 5 Модель: классы ChatItem и Chat public class ChatItem { public string Message { set; get; } public string Author { set; get; } public DateTime Time { set; get; } } public static class Chat { public static List<ChatItem> list = new List<ChatItem>(); static object _objLock = new Object(); public static void AddItem(ChatItem item) { if (string.IsNullOrWhiteSpace(item.Author)) item.Author = "Anonimus"; item.Time = DateTime.Now; lock (_objLock) { list.Add(item); } } } 6 Модель представления public class VModel { public List<ChatItem> All { set; get; } public string Message { set; get; } public string Author { set; get; } } Модель представления должна быть близка структуре представления. 7 Контроллер У контроллера две задачи: 1) по команде GET показать первоначальный вид страницы – протокол чата и поле ввода для нового сообщения; 2) по команде POST добавить сообщение в протокол и снова показать страницу. public class HomeController : Controller { [HttpGet] public ActionResult Index() { // Показать страницу VModel vm = new VModel { All = Chat.list, Author = "" }; return View(vm); } [HttpPost] public ActionResult Index(VModel item) { // Добавить сообщение в протокол if (ModelState.IsValid) Chat.AddItem(item); // Показать страницу VModel vm = new VModel { All = Chat.list, Author = item.Author }; return View(vm); } } 8 Типизированное представление Шаблон типизированного представления строится с учетом типа модели представления. Состав типа определяется при помощи отражения. Если выбрать опцию Empty никакого специального кода построено не будет. @model ChatMVC.Models.VModel @{ ViewBag.Title = "Index"; } <h2>Index</h2> Типизация представления выражается только в появлении в шаблоне свойства Model. 9 Шаблон представления @model ChatMVC.Models.VModel @{ Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Chat MVC</h2> <div id="chat"> @foreach (var item in Model.All) { <section class='message'> <span class='author'>@item.Author: </span> @item.Message <br /> <span class='time'>@item.Time</span> </section> } </div> <form method="post" action="/Home/Index"> @Html.ValidationSummary() Сообщение:<br/> <textarea id="message" name="message" ></textarea> <br/> Подпись: <input type="text" id="author" name="author" value="@Model.Author"/> <input type="submit" value="Submit"/> <br/> </form> Директива @model позволяет получать подсказки во время разработки. Во время выполнения она роли не играет. 10 Проверка ввода Пользователь вводит данные в веб-форму, затем они попадают в контроллер, контроллер пересылает их в модель. Браузер Контроллер Модель Ввод пользователя можно проверять в трех местах: 1) в браузере перед отсылкой формы, 2) в контроллере перед передачей в модель, 3) в модели перед тем как изменить состояние модели. Только модель владеет информацией, необходимой для полной проверки данных – это плюс. Если проверять в модели, то это придется делать безотносительно того, вводились ли данные пользователем или были получены из надежного источника – это минус. 11 Проверка в модели, интерфейс IValidatableObject public class VModel: IValidatableObject { public List<ChatItem> All { set; get; } public string Message { set; get; } public string Author { set; get; } public IEnumerable<ValidationResult> Validate( ValidationContext validationContext) { if (string.IsNullOrWhiteSpace(Message)) yield return new ValidationResult("Message must not be empty."); } } При помощи интерфейса IValidatableObject MVC фреймворк собирает сведения об ошибках в коллекцию ModelState. Объект ModelState потом будет доступен в контроллере и в представлении. 12 Действия в контроллере и в представлении В контроллере: [HttpPost] public ActionResult Index(VModel vm) { if (ModelState.IsValid) { ChatItem item = new ChatItem() { Message = vm.Message, Author = vm.Author }; Chat.AddItem(item); vm.Message = ""; vm.Author = ""; } vm.All = Chat.list; return View(vm); } В представлении: <form method="post" action="/Home/Index"> @Html.ValidationSummary() Сообщение:<br/> <textarea id="message" name="message" ></textarea> <br/> Подпись: <input type="text" id="author" name="author" value="@Model.Author"/> <input type="submit" value="Submit"/> <br/> </form> 13 Bundling & Minification public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new StyleBundle("~/css").Include("~/Content/site.css")); bundles.Add(new ScriptBundle("~/js").Include("~/Scripts/site.js")); } } @Styles.Render("~/css") @Scripts.Render("~/js") + = <script src="/Scripts/site.js"></script> <link href="/Content/site.css" rel="stylesheet"/> Метод RegisterBundles() вызывается на старте приложения. Строка "~/css" – имя упаковки. Имя должно иметь вид виртуального пути в приложении. В web.config должна быть указана версия целевого фреймвормка, у нас это 4.5. <compilation debug="false" targetFramework="4.5" /> 14 Программный код в шаблонах представления Начиная с ASP в 1996 г., код шаблонов страниц представлял собой смесь из HTML-разметки и кода на языке программирования – VB или C#. <% foreach (var item in Model) { %> <tr> <td> <%: Html.DisplayFor(modelItem => item.Message) %> </td> </tr> <% } %> Код на C# отделялся от кода разметки специальными скобками <% %> Начиная с MVC 3, можно использовать разные интерпретаторы для рендеринга шаблонов. Студия по умолчанию предлагает два: старый – ASPX и новый – Razor. 15 Движок Razor http://habrahabr.ru/post/98241/ - перевод статьи с блога Скотта Гаттри Границы разметки и кода Основная особенность Razor в том, что для разделения языков предлагаются не две скобки, а одна. Где начинается код? Когда парсер встречает знак @, он проверяет, может ли то, что следует за ним, рассматриваться как код. Где начинается разметка? Начало определяется по наличию тэга <>. В движке есть специальный тэг <text>… </text>, единственная задача которого обозначить разметку. В отличие от HTML-тэгов <text> не будет показан на странице. 17 Сложные выражения • Круглые скобки @( ) позволяют выводить значения выражений. 18 Многострочные выражения В блок @{ } можно вставить несколько строчек кода 19 Блоки @if и @foreach Переменная может быть видна в несколько серверных блоках кода. 20 Интеграция содержимого и кода Этот код, выведет следующий HTML: Email-адрес выведется, как статическое содержимое, а @DateTime.Now определится, как код. Чтобы показать символ '@', пишут @@, но это нужно не всегда. 21 Обертывание в тэги Вывод: 22 Кодирование HTML По умолчанию содержимое, выводимое в блоках @, автоматически кодировано в HTML. Кодирование необходимо для защиты против XSS-атак (англ. Сross Site Sсriрting — «межсайтовый скриптинг»). Если нужен "не испорченный" HTML, применяйте HtmlString. @( "<h1>привет</h1>" + "с Марса") @( new HtmlString("<h1>привет</h1>" + "с Марса") ) 23 Самостоятельно Запрограммировать игру в города – когда следующий город начинается на последнюю букву предыдущего. Некорректные города не принимаются. Корректным считается город, который: - не пустой, - начинается на последнюю букву (кроме "ь", тогда – на предпоследнюю) -ранее не играл. Первый город может быть любым. Все уже названные города должны быть показаны на странице в виде маркированного списка <ul>. 24