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

ASP_NET_MVC_4_Framework_s_primerami_na_C_dlya_p

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

Вспомогательные методы для URL и Ajax

В этой главе мы собираемся закончить со вспомогательными методами MVC. Мы покажем вам те методы, которые способны генерировать URL-адреса, ссылки и элементы с включенным Ajax. Ajax является ключевой особенностью любого богатого веб-приложения, и MVC фреймворк включает в себя некоторые полезные функции, которые основаны на библиотеке JQuery. Мы покажем вам, как все это работает и как вы можете создавать формы и ссылки с включенным Ajax.

Примечание

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

Обзор и подготовка проекта для примера

Мы собираемся продолжать использовать проект HelperMethods, который мы создали в главе 19 и дополнили в главе 20. Некоторые из наших примеров в данной главе будут использовать информацию о маршрутизации, которую мы определили в проекте, и это, как напоминание, показано в листинге 21-1.

Листинг 21-1: Содержание файла /App_Start/RouteConfig.cs

using System;

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

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

using System.Web.Routing; namespace HelperMethods

{

public class RouteConfig

{

public static void RegisterRoutes(RouteCollection routes)

{

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute( name: "Default",

url: "{controller}/{action}/{id}", defaults: new

{

controller = "Home", action = "Index",

id = UrlParameter.Optional

}

);

routes.MapRoute( name: "FormRoute",

url: "app/forms/{controller}/{action}" );

}

}

}

531

Наша конфигурация маршрутизации довольно проста. Она состоит из роута по умолчанию, добавленного Visual Studio, когда проект был создан, и дополнительного роута FormRoute, который имеет два статических сегмента.

Для этой главы мы создали новый контроллер People, как показано в листинге 21-2. Этот контроллер определяет коллекцию объектов Person, которую мы будем использовать, чтобы продемонстрировать различные функции вспомогательных методов.

Листинг 21-2:Контроллер People

using System;

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

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

using HelperMethods.Models; namespace HelperMethods.Controllers

{

public class PeopleController : Controller

{

private Person[] personData = {

new Person {FirstName = "Adam", LastName = "Freeman", Role = Role.Admin}, new Person {FirstName = "Steven", LastName = "Sanderson", Role = Role.Admin}, new Person {FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User}, new Person {FirstName = "John", LastName = "Smith", Role = Role.User},

new Person {FirstName = "Anne", LastName = "Jones", Role = Role.Guest} };

public ActionResult Index()

{

return View();

}

public ActionResult GetPeople()

{

return View(personData);

}

[HttpPost]

public ActionResult GetPeople(string selectedRole)

{

if (selectedRole == null || selectedRole == "All")

{

return View(personData);

}

else

{

Role selected = (Role)Enum.Parse(typeof(Role), selectedRole); return View(personData.Where(p => p.Role == selected));

}

}

}

}

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

Мы также должны добавить к проекту некоторые новые стили CSS. В предыдущих главах мы показали, что можно определить стили в отдельных представлениях или макетах, но мы собираемся

532

определить нужные нам стили в файле /Content/Site.css, для которого есть элемент link в файле /Views/Shared/_Layout.cshtml. Вы можете увидеть, какие стили мы добавили в Site.css, в листинге 21-3. Мы определим элементы, к которым они применяют, далее в этой главе.

Листинг 21-3: Добавление стилей в файл Site.css

...

table, td, th {

border: thin solid black; border-collapse: collapse; padding: 5px; background-color: lemonchiffon; text-align: left; margin: 10px 0;

}

div.load {color: red; margin: 10px 0; font-weight: bold;} div.ajaxLink {margin-top: 10px;margin-right: 5px;float: left;}

...

Создание базовых ссылок и URL

Одной из самых основных задач в представлении является создание ссылок или URL, по которым пользователь может перейти в другую часть приложения. В предыдущих главах вы видели большую часть вспомогательных методов, которые можно использовать для создания ссылок и URL. И сейчас мы хотим воспользоваться моментом и напомнить их вам, прежде чем перейти к некоторым из более продвинутых вспомогательных методов. В таблице 21-1 описаны вспомогательные методы HTML и показаны примеры с ними.

Совет

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

Таблица 21-1: Вспомогательные методы HTML, которые отображают URL

Описание

Пример

URL относительно

Url.Content("~/Content/Site.css"); Выход: /Content/Site.css

приложения

Ссылка к именованному

Html.ActionLink("My Link", "Index", "Home"); Выход: <a

действию/контроллеру

href="/">My Link</a>

URL для действия

