Pregunta

Estoy usando ASP.NET MVC 2.0 y estoy tratando de aprovechar la encuadernación del modelo en mi controlador y también la validación de ModelState. Sin embargo, he subido contra un problema y quería compartirlo con personas aquí para ver lo que piensas.

OK Tengo mi usuario limpio Poco en mi biblioteca de clase modelo ...

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;
        }
    }
}

El diseño que he ido solo permite editar ciertas propiedades, después de que se haya construido el objeto. El nombre de usuario, por ejemplo, solo se puede configurar cuando se construye el objeto, para mí, esto hace que OO Sense, pero es la clave de mi problema, así que quería resaltarlo aquí.

Entonces tengo una 'clase de amigos' que define los metadatos de validación para mi clase de usuario ...

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; }
    }
}

}

Luego, en mi capa web, quiero permitir que mis usuarios puedan editar este objeto. Así que tengo los siguientes dos métodos de acción en mi controlador de perfil.

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);
        }
    }
}

Esto tiene una vista muy escrita para ir con él ...

<%@ 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>

OK, así que eso es todo el código en el camino!

Así que aquí está el problema, la vista se traduce bien después de la solicitud de obtendrás inicial. Pero cuando el usuario publica el formulario de vuelta, digamos después de editar su nombre de visualización, el StatemState no es válido. Esto se debe a que la propiedad Nombre de usuario tiene un setter privado. Sin embargo, esto es por diseño, por seguridad y semántica, no quiero que cambien su nombre de usuario, por lo que el setter es privado. Sin embargo, como he agregado el atributo requerido a la propiedad, ¿no está fallando ya que no está establecido?

La pregunta es que el ModelBinding esté reportando esto como un error de validación o no? A medida que la propiedad es privada, lo he diseñado para que no se configure, por lo tanto, por diseño, no espero que la carpeta modelo lo esté configurando, pero no quiero un error de validación. Creo que solo debe producir errores de validación para propiedades que puede establecer.

OK, así que las posibles soluciones que he llegado hasta ahora.

Hacer pública la propiedad.

Si hago esto, me abre hasta permitir que se cambie el nombre de usuario para el usuario existente. Tendría que agregar una lógica extra en algún lugar para atrapar esto, no es realmente muy agradable. También tendría que agregar un enlace excluir en el método de acción para detener a cualquier gente traviesa que intenta configurarla a través de una publicación.

Eliminar el error

Creo que puedo eliminar el error del Diccionario de Statemstate, esto estaría bien en esta ocasión, pero creo que esto presentará algún olor a código, ya que tendría que agregar esto para todos mis objetos que tienen los consentidos privados. ¡Probablemente olvidaría !!

Escribe fuertemente mi vista contra una interfaz

He leído que algunas personas se unen a su vista a una interfaz de su modelo, este es el rey de una interfaz de modelo de modelo en el objeto modelo de negocio. Me gusta esta idea, pero pierdo la unión automática y necesito duplicar mis objetos modelo con sus constructores en mi capa web, ¡no estoy seguro de eso? Alguna información sobre esto aquí http://www.codethinked.com/post/2010/04/12/easy-and-safe-model-binding-in-aspnet-mvc.aspx .

Use Model Views

¡Esto simplemente no me parece seco? Estoy feliz de usarlos si no tengo un objeto modelo existente que se ajusta (por ejemplo, uso una vista de modelo de registro).

CustomodElBinder

Mi opción preferida, pero no estoy seguro de saber lo que estoy haciendo! Si pudiera hacer que el carpeta solo se une a las propiedades que puede configurar, ¡entonces me ríe!

¿Qué piensa la gente? Comentarios sobre las opciones anteriores, cualquier otra solución, ¡estoy fuera de la marca con mi arquitectura?!

gracias :)

¿Fue útil?

Solución 3

JFAR ha publicado un buen enlace a una publicación por Brad Wilson, donde los comentarios de Brad ...

Todavía puedes hacer la edición parcial, pero No puedes hacer validación parcial más.Así que si excluye la unión. algo con el [requerido] Atributo, entonces la validación fallará. Tienes algunas opciones para trabajar esto:

  • Use un modelo de vista que refleje exactamente los datos del formulario

  • Pre-rellene [requerido] pero campos sin unir con datos antes de llamar (Prueba) updatemodel para que la la validación tendrá éxito (aunque sea No tienes la intención de hacer nada con que los datos)

  • Permitir que ocurran los errores de validación, y luego elimínelos de ModelState después de la validación se realiza, ya que son errores inapropiados.

Mi caso parece encajar en el caso 'Edición parcial', donde no quiero actualizar ciertos campos.

Voy a mirar a estos como soluciones.

Otros consejos

" He diseñado para que no se estableciera, por lo tanto, por diseño, no espero que el Modelo Binder lo configure, pero no quiero un error de validación. Creo que solo debería producir validación Errores para propiedades que puede configurar. "

Leer más sobre esta decisión de diseño aquí:

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

Curiosamente la mayoría de las personas se quejaron todo lo contrario de lo que se queja. ;)

que básicamente le dice al sistema que siempre se debe establecer algo que no se debe establecer. Así que no diría que MVC está trabajando incorrectamente o algo así. Usted solo codifica un escenario imposible.


En general, usted acaba de llegar a los puntos de dolor de la técnica metadatabudud. Principalmente la necesidad de tener una validación diferente para los escenarios nuevos y editar.

" Si hago esto, me abro para permitir que se cambie el nombre de usuario para los usuarios existentes. Tendría que agregar lógica extra en algún lugar para atrapar esto, no es realmente muy agradable. También tendría que agregar un Enlace excluir en el método de acción para detener a cualquier persona traviesa que intenta configurarla a través de una publicación. "

IMHO su exceso de cambios a estos cambios de código. Usted estaría agregando una cadena simple a una sola llamada de método. ¿Cual es el problema? Tomaría el enfoque pragmático aquí.

Yo usaría un modelo de vista porque es el mejor ajuste para el trabajo.No piense en el significado seco que no puede repetir propiedades en dos objetos, piense en ello como "No duplique la lógica o persista los datos idénticos en dos lugares".En este caso, la semántica de tratar con la unión del modelo no se coincide con su modelo de dominio, por lo que necesita una forma de traducirla.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top