Индикаторы корректности введенных данных

Пользователям свойственно ошибаться при вводе данных, и приложению необходимо уведомлять пользователя о допущенных ошибках и конкретных полях формы, которые заполнены некорректно. Для этого существуют два вспомогательных метода: Html.validationMessage(), который выводит сообщение, относящееся к определенному полю на форме, и Html.validationSummary (), который выводит общую информацию по ошибкам, допущенным при заполнении формы.

Работа этих вспомогательных методов основана на коллекции ModelState, которая упоминалась ранее. В этой коллекции на этапе проверки корректности данных сохраняется информация об ошибках, связанных с конкретными полями формы. Пример действия контроллера, выполняющего проверку корректности введенных данных (валидацию), приведен в листинге 5.7.

Листинг 5.7. Пример валидации данных

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Edit(Product obj, int id)

{

  if (obj.UnitsOnOrder < 0)

    ModelState.AddModelError("UnitsOnOrder",

         "Количество заказанных единиц товара не может

          быть отрицательным.");

  if (obj.UnitsInStock < 0)

    ModelState.AddModelError("UnitsInStock",

          "Количество единиц товара на складе должно быть не

          отрицательным.");

  if (obj.UnitPrice <= 0)

    ModelState.AddModelError("UnitPrice",

          "Цена должна быть больше нуля.");

  if (!ModelState.IsValid)

  {

    // есть ошибки, еще раз

    // показать форму редактирования

    return View(obj);

  }

  else

  {

    // ошибок нет, сохранить

    db.SaveProduct(obj);

    return RedirectToAction("Index");

  }

}

Процесс валидации прост — выполняется проверка условий и в случае наличия ошибок в коллекцию Modelstate добавляется информация в виде пары "идентификатор элемента — описание допущенной ошибки". Если в коллекцию Modelstate добавлена хотя бы одна такая пара, то значение свойства Modelstate.isValid будет установлено в false. В случае если ошибки допущены, то необходимо снова отобразить то же представление, которое использовалось для радактирования данных, и передать ему те данные, которые были введены пользователем на предыдущем шаге. Пример такого представления, работающего с кодом, описанным в листинге 5.7, показан в листинге 5.8, там же приведено строго типизированное представление, в качестве модели использующее класс Product.

Листинг 5.8. Представление Edit.aspx

<%@ Page Title="" Language="C#"

        MasterPageFile="~/Views/Shared/Site.Master"

        Inherits="System.Web.Mvc.ViewPage<MvcViewsDemo.Models.Product>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent"

                    runat="server">

  Edit

</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

  <h2>

    Редактирование сведений о товаре

  </h2>

  <%= Html.ValidationSummary("npи редактировании сведений

                    о товаре произошли ошибки.") %>

  <% using (Html.BeginForm())

  {%>

    <fieldset>

      <legend>Редактирование сведений о товаре</legend>

      <p>

        <label for="ProductID">

          Код продукта:

        </1аЬе1>

        <%= Model.ProductID.ToString() %>

        <%= Html.Hidden("ProductId", Model.ProductID)%>

      </p>

      <p>

        <label for="ProductName">

          Название:

        </label>

        <%= Html.TextBox("ProductName", Model.ProductName) %>

        <%= Html.ValidationMessage("ProductName", "*") %>

      </p>

      <p>

        <label for="UnitPrice">

          Цена:

        </label>

        <%= Html.TextBox("UnitPrice",

               String.Format("{0:F}", Model.UnitPrice)) %>

        <%= Html.ValidationMessage("UnitPrice", "*") %>

      </p>

      <p>

        <label for="UnitsInStock">

          На складе:

        </label>

        <%= Html.TextBox("UnitsInStock", Model.UnitsInStock) %>

        <%= Html.ValidationMessage("UnitsInStock", "*") %>

      </p>

      <p>

        <label for="UnitsOnOrder">

          Заказано:

        </label>

        <%= Html.TextBox("UnitsOnOrder", Model.UnitsOnOrder) %>

        <%= Html.ValidationMessage("UnitsOnOrder", "*") %>

      </p>

      <p>

        <input type="submit" value="Save" />

      </p>

    </fieldset>

  <% } %>

  <div>

    <%=Html.ActionLink("K списку товаров", "Index") %>

  </div>

</asp:Content>

В листинге 5.8 методы Html.ValidationMessage() вызываются co вторым строковым параметром, указывающим сообщение, которое должно быть отображено пользователю в случае наличия ошибки в коллекции ModelState. В результате форма, заполненная с ошибками, будет выглядеть так, как показано на рис. 5.2.

Для того чтобы сообщение об ошибке было выведено непосредственно в месте вызова метода Html.ValidationMessage(), метод нужно вызывать без указания второго параметра Html.ValidationMessage("UnitPrice"). Результат приведен на рис. 5.3.

Стоит отметить, что если в коде представления не используется строготипизированная привязка к свойствам модели, то привязка к данным осуществляется автоматически, и в этом случае при возникновении ошибок нет необходимости передавать объект модели представлению через метод View(), как это было сделано в листинге 5.7. То есть фрагмент кода из листинга 5.7 может быть написан так, как указано далее. Листинг 5.9 демонстрирует код представления, не использующего привязку к свойствам объекта модели Model.

if (IModelState.IsValid)

{

  // есть ошибки, еще раз

  // показать форму редактирования

  return View();

}

Листинг 5.9. Представление Edit.aspx без привязки к свойствам объекта Model

<%@ Page Title="" Language="C#"

        MasterPageFile="~/Views/Shared/Site.Master"

        Inherits="System.Web.Mvc.ViewPage<MvcViewsDemo.Models.Product>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">

  Edit

</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

  <h2>

    Редактирование сведений о товаре

  </h2>

  <%= Html.ValidationSummary("при редактировании сведений

                   о товаре произошли ошибки.") %>

  <% using (Html.BeginForm())

  {%>

    <fieldset>

      <legend>Редактирование сведений о товаре</legend>

      <p>

        <label for="ProductID">

          Код продукта:

        </label>

        <%= ViewData.Eval("ProductID") %>

        <%= Html.Hidden("ProductID")%>

      </p>

      <p>

        <label for="ProductName">

          Название:

        </label>

        <%= Html.TextBox("ProductName") %>

        <%= Html.ValidationMessage("ProductName") %>

      </p>

      <p>

        <label for="UnitPrice">

          Цена:

        </label>

        <%= Html.TextBox("UnitPrice") %>

        <%= Html.ValidationMessage("UnitPrice") %>

      </p>

      <p>

        <label for="UnitsInStock">

          На складе:

        </label>

        <%= Html.TextBox("UnitsInStock") %>

        <%= Html.ValidationMessage("UnitsInStock") %>

      </p>

      <p>

        <label for="UnitsOnOrder">

          Заказано:

        </label>

        <%= Html.TextBox("UnitsOnOrder") %>

        <%= Html.ValidationMessage("UnitsOnOrder") %>

      </p>

      <p>

        <input type="submit" value="Save" />

      </p>

    </fieldset>

  <% } %>

  <div>

    <%=Html.ActionLink("K списку товаров", "Index") %>

  </div>

</asp:Content>

Примечание

Важно обратить внимание, что при использовании кода, аналогичного приведенному в листинге 5.9, поиск значений элементов формы будет осуществляться через ViewData.Eval(), и значение ViewData["SomeProperty"] имеет больший приоритет, чем ViewData.Model.SomeProperty. Поэтому, во избежание трудноуловимых ошибок, при создании кода контроллера стоит с особенной тщательностью относиться к тому, как передаются данные — через свойства объекта-модели или через коллекцию ViewData.

***************************

Более 800 000 книг и аудиокниг! 📚

Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением

ПОЛУЧИТЬ ПОДАРОК