В прошлой части были возвращены исходные значения для параметров ClientValidationEnabled и UnobtrusiveJavaScriptEnabled. Теперь предварительная проверка условий для стандартных атрибутов производится на стороне клиента. Продолжим начатое и дополним ее аналогами созданных атрибутов.
Проверка на стороне клиента реализуется при помощи отдельного программного кода, как правило написанного на языке JavaScript. Она реализует те же правила, но при этом нет требования обязательно полностью повторять серверный вариант.
Вполне логично возникает вопрос о синхронизации параметров проверки данных. Конечно их можно каждый раз задавать вручную в C# и соответствующем JavaScript. Но это усложнит сопровождение проекта. Кроме того, есть вероятность ошибочного указания различных значений.
На помощь приходит ядро ASP.NET MVC 3. Оно предоставляет механизм, который обеспечивает передачу значений параметров от атрибутов проверки данных к JavaScript коду на стороне клиента.
Реализация поддержки проверки на стороне клиента для [Equal]
Интерфейс для атрибутов
Для пересылки своих параметров в JavaScript код атрибут должен поддерживать интерфейс IClientValidatable, определенный в пространстве имен System.Web.Mvc. При это необходимо реализовать всего лишь один метод GetClientValidationRules(), который возвращает перечень правил. Каждое правило включает список значений для настройки функции проверки и соответствующего сообщения об ошибке.
Откроем исходный код класса EqualAttribute и добавим поддержку указанного интерфейса. С помощью редактора Visual Studio создадим заготовку его метода и добавим в неё следующий код:
namespace MVCDemo.Attributes.Validation
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class EqualAttribute : ValidationAttribute, IClientValidatable
{
private readonly object _valueToCompare;
.........
#region IClientValidatable Members
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule() {
ErrorMessage = this.FormatErrorMessage(metadata.DisplayName),
ValidationType = "equal"
};
rule.ValidationParameters.Add("valuetocompare", this._valueToCompare);
yield return rule;
}
#endregion
}
}
Теперь подробно рассмотрим реализацию метода GetClientValidationRules().
Первый параметр данный метод содержит метаданные свойства, для которого назначен атрибут. В частности, из него можно получить отображаемое имя свойства, которое будет использовано для создания текста сообщения об ошибке. Вторым параметром является контекст Контроллера, включающий его данные и значения из исходного запроса.
Поскольку в данном случае только одно правило, то создается перечисление из единственного экземпляра ModelClientValidationRule. В нем сохраняются:
- ErrorMessage – сообщение об ошибке.
- ValidationType – уникальное имя данного правила (запомним его, т.к. оно не раз будет использовано в клие��тском коде).
- ValidationParameters – коллекция пар "ключ-значение", в которой сохраняются необходимые для передачи в JavaScript параметры (имена ключей также потребуются в коде на JavaScript).
Таким образом, в результате вызова данной реализации GetClientValidationRules() будет создано правило "equal", содержащее значение для сравнения "valuetocompare" и строку с текстом сообщения об ошибке.
Каркас ASP.NET MVC 3 сохранит эти значения в HTML теге соответствующего поля в следующем виде:
<input name="AgreementAccepted" class="check-box"
id="AgreementAccepted" type="checkbox"
data-val="true"
data-val-required="The I have read the EULA and I agree with it field is required."
data-val-equal-valuetocompare="True"
data-val-equal="You must agree with the EULA."
value="true"/>
Обратите внимание, имя правила используется для создания названий атрибутов HTML тегов. Сообщение об ошибке при этом располагается в "data-val-[имя-правила]", а значения параметров в "data-val-[имя-правила]-[ключ]". Кроме того, в именах правил и названиях ключей можно использовать только строчные буквы без пробелов и других символов.
Создаем JavaScript с алгоритмом проверки
Все готово для того, чтобы программа на JavaScript смогла получить данные и передать их в функцию проверки. Но перед тем как продолжить, давайте выберем место хранения для файлов кодом проверок на JavaScript. Для этого в папке Scripts создадим папку Validation. Кроме того, называть все создаваемые файлы будем по аналогии с файлами, содержащими исходный код атрибутов.
Чтобы в очередной раз не изобретать колесо, ядро ASP.NET MVC 3 использует библиотеку jQuery для клиентской части веб-приложения. С её помощью реализован функционал проверки в браузере свойств, отмеченных стандартными атрибутами. Не будем углубляться в тонкости её работы и рассмотрим только необходимые для решаемой задачи детали.
Проверка данных на стороне клиента выполняется дополнением jQuery Validation plugin. Его работа сводится к следующему: при изменении поля необходимо вызвать функцию проверки значения и, в случае ошибки, вывести текст полученного сообщение на соответствующе место страницы. Данный механизм доступен через объект jQuery.validator. Используя его функцию addMethod() необходимо добавить новое правило проверки в их список.
В результате, в папке Scripts\Validation создадим файл EqualAttribute.js, содержащий следующий код:
/// <reference path="../jquery-1.4.4-vsdoc.js" />
/// <reference path="../jquery.validate-vsdoc.js" />
/// <reference path="../jquery.validate.unobtrusive.js" />
jQuery.validator.addMethod("equal", function (value, element, param) {
if ($(element).attr("type") == "checkbox") {
value = String($(element).attr("checked"));
param = param.toLowerCase();
}
return (value == param);
});
jQuery.validator.unobtrusive.adapters.addSingleVal("equal", "valuetocompare");
Первые три строчки с комментариями необходимы только поддержки IntelliSense и указывают на используемые файлы с описаниями функций.
Затем, с помощью вызова addMethod(), в список проверок добавляется новое правило. Обратите внимание, что указывается тоже самое имя, которое было задано в атрибуте. Это обязательно, за исключением случаев, когда правило содержит не более одного параметра. Причина этого заключена в адаптерах и будет рассмотрена в следующей части.
Последним параметром addMethod() является функция, ответственная за проверку значения. При вызове она получает три параметра:
- value – текущее значение поля ввода;
- element – элемент страницы;
- param – список параметров, переданный атрибутом проверки данных.
Код созданной функции проверки сравнивает введенное значение с заданным в param. Данная реализация учитывает особенность объектов представляющих checkbox, которые содержат значение не в HTML атрибуте value, а в checked. Метод при успешной проверке возвращает true, в противном случае – false.
jQuery Validation обработает значение, полученное от функции проверки. Если оно будет равно false, то на месте блока <span>, созданного методом ValidationMessageFor() и отмеченного при этом специальным HTML атрибутом, будет выведен текст сообщения об ошибке. Оно будет убрано в дальнейшем, после успешного прохождения проверки.
Остается разобрать еще одну, последнюю, строчку из созданного JavaScript кода.
Адаптер для jQuery Validate
Рассматривая код функции проверки может возникнуть вопрос: а откуда возьмётся значение для сравнения в переменой param? Логично предположить, что оно будет передано из jQuery Validation. Но откуда тогда сама библиотека возьмет это значение и текст сообщения об ошибке?
Для этой цели существуют адаптеры, которые считывают значения из атрибутов HTML тегов и передают их в jQuery.validator. Они располагаются в объекте jQuery.validator.unobtrusive.adapters и являются дополнением для jQuery Validation, созданным разработчиками ASP.NET MVC 3.
Посмотрим еще раз на последнюю строку созданного JavaScript:
jQuery.validator.unobtrusive.adapters.addSingleVal("equal", "valuetocompare");
Метод addSingleVal() используется для адаптации правил с одним значением. Имя адаптера указано в качестве первого и совпадает с именем правила. Затем следует название параметра (ключ из заданной в C# коде пары), значение которого будет передано как переменная param в созданную выше функцию.
Разумеется, не все правила используют только одно значение. Существуют другие вариант добавления адаптеров, которые будет рассмотрены в следующей части.
Подключение JavaScript в Представление
Остался один небольшой шаг: необходимо подключить созданный JavaScript на страницу создания профиля. Это можно сделать вручную добавив соответствующую строку в Представление UserProfiles\Create. Или же перетащить в него файл EqualAttribute.js из окна Solution Navigator (Solution Explorer). Для указания пути воспользуемся вызовом метода Url.Content(). Результат будет следующим:
@model MVCDemo.Models.NewUserProfileModel
@using MVCDemo.Resources.Views.UserProfiles;
@{
ViewBag.Title = CreateRes.PageTitle;
}
<h2>@ViewBag.Title</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/Validation/EqualAttribute.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
.........
Теперь можно запустить веб-приложение посмотреть на новую функциональность в работе. Приступим к разработке аналогичной поддержки проверки на стороне клиента и для оставшегося атрибута.
Проверка на стороне клиента для атрибута [StringLengthRange]
Реализация атрибута пойдет по знакомому уже плану, но в этот раз без создания адаптера.
Добавим классу StringLengthRangeAttribute поддержку интерфейса IClientValidatable. Здесь необходимо отметить, что jQuery Validation уже содержит набор часто используемых правил. Для их использования в ASP.NET MVC 3 существуют специальные версии классы, наследники ModelClientValidationRule().
namespace MVCDemo.Attributes.Validation
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class StringLengthRangeAttribute : ValidationAttribute, IClientValidatable
{
private readonly int _minLength;
private readonly int _maxLength;
.........
#region IClientValidatable Members
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationStringLengthRule(
this.FormatErrorMessage(metadata.DisplayName),
this._minLength,
this._maxLength);
}
#endregion
}
}
В данном случае нет необходимости в создании клиентской части на JavaScript и добавлении ссылки на неё в Представление. Использование ModelClientValidationStringLengthRule() позволяет использовать уже готовые адаптер и реализацию алгоритма проверки длины строки.
Стоит отметить, что использование готовых правил позволяет избежать их двойного применения к объекту. Дело в том, что атрибуты с одинаковыми стандартными правилами будут использовать их одинаковые имена. А это привет к ошибке в момент обращения к Представлению на этапе выполнения.
Классы ASP.NET MVC для стандартных правил
- ModelClientValidationEqualToRule – устанавливает равенство значений текущего и указанного поля.
- ModelClientValidationRangeRule – определяет минимальное и максимальное значения свойства.
- ModelClientValidationRegexRule – проверяет значение на соответствие регулярному выражению. Используется стандартным атрибутом [RegularExpression].
- ModelClientValidationRemoteRule – используется для удаленной проверки данных. Используется стандартным ASP.MET MVC 3 атрибутом [Remote].
- ModelClientValidationRequiredRule – указывает что данное поле обязательно к заполнению. Используется стандартным атрибутом [Required].
- ModelClientValidationStringLengthRule – ограничивает длину заданной строки.
Осталась только одна проверка, выполняемая только на сервере. Это тест на уникальность выбранного имени входа на сайт. И опять для данного значения будет использован свой подход. Но перед тем как приступить к реализации, посмотрим на стандартные адаптеры ASP.NET MVC 3 для jQuery Validation.
Исходный код проекта (C#, Visual Studio 2010):
MVCDemo-Part12.zip (477 Kb)