ASP.NET MVC и проблема с ValidationSummary

При использовании фреймворка ASP.NET MVC, есть возможность использования серверной и клиентской валидации при помощи атрибутов из пространства
имен DataAnnotations.

Для отображения ошибок полей ввода, можно воспользоваться расширениями для отображения сообщений об ошибках, входящими в фреймворк ASP.NET MVC:

Html.ValidationMessage
Html.ValidationMessageFor
Html.ValidationSummary

Расширения Html.ValidationMessage и Html.ValidationMessageFor, предназначены для отображения ошибок ввода для конкретного поля, а Html.ValidationSummary — отображает все ошибки, как относящиеся к полям, так и добавленные в словарь ModelState вручную из контроллера.

У расширения Html.ValidationSummary имеется булевый атрибут, который управляет отображением ошибок, при значении true будут исключены ошибки полей и отображены только ошибки модели, а при значении false (оно включено по умолчанию) будут показаны и ошибки полей и ошибки модели.

При использовании нижеприведенного кода для своего приложения, я столкнулся с одной странностью. При возникновении исключения в строке:

MembersManager.RegisterMember(member);

в секции catch добавляется ошибка в словарь ModelState, следующим образом:

ModelState.AddModelError("error", ex.Message);

и возвращается представление (View), в котором будет содержаться ошибка модели, которую хотелось бы отобразить в ValidationSummary. То есть, мне хотелось вывести только эту ошибку исключив отображение ошибок полей.

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

Модель (Model):

public class Member
{
    [Required(ErrorMessage = "*")]
    [DisplayName("Login:")]
    public string Login { get; set; }

    [Required(ErrorMessage = "*")]
    [DataType(DataType.Password)]
    [DisplayName("Password:")]
    public string Password { get; set; }
    [Required(ErrorMessage = "*")]
    [DataType(DataType.Password)]
    [DisplayName("Confirm Password:")]
    public string ConfirmPassword { get; set; }
}

Контроллер (Controller):

[HttpPost]
public ActionResult Register(Member member)
{
    try
    {
        if (!ModelState.IsValid)
            return View();

        MembersManager.RegisterMember(member);
    }
    catch (Exception ex)
    {
        ModelState.AddModelError("error", ex.Message);
        return View(member);
    }
}

Представление (View):

<% using (Html.BeginForm("Register", "Members", FormMethod.Post, new { enctype = "multipart/form-data" })) {%>

    <p>
        <%= Html.LabelFor(model => model.Login)%>
        <%= Html.TextBoxFor(model => model.Login)%>
        <%= Html.ValidationMessageFor(model => model.Login)%>
    </p>

    <p>
        <%= Html.LabelFor(model => model.Password)%>
        <%= Html.PasswordFor(model => model.Password)%>
        <%= Html.ValidationMessageFor(model => model.Password)%>
    </p>

    <p>
        <%= Html.LabelFor(model => model.ConfirmPassword)%>
        <%= Html.PasswordFor(model => model.ConfirmPassword)%>
        <%= Html.ValidationMessageFor(model => model.ConfirmPassword)%>
    </p>

    <div>
        <input type="submit" value="Create" />
    </div>

    <%= Html.ValidationSummary(true)%>
<% } %>

После длительного поиска на просторах интернет и изучения исходных кодов фреймворка ASP.NET MVC, было найдено решение, которое оказалось до жути банальным.

Как выяснилось ValidationSummary, ищет ошибки модели, которые привязаны к полям (в качестве ключа словаря ModelState передаются имена полей). Поэтому достаточно было в качестве ключа, при добавлении ошибки в ModelState, передать пустую строку

ModelState.AddModelError(String.Empty, ex.Message);

и все стало работать именно так, как и задумывалось :).

P.S. При использовании классов LINQ To SQL, может возникнуть необходимость пробежаться по набору EntitySet при помощи цикла foreach, но тут может возникнуть ошибка приведения типов. По ссылке можно увидеть решение данной проблемы.


А вы знаете как заработать деньги в интернете — заходите, расскажем.


Категории: ASP.NET MVC  Теги: ,
  1. Трэкбеков пока нет.
  1. Андрей
    15 мая 2010 14:13 | №1

    Вообще-то проще во View писать Html.ValidationMessage («Login») (вместо ValidationMessageFor) — view сам подставит действующую модель и ее поле, для остальных так же актуально...

  2. 15 мая 2010 14:26 | №2

    С точки зрения скорости написания текста, то может ты и прав, хотя при использовании инструментов IntelliSense и набор текста будет быстрым. А вот с точки зрения логичноссти и правильности, я с тобой не соглашусь. При использовании твоего варианта, в случае изменения названия свойства в модели, во скольких местах придется тебе править названия, которые у тебя обычной строкой переданы? А при использовании моего способа, сработает рефакторинг и все поменяется автоматом.

:D :) ^_^ :( :o 8) ;-( :lol: xD :wink: :evil: :p :whistle: :woot: :sleep: =] :sick: :straight: :ninja: :love: :kiss: :angel: :bandit: :alien: