Главная страница   /   15.2. Получение входных данных (ASP.NET MVC 4

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

15.2. Получение входных данных

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

  • Получить их из набора контекстных объектов
  • Получить данные, переданные в качестве параметров методу действия
  • Явно вызвать связывание данных модели

Здесь мы рассмотрим подходы получения входных данных для методов действия, уделяя особое внимание использованию контекстных объектов и параметров метода действия. В главе 22 мы подробно изучим связывание данных модели.

Получение данных из контекстных объектов

Самый прямой способ получить данные заключается в том, чтобы извлечь их самостоятельно. Когда вы создаете контроллер путем наследования от базового класса Controller, вы получаете доступ к набору полезных свойств для получения информации о запросе. Эти свойства включают Request, Response, RouteData, HttpContext и Server. Каждое из них предоставляет информацию о различных аспектах запроса. Эти свойства получают различные типы данных из экземпляра запроса ControllerContext (который может быть доступным через свойство Controller.ControllerContext). Мы описали некоторые из наиболее часто используемых контекстных объектов в таблице 15-1.

Таблица 15-1: Наиболее часто используемые контекстные объекты
Свойство Тип Описание
Request.QueryString NameValueCollection Переменные GET, отправленные с этим запросом
Request.Form NameValueCollection Переменные POST, отправленные с этим запросом
Request.Cookies HttpCookieCollection Куки, отправленные браузером с этим запросом
Request.HttpMethod string HTTP метод (например, GET или POST), используемый для этого запроса
Request.Headers NameValueCollection Полный набор HTTP заголовков, отправленный с этим запросом
Request.Url Uri Запрашиваемый URL
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 Информация о временных данных текущего пользователя

Метод действия может использовать любой из этих контекстных объектов, чтобы получить информацию о запросе, как показано в листинге 15-5, который демонстрирует гипотетический метод действия.

Листинг 15-5: Метод действия использует контекстные объекты, чтобы получить информацию о запросе
public ActionResult RenameProduct() {
	// Доступ к различным свойствам контекстных объектов
	string userName = User.Identity.Name;
	string serverName = Server.MachineName;
	string clientIP = Request.UserHostAddress;
	DateTime dateStamp = HttpContext.Timestamp;
	AuditRequest(userName, serverName, clientIP, dateStamp, "Renaming product");
	// Получение данных из Request.Form
	string oldProductName = Request.Form["OldName"];
	string newProductName = Request.Form["NewName"];
	bool result = AttemptProductRename(oldProductName, newProductName);
	ViewData["RenameResult"] = result;
	return View("ProductRenamed");
}

Вы можете просмотреть широкий спектр доступной контекстной информации о запросе при помощи IntelliSense (в методе действия наберите this. и просмотрите информацию во всплывающем окне) и Microsoft Developer Network (посмотрите System.Web.Mvc.Controller и его базовые классы или System.Web.Mvc.ControllerContext).

Использование параметров метода действия

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

...
public ActionResult ShowWeatherForecast() {
	string city = (string)RouteData.Values["city"];
	DateTime forDate = DateTime.Parse(Request.Form["forDate"]);
	// ... здесь идет реализация прогноза погоды ...
	return View();
}
...

Мы можем переписать его, чтобы использовать параметры:

...
public ActionResult ShowWeatherForecast(string city, DateTime forDate) {
	// ... здесь идет реализация прогноза погоды ...
	return View();
}

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

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

MVC фреймворк предоставит значения для наших параметров, проверив контекстные объекты, в том числе Request.QueryString, Request.Form и RouteData.Values. Имена наших параметров рассматриваются как регистронезависимые, так что параметр метода действия city можно заполнить значением из Request.Form["City"].

Понимание того, как создаются экземпляры объектов параметров

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

Провайдеры значений представляют собой совокупность элементов данных, доступных для вашего контроллера. Есть встроенные провайдеры значений, которые получают элементы из Request.Form, Request.QueryString, Request.Files и RouteData.Values. Затем значения передаются механизмам связывания данных, которые пытаются привязать их к типам, которые методы действий требуют в качестве параметров.

Дефолтовые механизмы связывания данных могут создать и заполнить объекты любого .NET типа, в том числе коллекции и специфические пользовательские типы для конкретного проекта. Вы видели пример этого в главе 10, когда сообщения от администраторов были представлены нашему методу действия как один объект Product, даже при том что отдельные значения были рассеяны среди элементов HTML формы. Мы расскажем о провайдерах значений и механизмах связывания данных модели в главе 22.

Понимание факультативных и обязательных параметров

Если MVC фреймворк не может найти значение параметра ссылочного типа (например, string или object), все равно будет вызван метод действия, но с использованием значения null для этого параметра. Если значение не может быть найдено для параметра простого типа (например, int или double), то будет сгенерировано исключение, и метод действия не будет вызван. Вот почему это так:

  • Параметры простого типа являются обязательными. Чтобы сделать их необязательными, либо укажите значение по умолчанию (см. следующий раздел), либо замените тип параметра на nullable (например, int? или DateTime?). Таким образом, MVC сможет передать null, если значение будет не доступно.
  • Параметры ссылочного типа не являются обязательными. Чтобы сделать их обязательными (чтобы убедиться, что передается значение не-null), добавьте код в начало метода действия, который не принимает значения null. Например, если значение равно null, выбрасывается исключение ArgumentNullException.

Указание значений параметров по умолчанию

Если вы хотите обрабатывать запросы, которые не содержат значений для параметров метода действия, но вы не хотите проверять в коде наличие значений null или выбрасывать исключения, вы можете использовать дополнительные параметры C#. В листинге 15-6 показан пример.

Листинг 15-6: Использование дополнительных параметров C# для метода действия
...
public ActionResult Search(string query= "all", int page = 1) {
	// ...обработка запроса...
	return View();
}
...

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

Для параметра string query, это означает, что нам не нужно проверять наличие значений null. Если в запросе, который мы обрабатываем, не задана строка запроса, тогда наш метод действия будет вызван со строкой all. Для параметра int нам не нужно беспокоиться о том, что запросы завершатся ошибками, если нет значения page. Наш метод действия будет вызываться со значением по умолчанию равным 1.

Необязательные параметры могут быть использованы для литеральных типов: это типы, которые можно определить без использования ключевого слова new, включая string, int и double.

Внимание

Если запрос содержит значение для параметра, но оно не может быть преобразовано в правильный тип (например, если пользователь дает нечисловую строку для параметра int), то фреймворк передаст значение по умолчанию для этого типа параметра (например, 0 для параметра int) и зарегистрирует предоставленное значение как ошибку валидации в специальном контекстном объекте ModelState. Если вы не проверите ошибки валидации в ModelState, вы можете попасть в неприятную ситуацию, когда пользователь ввел неправильные данные в форму, но запрос обрабатывается, как если бы пользователь не ввел никаких данных вообще или ввел значение по умолчанию. См. главу 23 для информации о валидации и ModelState, который может быть использован, чтобы избежать таких проблем.