Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP_NET_MVC_4_Framework_s_primerami_na_C_dlya_p

.pdf
Скачиваний:
25
Добавлен:
19.03.2016
Размер:
17.66 Mб
Скачать

мы укажем тип, с которым мы хотим работать (в этом примере GuestResponse), MVC предоставит дополнительные возможности, чтобы упростить нам задачу.

Внимание

Убедитесь, что перед работой ваш MVC проект скомпилирован. Если вы создали класс GuestResponse, но не скомпилировали его, MVC не сможет создать строго

типизированное представление для данного типа. Чтобы скомпилировать приложение, выберите Build Solution в Visual Studio меню Build.

Щелкните правой кнопкой мыши внутри метода действия RsvpForm и выберите для создания представления Add View из всплывающего меню. В диалоговом окне Add View поставьте галочку на Create a strongly-typed view и выберите опцию GuestResponse из выпадающего меню.

Снимите флажок с Use a layout or master page и убедитесь, что Razor выбран в качестве движка представления, и что опция Scaffold template установлена на Empty, как показано на рисунке 2-14.

Рисунок 2-14: Добавление строго типизированного представления

Нажмите кнопку Add, и Visual Studio создаст новый файл с именем RvspForm.cshtml и откроет его для редактирования. Вы можете увидеть первоначальное содержание в листинге 2-12. Как вы

31

заметили, это другой HTML файл, но он содержит Razor выражение @model. Вы сейчас увидите, что это является ключом к строго типизированному представлению и возможностям, которые оно предлагает.

Листинг 2-12: Начальное содержимое файла RsvpForm.cshtml

@model PartyInvites.Models.GuestResponse

@{

Layout = null;

}

<!DOCTYPE html> <html>

<head>

<meta name="viewport" content="width=device-width" /> <title>RsvpForm</title>

</head>

<body>

<div>

</div>

</body>

</html>

Построение формы

Теперь, когда мы создали строго типизированное представление, мы можем выстроить содержание RsvpForm.cshtml, чтобы превратить его в HTML форму для редактирования GuestResponse объектов. Измените представление так, чтобы оно соответствовало листингу 2-13.

Листинг 2-13: Создание представления формы

@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>Your name: @Html.TextBoxFor(x => x.Name) </p> <p>Your email: @Html.TextBoxFor(x => x.Email)</p> <p>Your phone: @Html.TextBoxFor(x => x.Phone)</p> <p>

Will you attend?

@Html.DropDownListFor(x => x.WillAttend, new[] {

new SelectListItem() {Text = "Yes, I'll be there", Value = bool.TrueString},

new SelectListItem() {Text = "No, I can't come", Value = bool.FalseString} }, "Choose an option")

</p>

<input type="submit" value="Submit RSVP" />

}

</body>

</html>

32

Для каждого свойства класса модели GuestResponse мы используем вспомогательный метод HTML, чтобы обработать подходящий HTML элемент управления input. Эти методы позволяют выбрать свойство, к которому относится элемент input, с помощью лямбда-выражения, например вот так:

@Html.TextBoxFor(x => x.Phone)

Вспомогательный метод HTML TextBoxFor генерирует HTML для элемента input, устанавливает параметр type на text и устанавливает атрибуты id и name на Phone, имя выбранного свойства доменного класса, вот так:

<input id="Phone" name="Phone" type="text" value="" />

Эта удобная функция работает, потому что наше представление RsvpForm строго типизировано, и мы сказали MVC, что GuestResponse это тот тип, который мы хотим обработать при помощи данного представления, поэтому вспомогательные методы HTML могут понять, какой тип данных мы хотим прочитать, с помощью выражения @model.

Не волнуйтесь, если вы не знакомы с лямбда-выражениями C#. Мы расскажем о них в главе 4, но в качестве альтернативы лямбда-выражениям вы можете обратиться к имени свойства типа модели как к строке, например, вот так:

@Html.TextBox("Email")

Мы считаем, что методика лямбда-выражений помогает нам не делать опечаток в имени свойства типа модели, потому что всплывает Visual Studio IntelliSense и позволяет нам выбрать свойство автоматически, как показано на рисунке 2-15.

