ModelState сообщила как недействительным для частных свойств на модели в ASP.NET MVC 2

StackOverflow https://stackoverflow.com/questions/3229971

Вопрос

Я использую ASP.NET MVC 2.0, и я пытаюсь воспользоваться преимуществами моделей привязки в моем контроллере, а также проверку ModelState. Однако я придумал проблему и хотел поделиться этим с людьми здесь, чтобы увидеть, что вы думаете.

Хорошо, у меня есть мой чистый пользователь PoCo в моей библиотеке классов модели ...

namespace Model
{    
    public partial class User
    {
        public virtual int Id { get; private set; }
        public virtual string UserName { get; private set; }
        public virtual string DisplayName { get; set; }
        public virtual string Email { get; set; }

        public User(string displayName, string userName)
            : this()
        {
            DisplayName = displayName;
            UserName = userName;
        }
    }
}
.

Дизайн, который я пошел только для того, чтобы редактировать определенные свойства, после того, как объект был построен. Имя пользователя, например, можно установить только тогда, когда объект построен, мне это делает смысл, но является ключом к моей проблеме, поэтому я хотел выделить это здесь.

У меня тогда есть «класс Buddy», который определяет метаданные проверки для моего класса пользователя ...

namespace Model
{
[MetadataType(typeof(UserMetadata))]
public partial class User
{
    class UserMetadata
    {
        [Required]
        public virtual int Id { get; set; }

        [Required]
        public virtual string UserName { get; set; }

        [Required]
        public virtual string DisplayName { get; set; }

        [RegularExpression(@"^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$", ErrorMessage = "Invalid address")]
        public virtual string Email { get; set; }
    }
}
.

}

Затем в моем веб-слое я хочу позволить своим пользователям сможете редактировать этот объект. Поэтому у меня есть следующие два метода действия в моем контроллере профиля.

namespace Web.Controllers
{
    public class ProfileController : Controller
    {
        [Authorize]
        public ActionResult Edit()
        {
            var user = _session.Single<User>(x => x.UserName == HttpContext.User.Identity.Name );
            return View(user);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        [Authorize]
        [TransactionFilter]
        public ActionResult Edit(User updatedUser)
        {
            // Get the current user to update.
            var user = _session.Single<User>(x => x.UserName == HttpContext.User.Identity.Name);

            if (ModelState.IsValid)
            {
                TryUpdateModel(user);
                // Update store...                
            }
            return View(updatedUser);
        }
    }
}
.

Это имеет сильно напечатанный вид, чтобы пойти с ним ...

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

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

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <%=Html.Script("jquery.validate.js")%>
    <%=Html.Script("MicrosoftMvcJQueryValidation.js")%>
    <%=Html.Script("MvcFoolproofJQueryValidation.js")%>
    <div class="container">
        <div class="column span-14">
        <% using (Html.BeginForm()) {%>
            <%= Html.AntiForgeryToken() %>
            <fieldset>
                <%: Html.DisplayFor(model => model.UserName) %>
                <%= Html.Label("Display Name") %>
                <%= Html.HiddenFor(model => model.DisplayName)%>
                <%= Html.ValidationMessageFor(model => model.DisplayName)%>
                <%= Html.Label("Email address") %>
                <%= Html.EditorFor(model => model.Email)%>
                <%= Html.ValidationMessageFor(model => model.Email)%>
                <%= Html.HiddenFor(model => model.UserName)%>
                <p>
                    <input type="submit" value="Save" />
                </p>
            </fieldset>
        </div>
        <div class="clear"></div>
        <% } %>
    </div>
</asp:Content>
.

Хорошо, так что весь код выше !!

Так вот проблема, просмотр отображается нормально после первоначального запроса Get. Но когда пользователь записывает форму образа, скажи после редактирования их отображения, ModelState недействителен. Это связано с тем, что свойство имени пользователя имеет на нем частный сеттер. Однако это по дизайну, для безопасности и семантики, я никогда не хочу, чтобы они изменили их имя пользователя, поэтому установка является частным. Однако, как я добавил необходимый атрибут к свойству, он не в состоянии не установлен!

Вопрос должен быть сообщать о том, что ModelBinding сообщает об этом как ошибка проверки или нет?! Поскольку свойство является частным, я разработал для него, чтобы он не был установлен, поэтому по дизайну я не ожидаю, что моделей Binder его установить, но я не хочу ошибку валидации. Я думаю, что он должен производить только ошибки проверки для свойств, которые он может установить.

ОК, настолько возможные решения, которые я придумал так далеко.

Составьте публику недвижимости.

Если я сделаю это, я открываю себя, чтобы позволить имя пользователя быть изменено для существующих пользователей. Я должен был бы добавить дополнительную логику где-то поймать это, не очень хорошо. Мне также пришлось бы добавить связывание, исключающую в методе действий, чтобы остановить каких-либо непослушных людей, пытающихся установить его через сообщение.

Удалить ошибку

Я верю, что могу удалить ошибку из словаря ModelState, это было бы в порядке по этому поводу, но я думаю, что это введет какое-то кодовый запах, так как мне придется добавить это для всех моих объектов, которые имеют частные загадки. Я бы, вероятно, забуду !!

сильно введите мой вид на интерфейс

Я прочитал, что некоторые люди связывают их вид на интерфейс своей модели, это король интерфейса ModelView на объекте бизнес-модели. Мне нравится эта идея, но я потеряю автоматическую связывание и нужно было бы дублировать мою модель объекты со своими конструкторами в моем веб-слое, не уверен в этом?! Некоторая информация об этом здесь http://www.codicked.com/post/2010/04/12/easy-and-safe-model-binding-in-aspnet-mvc.aspx .

Использовать вид модели

Это просто не кажется сухим для меня?! Я рад использовать их, если у меня нет существующего объекта модели, который соответствует (например, я использую вид модели регистрации).

CustomModelBinder

Мой предпочтительный вариант, но я не уверен, что знаю, что я делаю !! Если бы я мог просто получить связующее, чтобы привязать только к свойствам, он может установить, то я был бы смеяться !!

Что люди думают? Комментарии к вышеуказанным вариантам, любые другие решения, я только что сметку с моей архитектурой?!

Спасибо :)

