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

107

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

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

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

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

Наиболее часто используемые объекты контекста и свойства описаны в таблице ниже:

Часто используемые объекты контекста ControllerContext и свойства
Свойство Тип Описание
Request.QueryString NameValueCollection

Переменные GET, отправленные с этим запросом

Request.Form NameValueCollection

Переменные POST, отправленные с этим запросом

Request.Cookies HttpCookieCollection

Cookie-наборы, отправленные браузером с этим запросом

Request.HttpMethod string

Метод HTTP (команда наподобие GET или POST), используемый для этого запроса

Request.Headers NameValueCollection

Полный набор заголовков HTTP, отправленных с этим запросом

Request.Url Uri

Элемент RouteTable.Routes, выбранный для этого запроса

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

Временные элементы данных, сохраненные для текущего пользователя

Отдельные свойства, которые здесь упоминались - Request, HttpContext и т.д. - предоставляют объекты контекста. Здесь они подробно не рассматриваются (поскольку являются частью платформы ASP.NET), но следует знать, что такие объекты предоставляют доступ к полезной информации и средствам, и более подробно вы можете прочитать о них в разделе, посвященном ASP.NET Web Forms.

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

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

namespace ControllersAndActions.Controllers
{
    public class DerivedController : Controller
    {
        public ActionResult Index()
        {
            // ...
        }

        public ActionResult ActionMethod()
        {
            // Получить доступ к разнообразным свойствам из объектов контекста
            string userName = User.Identity.Name;
            string serverName = Server.MachineName;
            string clientIP = Request.UserHostAddress;
            DateTime dateStamp = HttpContext.Timestamp;

            // Извлечь отправленные данные из Request.Form 
            string oldProductName = Request.Form["OldName"]; 
            string newProductName = Request.Form["NewName"];

            // ...

            return View();
        }
    }
}

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

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

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

// ...
public ActionResult WeatherForecast()
{
    string city = (string)RouteData.Values["city"];
    DateTime forDate = DateTime.Parse(Request.Form["forDate"]);

    // реализовать прогноз погоды

    return View();
}
// ...

Его можно переписать так, чтобы в нем применялись параметры:

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

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

Полезно отметить, что методы действий не допускают применения параметров out или ref. Их использование не имеет никакого смысла; встретив такой параметр, MVC Framework сгенерирует исключение.

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

Создание объектов параметров

Базовый класс Controller получает значения для параметров методов действий с использованием компонентов MVC Framework, называемых поставщиками значений и связывателями моделей. Поставщики значений представляют набор элементов данных, доступных контроллеру. Существуют встроенные поставщики значений, которые производят выборку элементов из Request.Form, Request.QueryString, Request.Files и RouteData.Values. Эти значения затем передаются связывателям моделей, которые пытаются отобразить их на типы параметров, принимаемых методами действий.

Стандартные связыватели моделей могут создавать и заполнять объекты любого типа .NET, включая коллекции и специальные типы, специфичные для проектов. Соответствующий пример приводился в статье Админ панель: редактирование товаров, в котором отправляемая администратором форма была представлена методу действия как одиночный объект Game, несмотря на то, что индивидуальные значения были разбросаны по элементам HTML-формы.

Обязательные и необязательные параметры

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

Указание стандартных значений для параметров

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

// ...
public ActionResult WeatherForecast(DateTime forDate, string city = "Москва",
    int page = 1)
{
    // реализовать прогноз погоды
    return View();
}
// ...

Чтобы пометить параметр как необязательный, необходимо при определении присвоить ему значение. В примере были предоставлены стандартные значения для параметров city и page. Инфраструктура MVC Framework попытается получить значения для этих параметров из запроса, но если окажется, что значения не доступны, будут использоваться стандартные значения.

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

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

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

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

Пройди тесты
Лучший чат для C# программистов