Главная страница   /   22.4. Вызов модели связывания данных вручную (ASP.NET MVC 4

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

22.4. Вызов модели связывания данных вручную

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

Листинг 22-28: Запускаем процесс связывания данных вручную в методе действия Address
public ActionResult Address()
{
	IList<AddressSummary> addresses = new List<AddressSummary>();
	UpdateModel(addresses);
	return View(addresses);
}

Метод UpdateModel принимает объект модели, который мы ранее определили в качестве его параметра, и пытается извлечь значения из его открытых свойств, запуская стандартный процесс связывания.

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

Листинг 22-29: Ограничиваем поиск механизма связывания данными формы
public ActionResult Address()
{
	IList<AddressSummary> addresses = new List<AddressSummary>();
	UpdateModel(addresses, new FormValueProvider(ControllerContext));
	return View(addresses);
}

Эта версия метода UpdateModel принимает реализацию интерфейса IValueProvider, который становится единственным источником значений данных для процесса связывания. Для каждого из четырех адресов данных по умолчанию есть реализация IValueProvider, как показано в таблице 22-2.

Таблица 22-2: Встроенные реализации IValueProvider
Адрес Реализация IValueProvider
Request.Form FormValueProvider
RouteData.Values RouteDataValueProvider
Request.QueryString QueryStringValueProvider
Request.Files HttpFileCollectionValueProvider

Каждый из классов, перечисленных в таблице 22-2, принимает параметр конструктора ControllerContext, который мы получаем через свойство ControllerContext, определенное в классе Controller, как показано в листинге.

Наиболее распространенный способ ограничить источники данных – это проверять только значения формы. Существует удобная техника связывания, которая не требует создавать экземпляр FormValueProvider, как показано в листинге 22-30.

Листинг 22-30: Ограничиваем источники данных для механизма связывания
public ActionResult Address(FormCollection formData)
{
	IList<AddressSummary> addresses = new List<AddressSummary>();
	UpdateModel(addresses, formData);
	return View(addresses);
}

Класс FormCollection реализует интерфейс IValueProvider, и если мы определяем метод действия, который принимает параметр этого типа, механизм связывания создаст объект, который мы сможем передать непосредственно в метод UpdateModel.

Подсказка

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

Работаем с ошибками связывания

Пользователи неизбежно будут отправлять значения, которые не могут быть связаны с соответствующими свойствами модели – например, недействительные даты или текст для числовых значений. При явном вызове процесса связывания мы берем на себя ответственность за обработку таких ошибок. Механизм связывания генерирует для ошибок связывания исключение InvalidOperationException. Подробности ошибки можно узнать с помощью функции ModelState, которую мы опишем в главе 23. Но при использовании метода UpdateModel, мы должны быть готовы поймать исключение и создать сообщение об ошибке для пользователя с помощью ModelState, как показано в листинге 22-31.

Листинг 22-31: Работаем с ошибками связывания данных
public ActionResult Address(FormCollection formData)
{
	IList<AddressSummary> addresses = new List<AddressSummary>();
	try
	{
		UpdateModel(addresses, formData);
	}
	catch (InvalidOperationException ex)
	{
		// provide feedback to user
	}
	return View(addresses);
}

В качестве альтернативного подхода, можно использовать метод TryUpdateModel, который возвращает true, если процесс связывания прошел успешно, и false, если возникли ошибки, как показано в листинге 22-32.

Листинг 22-32: Используем метод TryUpdateModel
public ActionResult Address(FormCollection formData)
{
	IList<AddressSummary> addresses = new List<AddressSummary>();
	if (TryUpdateModel(addresses, formData))
	{
		// proceed as normal
	}
	else
	{
		// provide feedback to user
	}
	return View(addresses);
}

Единственное преимущество метода TryUpdateModel над UpdateModel в том, что вам не нужно будет ловить исключения и обрабатывать их. Функциональных различий в процессе связывания нет.

Подсказка

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