Url.Action("GetPeople", "People"); Выход: /People/GetPeople

URL с использованием

Url.RouteUrl(new {controller = "People", action="GetPeople"});

роутовых данных

Выход: /People/GetPeople

Ссылка с использованием

Html.RouteLink("My Link", new {controller = "People",

action="GetPeople"}); Выход: <a href="/People/GetPeople">My

роутовых данных

Link</a>

 

Ссылка к именованному

Html.RouteLink("My Link", "FormRoute", new {controller =

"People", action="GetPeople"}); Выход: <a

роуту

href="/app/forms/People/GetPeople">My Link</a>

 

Чтобы показать эти вспомогательные методы, мы создали файл представления /People/Index.cshtml, содержание которого вы можете увидеть в листинге 21-4.

533

Листинг 21-4: Содержание файла /People/Index.cshtml

@{

ViewBag.Title = "Index";

}

<h2>Basic Links & URLs</h2> <table>

<thead>

<tr>

<th>Helper</th>

<th>Output</th>

</tr>

</thead>

<tbody>

<tr>

<td>Url.Content("~/Content/Site.css")</td>

<td>@Url.Content("~/Content/Site.css")</td>

</tr>

<tr>

<td>Html.ActionLink("My Link", "Index", "Home")</td> <td>@Html.ActionLink("My Link", "Index", "Home")</td>

</tr>

<tr>

<td>Url.Action("GetPeople", "People")</td> <td>@Url.Action("GetPeople", "People")</td>

</tr>

<tr>

<td>Url.RouteUrl(new {controller = "People", action="GetPeople"})</td> <td>@Url.RouteUrl(new {controller = "People", action="GetPeople"})</td>

</tr>

<tr>

<td>Html.RouteLink("My Link", new {controller = "People", action="GetPeople"})</td>

<td>@Html.RouteLink("My Link", new {controller = "People", action="GetPeople"})</td>

</tr>

<tr>

<td>Html.RouteLink("My Link", "FormRoute", new {controller = "People", action="GetPeople"})</td>

<td>@Html.RouteLink("My Link", "FormRoute", new {controller = "People", action="GetPeople"})</td>

</tr>

</tbody>

</table>

Это представление содержит тот же набор вспомогательных вызовов, которые мы перечислили в таблице 21-1, и представляет результаты в HTML таблице, как показано на рисунке 21-1. Мы включили этот пример, потому что он позволяет легко экспериментировать с изменением маршрутизации и сразу видеть результат.

Рисунок 21-1: Использование вспомогательных методов для создания ссылок и URL

534

Использование в MVC "ненавязчивого"

(unobtrusive) Ajax

Ajax (часто упоминается как AJAX) является сокращением для Asynchronous JavaScript and XML. Как мы увидим, XML часть является не столь значительной, как это было раньше, но асинхронная часть делает Ajax полезным. Это модель для запроса данных с сервера в фоновом режиме, без перезагрузки веб-страницы.

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

Совет

Функция ненавязчивого Ajax в MVC основана на JQuery. Если вы знакомы с тем, как JQuery обрабатывает Ajax, тогда вы поймете эту особенность MVC очень быстро.

Создание синхронного представления в виде формы

Мы собираемся начать этот раздел с создания представление для действия GetPeople в нашем контроллере, то есть мы создали файл /Views/People/GetPeople.cshtml. Вы можете увидеть содержимое этого файла в листинге 21-5.

Листинг 21-5: Содержимое файла представления GetPeople.cshtml

@using HelperMethods.Models @model IEnumerable<person> @{

ViewBag.Title = "GetPeople";

}

<h2>Get People</h2> <table>

<thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead>

<tbody>

@foreach (Person p in Model) { <tr>

<td>@p.FirstName</td>

<td>@p.LastName</td>

<td>@p.Role</td>

</tr>

}

</tbody>

</table>

@using (Html.BeginForm()) { <div>

@Html.DropDownList("selectedRole", new SelectList( new [] {"All"}.Concat(Enum.GetNames(typeof(Role)))))

<button type="submit">Submit</button> </div>

}

Это строго типизированное представление, чьим типом модели является IEnumerable<Person>. Мы перечисляем объекты Person в модели для создания строк в HTML таблице и используем вспомогательный метод Html.BeginForm для создания простой формы, которая возвращается к действию и контроллеру, сгенерировавшим представление. Форма содержит вызов вспомогательного метода Html.DropDownList, который мы используем для создания элемента select, содержащего

535