Это было полезно?

Решение 3

jfar опубликовал хорошую ссылку на сообщение brad wilson, где Brad Comments ...

Вы все еще можете сделать частичное редактирование, но Вы не можете сделать частичную проверку любой более.Так что если вы исключите привязку что-то с [обязательным] атрибут, то валидация не удастся. У вас есть несколько вариантов для работы Это:

    .
  • Используйте модель просмотра, которая точно отражает данные формы

  • Предварительно заполните [обязательно], но несвязанные поля с данными перед вызовом (Попробуйте) UpdateModel так, чтобы проверка добится успеха (хотя Вы не намерены ничего делать с что данные)

  • Разрешить возникнуть ошибки проверки, а затем удалить их из ModelState после проверки сделан, Поскольку они неуместные ошибки.

Мое дело, кажется, вписывается в корпус «частичного редактирования», где я не хочу обновляться определенные поля.

Я посмотрю в это как решения.

Другие советы

" Я разработан для нее, чтобы не быть установленным, поэтому по дизайну я не ожидаю, что моделей связующее настроить его, но я не хочу ошибку валидации. Я думаю, что это должно производить только проверку только Ошибки для свойств, которые он может установить. "

Подробнее об этом решении дизайна здесь:

http : //bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.html

Интересно, что большинство людей жаловались на полную противоположность того, о чем вы жалуетесь. ;)

Вы в основном сообщаете систему, что что-то не может быть установлено, всегда должно быть установлено. Поэтому я бы не сказал, что MVC работает неправильно или что-то подобное. Вы просто кодируете невозможный сценарий.


В целом ваш просто достигая боли техники метадатабадди. В первую очередь необходимость иметь разные валидации для новых сценариев и редактирования.

" Если я сделаю это, я открываю себя, чтобы позволить имя пользователя быть изменено для существующих пользователей. Мне бы пришлось бы добавить дополнительную логику где-то, чтобы поймать это, не очень хорошо. Мне бы также придеться Свяжитесь с методом действия, чтобы остановить любые непослушные люди, пытающиеся установить его через сообщение. "

ИМХО, ваше переедание на эти изменения кода. Вы будете добавлять простую строку в один вызов метода. Подумаешь? Я бы взял прагматичный подход здесь.

Я бы использовал модель просмотра, потому что это лучшее подходит для работы.Не думайте о сухом смысле, что вы не можете повторять свойства на двух объектах, думать об этом как «не дублируйте логику или не сохранять идентичные данные в двух местах».В этом случае семантика борьбы с моделей связыванием модели не совпадает с вашей моделью домена, поэтому вам нужен способ перевести его.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top