ASP.NET MVC 2 Preview 1 — Проверка DataAnnotation с помощью сложного объекта модели

Возможность позволить модели самостоятельно выполнять проверку побудила меня начать экспериментировать с предварительным выпуском MVC 2. Пока что мне нравится простота схемы проверки. Тем не менее, я столкнулся с блокпостом. Этот стиль проверки отлично работает для простых объектов модели представления. Например, если у меня есть объект модели с именем car, и я хочу создать представление для создания нового автомобиля:

-----Модель-------

public class Car
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Color { get; set; }
}

----- Контроллер ---------

public class CarController : Controller
{
    public ActionResult Create()
    {
        Car myCar = new Car();
        return View("Create", myCar);

    }

    [HttpPost]
    public ActionResult Create(Car myCar)
    {
        if (!ModelState.IsValid)
        {
            return View("Create", myCar);
        }

        //Do something on success
        return View("Index");

    }

}

-------Вид--------------

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Car>" %>

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

    <%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>

    <% 
        using (Html.BeginForm()) {%>

        <fieldset>
            <legend>Edit User Profile</legend>
            <p>
                <label for="Id">Id:</label>
                <%= Html.TextBox("Id", Model.Id)%>
                <%= Html.ValidationMessage("Id") %>
            </p>
            <p>
                <label for="Name">Name:</label>
                <%= Html.TextBox("Name", Model.Name)%>
                <%= Html.ValidationMessage("Name") %>
            </p>
            <p>
                <label for="Color">Color:</label>
                <%= Html.TextBox("Color", Model.Color)%>
                <%= Html.ValidationMessage("Color") %>
            </p>

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

    <% } %>

</asp:Content>

Это работает как шарм. Но не все мои представления или объекты моделей, если уж на то пошло, просты. У меня может быть объект модели автомобиля, например:

-----Модель-------

public class PaintScheme
{
    public int Red { get; set; }
    public int Blue { get; set; }
    public int Green { get; set; }
}

public class Car
{
    public string Id { get; set; }
    public string Name { get; set; }
    public PaintScheme Paint{ get; set; }
}

-------Вид--------------

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Car>" %>

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

    <%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>

    <% 
        using (Html.BeginForm()) {%>

        <fieldset>
            <legend>Edit User Profile</legend>
            <p>
                <label for="Id">Id:</label>
                <%= Html.TextBox("Id", Model.Id)%>
                <%= Html.ValidationMessage("Id") %>
            </p>
            <p>
                <label for="Name">Name:</label>
                <%= Html.TextBox("Name", Model.Name)%>
                <%= Html.ValidationMessage("Name") %>
            </p>
            <p>
                <label for="Red">Color Red:</label>
                <%= Html.TextBox("Red", Model.Paint.Red)%>
                <%= Html.ValidationMessage("Red") %>
            </p>
            <p>
                <label for="Blue">Color Blue:</label>
                <%= Html.TextBox("Blue", Model.Paint.Blue)%>
                <%= Html.ValidationMessage("Blue") %>
            </p>
            <p>
                <label for="Green">Color Green:</label>
                <%= Html.TextBox("Green", Model.Paint.Green)%>
                <%= Html.ValidationMessage("Green") %>
            </p>

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

    <% } %>

</asp:Content>

Когда я добавляю свойства PaintScheme в свое представление, они не переносятся с объектом "myCar", переданным в действие моего контроллера. Есть ли способ решить эту проблему без необходимости перестраивать объект из коллекции форм и затем проверять ModelState?


person gun_shy    schedule 02.09.2009    source источник
comment
Я думаю, что заголовок следует изменить на что-то вроде ASP.NET MVC Binding Nested Object Properties, поскольку он, похоже, вообще не связан с DataAnnotations.   -  person Dmytrii Nagirniak    schedule 02.09.2009


Ответы (3)


  1. У вас должен быть общедоступный сеттер для свойств, которые вы хотите связать. Интересно, как первый образец работает для вас, поскольку все конфиденциально.
  2. Вы должны опубликовать хотя бы одно значение свойства PaintScheme, чтобы иметь возможность привязать его.
  3. Все дочерние свойства должны иметь префикс путь к нему. Где path можно определить как *(PropertyName.)**.

Кажется пункт 3 не устраивает во View. Измените соответствующую часть представления на это:

        <p>
            <label for="Red">Color Red:</label>
            <%= Html.TextBox("Paint.Red")%>
            <%= Html.ValidationMessage("Red") %>
        </p>
        <p>
            <label for="Blue">Color Blue:</label>
            <%= Html.TextBox("Paint.Blue")%>
            <%= Html.ValidationMessage("Blue") %>
        </p>
        <p>
            <label for="Green">Color Green:</label>
            <%= Html.TextBox("Paint.Green")%>
            <%= Html.ValidationMessage("Green") %>
        </p>

Кроме того, обратите внимание, что я удалил явные значения из помощника TextBox, чтобы избежать возможного исключения NullReferenceException.

person Dmytrii Nagirniak    schedule 02.09.2009
comment
Он оставил их для краткости. - person mxmissile; 02.09.2009
comment
В порядке. Кажется, я вижу, что не так. Обновил ответ соответственно. - person Dmytrii Nagirniak; 02.09.2009
comment
Это было именно то, чего мне не хватало. Спасибо Дмитрий. - person gun_shy; 02.09.2009

Самый простой способ справиться с этим — сгладить вашу модель с помощью dto. Затем используйте automapper для сопоставления объекта домена с вашей моделью представления. Этот перевод может быть определен таким образом, что вы конвертируете перечисление в строку и обратно. Тогда проверка сработает, и ваша бом не будет касаться представления, достаточно хорошо поддерживая разделение проблем.

person Andrew Siemer    schedule 02.09.2009
comment
Зачем сглаживать и вводить другую зависимость вместо того, чтобы просто правильно использовать функцию (ModelBinding)? Показанная модель не является сложной для ее разделения. - person Dmytrii Nagirniak; 02.09.2009
comment
Поддержание разделения проблем от слоя к слою почти всегда делает вещи чище. - person Andrew Siemer; 03.09.2009

Для части цвета у вас может быть что-то вроде этого, будучи int, я не думаю, что вы будете использовать текстовое поле, но это свяжет ваш красный цвет (если входное значение является числом)

 <p>
                <label for="Red">Color:</label>
                <%= Html.TextBox("Red", Model.Paint.Red)%>
                <%= Html.ValidationMessage("Red") %>
 </p>
person San    schedule 02.09.2009