элементы option для каждого из значений, определенных перечислением Role, плюс значение All. (Мы воспользовались LINQ для создания списка значений для элемента option путем объединения значений в enum с массивом, который содержит одну строку All).

Форма содержит кнопку для отправки формы. Результат заключается в том, что вы можете воспользоваться формой для фильтрации объектов Person, которые мы определили в контроллере в листинге 21-2, как показано на рисунке 21-2.

Рисунок 21-2: Простая синхронная форма

Это простая демонстрация фундаментального ограничения в HTML форме, которое заключается в том, что вся страница перезагружается при отправке формы. Это означает, что все содержимое вебстраницы должно быть заново сгенерировано и загружено с сервера (что может быть дорогостоящей операцией для сложных представлений). И в то время, как это происходит, пользователи не могут выполнять любые другие задачи с приложением. Они должны ждать, пока новая страница не сгенерируется, не загрузится, а затем отобразится в браузере.

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

Подготовка проекта для ненавязчивого Ajax

Функция ненавязчивого Ajax настроена в двух местах приложения. Во-первых, в файле /Web.config (одном из файлов в корневой папке проекта) элемент configuration/appSettings содержит запись для свойства UnobtrusiveJavaScriptEnabled, которое должно быть установлено на true, как показано в листинге 21-6. (Это свойство имеет значение true по умолчанию, когда Visual Studio создает проект).

536

Листинг 21-6: Включение ненавязчивого Ajax в файле Web.config

...

<configuration>

<!-- другие элементы опущены для краткости --> <appSettings>

<add key="webpages:Version" value="2.0.0.0" /> <add key="webpages:Enabled" value="false" /> <add key="PreserveLoginUrl" value="true" />

<add key="ClientValidationEnabled" value="true" /> <add key="UnobtrusiveJavaScriptEnabled" value="true" />

</appSettings>

<!-- другие элементы опущены для краткости --> </configuration>

...

В дополнение к проверке настойки в Web.config нам нужно добавить ссылки на JavaScript библиотеки jQuery, которые реализуют функциональность ненавязчивого Ajax. Вы можете ссылаться на эти библиотеки из отдельных представлений, но наиболее распространенным подходом является реализация этого в файле макета, поэтому он влияет на все представления, которые используют данный макет. В листинге 21-7, можно увидеть, как мы добавили ссылки на две библиотеки

JavaScript в файл /Views/Shared/_Layout.cshtml.

Листинг 21-7: Добавление ссылок для JavaScript библиотек ненавязчивого Ajax в файл _Layout.cshtml

<!DOCTYPE html> <html>

<head>

<meta charset="utf-8" />

<meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title>

<link href="~/Content/Site.css" rel="stylesheet" /> <style type="text/css">

label {

display: inline-block; width: 100px;

}

h2 > label { width: inherit;

}

.dataElem { margin: 5px;

}

.editor-label, .editor-field { float: left;

}

.editor-label, .editor-label label, .editor-field input { height: 20px;

}

.editor-label { clear: left;

}

.editor-field { margin-left: 10px; margin-top: 10px;

}

537

input[type=submit] { float: left; clear: both; margin-top: 10px;

}

.column { float: left; margin: 10px;

}

</style>

<script src="~/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script> <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"

type="text/javascript"></script>

</head>

<body>

@RenderBody()

</body>

</html>

Файлы, у которых есть ссылки на наши элементы script, добавляются Visual Studio в папку Scripts проекта, когда вы создаете новый MVC проект, используя шаблон Basic. Файл jquery- 1.7.1.min.js содержит базовую библиотеку JQuery, а файл jquery.unobtrusive-ajax.min.js

содержит функционал Ajax (который опирается на главную библиотеку JQuery). Расширение .min обозначает, что это ужатую версии библиотек, которые меньше, чем версии без расширения .min, но с которыми невозможна отладка. Мы, как правило, не используем .min версии при разработке, а затем переключаемся на них в финальной версии наших проектов.

Совет

JQuery является хорошо поддерживаемой библиотекой, и новые версии появляются часто. Поэтому проверяйте постоянно версии, чтобы знать, что вы используете последнюю. Мы будем использовать версии, которые пришли с первоначальным выпуском Visual Studio 2012, и когда мы писали эту книгу, JQuery 1.8.2 можно было получить на http://jquery.com.

Создание "ненавязчивой" Ajax формы

Теперь мы готовы начать применять ненавязчивого Ajax в нашем приложении, начиная с формы с ненавязчивым Ajax. В последующих разделах мы рассмотрим процесс замены обычных синхронных форм эквивалентным Ajax и объясним, как работает ненавязчивый Ajax.