Рисунок 2-15: Visual Studio IntelliSense для лямбда-выражений во вспомогательных методах

HTML

Другим удобным вспомогательным методом является Html.BeginForm, который генерирует элемент HTML формы, настроенный на обратную передачу данных методу действия. Поскольку мы не передали вспомогательному методу никаких параметров, он предполагает, что мы хотим

33

передать обратно тот же URL. Ловким трюком является то, чтобы обернуть это в C# выражение using, вот таким образом:

@using (Html.BeginForm()) {

...form contents go here...

}

Обычно, когда оно применяется таким образом, выражение using гарантирует, что объект удаляется, когда выходит из области видимости. Оно широко используется для подключения к базе данных, например, чтобы убедиться, что она закрывается, как только запрос был выполнен. (Это применение ключевого слова using отличается от того, что касается области видимости класса).

Вместо удаления объекта, помощник HtmlBeginForm закрывает HTML элемент form, когда он выходит из области видимости. Это означает, что вспомогательный метод Html.BeginForm создает обе части элемента form, например:

<form action="/Home/RsvpForm" method="post">

...form contents go here...

</form>

Не волнуйтесь, если вы не знакомы с удалением объектов в C#. Наша цель на данный момент состоит в том, чтобы показать, как создать форму с помощью вспомогательного метода HTML. Вы можете видеть форму в представлении RsvpForm, когда вы запустите приложение и нажмете ссылку RSVP Now. На рисунке 2-16 показан результат.

Рисунок 2-16: Представление RspvForm

Примечание

Это не книга о CSS или веб дизайне. По большей части мы будем создавать примеры, внешний вид которых может быть описан как устаревший (хотя мы предпочитаем термин классический, в котором чувствует меньше пренебрежения). MVC представления генерируют очень чистый и простой HTML, и

34

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

Обработка форм

Мы не сказали MVC, что мы хотим сделать, когда форма отправляется на сервер. На данный момент нажатие на кнопку Submit RSVP просто удаляет любые значения, которые вы ввели в

форму. Это потому что форма отправляется обратно методу действия RsvpForm в контроллере Home, который просто говорит MVC обработать представление еще раз.

Примечание

Вы можете быть удивлены тем фактом, что входные данные теряются, когда представление снова обрабатывается. Если это так, то вы, вероятно, разрабатывали приложения при помощи ASP.NET Web Forms, который автоматически сохраняет данные в этой ситуации. Мы покажем вам, как добиться такого же результата с MVC в ближайшее время.

Чтобы получить и обработать отправленные данные формы, мы собираемся сделать умную и классную вещь. Мы добавим второй метод действия RsvpForm для того, чтобы создать следующее:

Метод, который отвечает на HTTP GET запросы: GET запрос является тем, с чем браузер имеет дело после каждого клика по ссылке. Этот вариант действий будет отвечать за отображение начальной пустой формы, когда кто-то первый раз посетит /Home/RsvpForm.

Метод, который отвечает на HTTP POST запросы: По умолчанию, формы,

обрабатываемые при помощи Html.BeginForm(), отправляются браузером как POST запросы. Этот вариант действий будет отвечать за получение отправленных данные и решать, что с ними делать.

Обработка GET и POST запросов в отдельных методах C# помогает сохранить наш код опрятным, так как оба метода имеют различные обязанности. Оба метода действия вызываются одним и тем же URL, но MVC гарантирует, что будет вызван соответствующий метод в зависимости от того, имеем ли мы дело с GET или с POST запросом. В листинге 2-14 показаны изменения, которые мы должны сделать в классе HomeController.

Листинг 2-14: Добавление метода действия для поддержки POST запросов

using System;

using System.Collections.Generic; using System.Linq;

using System.Web; using System.Web.Mvc;

using PartyInvites.Models;

namespace PartyInvites.Controllers

{

public class HomeController : Controller

{

public ViewResult Index()

{

int hour = DateTime.Now.Hour;

ViewBag.Greeting = hour < 12 ? "Good Morning" : "Good Afternoon"; return View();

35

}

[HttpGet]

public ViewResult RsvpForm()

{

return View();

}

[HttpPost]

public ViewResult RsvpForm(GuestResponse guestResponse)

{

// TODO: Email response to the party organizer return View("Thanks", guestResponse);

}

}

}