Подготовка контроллера

Наша цель состоит в том, чтобы менялись только данные HTML элемента table, когда пользователь нажимает на кнопку Submit в нашем приложении. Это означает, что первое, что нам нужно сделать, это переделать методы действия в нашем контроллере People так, чтобы мы могли получить только те данные, которые нам нужны. Вы можете увидеть изменения, которые мы внесли в контроллер People, в листинге 21-8.

Листинг 21-8: Изменение методов действий в контроллере People

using System;

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

using System.Web;

538

using System.Web.Mvc;

using HelperMethods.Models; namespace HelperMethods.Controllers

{

public class PeopleController : Controller

{

private Person[] personData = {

new Person {FirstName = "Adam", LastName = "Freeman", Role = Role.Admin}, new Person {FirstName = "Steven", LastName = "Sanderson", Role = Role.Admin}, new Person {FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User}, new Person {FirstName = "John", LastName = "Smith", Role = Role.User},

new Person {FirstName = "Anne", LastName = "Jones", Role = Role.Guest} };

public ActionResult Index()

{

return View();

}

public PartialViewResult GetPeopleData(string selectedRole = "All")

{

IEnumerable<Person> data = personData; if (selectedRole != "All")

{

Role selected = (Role)Enum.Parse(typeof(Role), selectedRole); data = personData.Where(p => p.Role == selected);

}

return PartialView(data);

}

public ActionResult GetPeople(string selectedRole = "All")

{

return View((object)selectedRole);

}

}

}

Мы добавили действие GetPeopleData, оно выбирает объекты Person, которые нам нужно отобразить, и передает их методу PartialView для создания требуемых строк таблицы. Поскольку выборка данных обрабатывается методом действия GetPeopleData, мы можем сильно упростить метод действия GetPeople и полностью удалить версию HttpPost. Цель этого метода состоит в передаче выбранной роли в виде string в представление.

Мы создали новый файл частичного представления /Views/People/GetPeopleData.cshtml для нового метода действия GetPeopleData. Вы можете увидеть содержимое представления в листинге 21-9. Это представление отвечает за генерацию элементов tr, которые будут заполнять таблицу, используя перечисление объектов Person, которые передаются от метода действия.

Листинг 21-9: Создание представления GetPeopleData.cshtml

@using HelperMethods.Models @model IEnumerable<Person> @foreach (Person p in Model) {

<tr>

<td>@p.FirstName</td>

<td>@p.LastName</td>

<td>@p.Role</td>

</tr>

}

Мы также должны обновить представление /Views/People/GetPeople.cshtml, которое вы можете увидеть в листинге 21-10.

Листинг 21-10: Обновление представления GetPeople.cshtml

539

@using HelperMethods.Models

@model string

@{

ViewBag.Title = "GetPeople";

}

<h2>Get People</h2> <table>

<thead>

<tr>

<th>First</th>

<th>Last</th>

<th>Role</th>

</tr>

</thead>

<tbody>

@Html.Action("GetPeopleData", new {selectedRole = Model })

</tbody>

</table>

@using (Html.BeginForm()) { <div>

@Html.DropDownList("selectedRole", new SelectList( new [] {"All"}.Concat(Enum.GetNames(typeof(Role)))))

<button type="submit">Submit</button> </div>

}

Мы изменили тип модели представления на string, который мы передаем вспомогательному методу Html.Action для вызова дочернего действия GetPeopleData. Это рендерит частичное представление и дает нам строки таблицы.

Создание Ajax формы

У нас после этих изменений еще есть синхронная форма в приложении, но мы выделили функциональность контроллера таким образом, мы можем запрашивать только строки таблицы через действие GetPeopleData. Этот новый метод действия будет целью нашего Ajax запроса, и следующим шагом является обновление представления GetPeople.cshtml, таким образом, чтобы работа с формой осуществлялась через Ajax, как показано в листинге 21-11.

Листинг 21-11: Создание ненавязчивой Ajax формы в представлении GetPeople.cshtml

@using HelperMethods.Models @model string

@{

ViewBag.Title = "GetPeople";

AjaxOptions ajaxOpts = new AjaxOptions { UpdateTargetId = "tableBody"

};

}

<h2>Get People</h2> <table>

<thead>

<tr>

<th>First</th>

<th>Last</th>

<th>Role</th>

</tr>

</thead>

<tbody id="tableBody">

@Html.Action("GetPeopleData", new {selectedRole = Model }) </tbody>

</table>

@using (Ajax.BeginForm("GetPeopleData", ajaxOpts)) {

540

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