Мы добавили атрибут HttpGet для нашего существующего метода действия RsvpForm. Это говорит MVC, что данный метод должен использоваться только для GET запросов. Затем мы добавили перегруженную версию RsvpForm, который принимает параметр GuestResponse и применяет атрибут HttpPost. Атрибут говорит MVC, что новый метод будет иметь дело с POST запросами. Обратите внимание, что мы также импортировали пространство имен PartyInvites.Models – таким образом мы можем обратиться к типу модели GuestResponse без необходимости указывать имя класса. Мы расскажем, как работают наши дополнения в листинге, в следующих разделах.

Использование связывания данных модели

Первый вариант перегруженного метода действия RsvpForm обрабатывает то же представление, что и раньше. Она генерирует форму, показанную на рисунке 2-16. Второй вариант перегруженного метода является более интересным из-за параметра, но, учитывая, что метод действия будет вызываться в ответ на HTTP POST запрос, и что GuestResponse является типом класса C #, то как они объединены?

Ответом является связывание данных модели – чрезвычайно полезная функциональная особенность MVC, когда входные данные разбиваются (парсятся) и пары ключ/значение в HTTP запросе используются для заполнения свойств типа доменной модели. Этот процесс является противоположностью использования вспомогательных методов HTML; это когда при создании данных формы для отправки клиенту, мы генерировали HTML элементы input, где значения атрибутов id и name были получены из названий свойств классов моделей.

В отличие от этого, со связыванием данных модели, имена элементов input используются для указания значений свойств в экземпляре класса модели, которые затем передаются нашему методу действия с POST поддержкой.

Модель представления данных является мощной и настраиваемой функцией, которая избавляет от рутины работы напрямую с HTTP-запросами и позволяет нам работать с C# объектами, а не иметь

дело со значениями Request.Form[] и Request.QueryString[]. Объект GuestResponse, который передается в качестве параметра нашему методу действия, автоматически заполняется данными из полей формы. Мы рассмотрим подробно модель представления данных, а также в том числе, как ее можно настроить, в главе 22.

Обработка других представлений

36

Второй вариант перегруженного метода действий RsvpForm также показывает, как мы можем указать MVC обрабатывать конкретное представление, а не представление по умолчанию, в ответ на запрос. Вот соответствующее выражение:

return View("Thanks", guestResponse);

Этот вызов метода View говорит MVC найти и обработать представление, которое называется Thanks, и передать представлению наш объект GuestResponse. Чтобы создать представление, которое мы указали, щелкните правой кнопкой мыши внутри одного из методов HomeController и выберите пункт Add View из всплывающего меню. Установите имя представления на Thanks, как показано на рисунке 2-17.

Рисунок 2-17: Добавление представления Thanks

Мы собираемся создать еще одно строго типизированное представление, поэтому поставьте галочку на этом пункте в диалоговом окне Add View. Класс данных, который мы выберем для этого представления, должен соответствовать классу, который мы передали представлению при помощи метода View. Поэтому убедитесь, что в выпадающем меню выбран GuestResponse. Убедитесь, что нет галочки на Use a layout or master page, View engine установлен на Razor,

а также Scaffold template установлен на Empty.

37

Нажмите кнопку Add, чтобы создать новое представление. Поскольку представление связано с контроллером Home, MVC создаст представление как ~/Views/Home/Thanks.cshtml. Измените новое представление так, чтобы оно соответствовало листингу 2-15: мы выделили то, что нужно добавить.

Листинг 2-15: Представление Thanks

@model PartyInvites.Models.GuestResponse

@{

Layout = null;

}

<!DOCTYPE html> <html>

<head>

<meta name="viewport" content="width=device-width" /> <title>Thanks</title>

</head>

<body>

<div>

<h1>Thank you, @Model.Name!</h1> @if (Model.WillAttend == true)

{

@:It's great that you're coming. The drinks are already in the fridge!

}

else

{

@:Sorry to hear that you can't make it, but thanks for letting us know.

}

</div>

</body>

</html>

Представление Thanks использует Razor для отображения контента на основе значения свойства GuestResponse, которые мы передали методу View в методе действия RsvpForm. Razor оператор @model определяет тип доменной модели, с которым связано представление. Чтобы получить доступ к значению свойства доменного объекта, мы используем Model.PropertyName. Например, чтобы получить значение свойства Name, мы вызываем Model.Name. Не волнуйтесь, если вам не понятен синтаксис Razor, мы объясним это подробно в главе 5.

Теперь, когда мы создали представление Thanks, у нас есть базовый рабочий пример обработки формы при помощи MVC.

Запустите приложение в Visual Studio, нажмите на ссылку RSVP Now, добавьте в форму данные и нажмите на кнопку Submit RSVP. Вы увидите результат, показанный на рисунке 2-18 (хотя он может отличаться, если ваше имя не Джо, и вы сказали, что не сможете присутствовать).

Рисунок 2-18: Обработанное представление Thanks

38

Добавление валидации

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

В приложении MVC проверка, как правило, применяется к доменной модели, а не к пользовательскому интерфейсу. Это обозначает, что мы определяем наши критерии валидации в одном месте, и они вступают в силу в любом месте используемого класса модели. ASP.NET MVC поддерживает правила проверки, определяемые атрибутами пространства имен

System.ComponentModel.DataAnnotations. В листинге 2-16 показано, как эти атрибуты могут быть применены к классу модели GuestResponse.

Листинг 2-16: Применение валидации к классу модели GuestResponse

using System.ComponentModel.DataAnnotations;

namespace PartyInvites.Models

{

public class GuestResponse

{

[Required(ErrorMessage = "Please enter your name")] public string Name { get; set; }

[Required(ErrorMessage = "Please enter your email address")] [RegularExpression(@".+\@.+\..+", ErrorMessage = "Please enter a valid email

address")]

public string Email { get; set; }

[Required(ErrorMessage = "Please enter your phone number")] public string Phone { get; set; }

[Required(ErrorMessage = "Please specify whether you'll attend")] public bool? WillAttend { get; set; }

}

}

Правила валидации выделены жирным шрифтом. MVC автоматически обнаруживает атрибуты и использует их для проверки данных во время представления модели данных. Обратите внимание, что мы импортировали пространство имен, содержащее правила валидации, поэтому мы можем ссылаться на них без необходимости указывать их имена.

39

Совет

Как отмечалось ранее, мы использовали тип bool? для свойства WillAttend, поэтому мы смогли применить атрибут валидации Required. Если бы мы использовали обычный bool, значение, которое мы могли бы получить благодаря модели представления данных, могло бы быть только true или false, и мы не были бы сказать, выбрал ли пользователь значение. Тип bool? имеет три возможных значения: true, false и null. Значение null будет использовано, если пользователь не выбрал значение, и это заставляет атрибут Required

сообщить об ошибке валидации.

Мы можем проверить, была ли ошибка валидации проверкой с помощью свойства ModelState.IsValid в нашем классе контроллера. В листинге 2-17 показано, как это можно сделать в нашем методе действия RsvpForm с поддержкой POST.

Листинг 2-17: Проверка на наличие ошибок при валидации формы

[HttpPost]

public ViewResult RsvpForm(GuestResponse guestResponse)

{

if (ModelState.IsValid)

{

// TODO: Email response to the party organizer return View("Thanks", guestResponse);

}

else

{

// there is a validation error return View();

}

}

Если ошибки валидации нет, мы говорим MVC обрабатывать представление Thanks, как мы делали ранее. Если ошибка валидации есть, мы вновь обрабатываем представление RsvpForm, вызвав метод View без параметров.

Просто отображать форму, когда есть ошибка, не очень полезно, мы должны дать пользователю некоторую информацию о том, в чем заключается проблема, и почему мы не можем принять его форму. Мы делаем это с помощью вспомогательного метода Html.ValidationSummary в представлении RsvpForm, как показано в листинге 2-18.

Листинг 2-18: Использование вспомогательного метода Html.ValidationSummary

@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())

{

40

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]