Pregunta

Cuando empecé a usar XVal para la validación del lado del cliente, sólo estaba poniendo en práctica métodos de acción que utilizaron el modelo de dominio objetos como un modelo de vista o instancias incrustados de los objetos en el modelo de vista.

Este enfoque funciona bien la mayor parte del tiempo, pero hay casos en los que la vista tiene que mostrar y después de vuelta sólo un subconjunto de las propiedades del modelo (por ejemplo, cuando el usuario quiere actualizar su contraseña, pero no el resto de su perfil de datos).

Un (feo) solución es tener un campo de entrada oculto en el formulario para cada propiedad que no está presente de otro modo en el formulario.

Al parecer, la mejor práctica es crear un modelo de vista personalizada que sólo contiene propiedades relevantes a la vista y poblar el modelo de vista a través de AutoMapper. Es mucho más limpio ya que sólo estoy transfiriendo los datos relevantes a la vista, pero está lejos de ser perfecto ya que tengo que repetir los mismos atributos de validación que ya están presentes en el modelo de objetos de dominio.

Lo ideal sería que especificar el objeto modelo de dominio como clase meta a través de un atributo de metadatos (esto también se refiere a menudo como "la clase de amigos"), pero eso no quiere trabajar desde XVal lanza cuando la clase de metadatos tiene propiedades que no están presentes en el modelo de vista.

¿Hay alguna solución a este elegante? He estado considerando la piratería XVal el código fuente, pero tal vez hay alguna otra manera que he pasado por alto hasta ahora.

Gracias,

Adrian

Editar Con la llegada de ASP.NET MVC 2, esto no es sólo un problema relacionado con los atributos de validación más, pero también se aplica a los atributos de edición y visualización.

¿Fue útil?

Solución

Esta es la razón por excelencia por qué sus pantallas de entrada no deben ser estrechamente unidas a su modelo. Esta pregunta en realidad aparece aquí en la etiqueta MVC aproximadamente 3-4 veces al mes. Me DUPE Si pudiera encontrar la pregunta anterior y parte del comentario de discusión aquí es interesante. ;)

El problema es que usted tenga que está tratando de forzar a dos contextos diferentes de validación de un modelo en un modelo único que falle bajo una gran cantidad de escenarios. El mejor ejemplo es la firma de un nuevo usuario y luego tener un administrador editar un campo de usuario más tarde. Es necesario para validar una contraseña en un objeto de usuario durante el registro, pero no se mostrará el campo de contraseña al administrador de la edición de los datos de usuario.

Las opciones para moverse por todos estos son sub-óptimos. He trabajado en este problema para 3 proyectos de ahora y la implementación de las siguientes soluciones nunca ha sido limpia y por lo general frustrante. Voy a tratar de ser práctica y olvidar todo el DDD / db / modelo / discusiones hotnessofthemonth todo el mundo está teniendo.

1) Múltiples Visualización de modelos  Tener ViewModels que son casi la misma viola el principio DRY pero siento los costos de este enfoque son realmente bajos. Por lo general, viola SECO amplifica los costes de mantenimiento, pero en mi humilde opinión los costos de este son los más bajos y no es gran cosa. Hipotéticamente hablando no cambiar la forma de caracteres número máximo el campo Apellidos puede tener muy a menudo.

2) dinámico de metadatos Hay ganchos en MVC 2 para proporcionar su propia metadatos para un modelo. Con este enfoque podría tener cualquiera que sea su uso para proporcionar metadatos excluyen ciertos campos en base a la HTTPRequest actual y, por tanto, la acción y el controlador. He usado esta técnica para construir un sistema de permisos con base de datos que va a la base de datos y le dice a la una subclase de la DataAnnotationsMetadataProvider para excluir propiedades valores almacenados en la base de datos basados.

Esta técnica funciona de maravilla atm pero el único problema es la validación con UpdateModel(). Para resolver este problema hemos creado un método SmartUpdateModel() que también va a la base de datos y genera automáticamente los excluye string [] matriz de modo que cualquier campo no permissisable no se validan. Nosotros, por supuesto, esta en caché por motivos de rendimiento por lo que no está mal.

Sólo quiero reiterar que utilizamos [ValidationAttributes] en nuestros modelos y luego los superceeded con las nuevas normas sobre el tiempo de ejecución. El resultado final fue que el campo [Required] User.LastName no fue validado si el usuario no tiene permiso para acceder a él.

3) Loco interfaz dinámica Proxy cosa La última técnica intenté era utilizar las interfaces de ViewModels. El resultado final fue que tenía un objeto de usuario que heredó de interfaces como IAdminEdit y IUserRegistration. IAdminEdit y IUserRegistration serían ambos contienen atributos DataAnnotation que hacían toda la validación específica contexto como una propiedad de contraseña con las interfaces.

Esto requiere algún hackery y era más un ejercicio académico que cualquier otra cosa. El problema con 2 y 3 es que UpdateModel y el proveedor DataAnnotationsAttribute necesarios para personalizar estar al tanto de esta técnica.

Mi mayor obstáculo era yo no quiero volver a enviar la totalidad del objeto de usuario a la vista, así que terminé el uso de proxies dinámicos para crear instancias de tiempo de ejecución de IAdminEdit

Ahora entiendo que esto es una pregunta específica muy XVal pero todos los caminos a la validación dinámico como este cable a la personalización de los proveedores internos MVC metadatos. Dado que todas las cosas de metadatos es nada nuevo es que limpia o fácil de hacer en este momento. El trabajo que tendría que hacer para personalizar el comportamiento de la validación de MVC no es difícil, pero requiere un poco de conocimiento en profundidad de cómo todo el trabajo internos.

Otros consejos

Nos cambiamos los atributos de nuestra validación de la capa de modelo de vista. En nuestro caso, esto proporcionó una separación más limpia de las preocupaciones de todos modos, tal como nos fueron capaces de diseñar nuestro modelo de dominio tal que no podía entrar en un estado no válido en el primer lugar. Por ejemplo, la fecha podría ser necesario en un objeto BillingTransaction. Por lo que no queremos que sea anulable. Sin embargo, en nuestro modelo de vista, puede ser que necesite para exponer anulable tal que podemos captar la situación en la que el usuario no introduzca un valor.

En otros casos, puede que tenga la validación de que es específico por página / formulario, y usted querrá validar basándose en la orden que el usuario está tratando de realizar, en lugar de establecer un montón de cosas y pedir el modelo de dominio, "¿estás válida para tratar de hacer XYZ", donde en la práctica "ABC" esos valores son válidos.

Si ViewModels hipotéticamente se ven obligados a usted, entonces le recomiendo que sólo hacen cumplir los requisitos de dominio agnóstica. Esto incluye cosas como "se requiere nombre de usuario" y "correo electrónico tiene el formato correcto".

Si duplica la validación de los modelos de dominio en los modelos de vista, entonces has estrechamente unida al dominio de la interfaz de usuario. Cuando los cambios de validación de dominio ( "sólo se pueden aplicar 2 cupones por semana" se convierte en "sólo puede aplicarse 1 cupón por semana"), la interfaz de usuario debe ser actualizado. En términos generales, esto sería terrible, y en detrimento de la agilidad.

Si se mueve la validación de los modelos de dominio de la interfaz de usuario, que ha coartado la su dominio y se coloca la responsabilidad de la validación de la interfaz de usuario. Una segunda interfaz de usuario tendría que duplicar toda la validación y se han unido dos juntos separada de la interfaz de usuario. Ahora bien, si el cliente desea una interfaz especial para administrar el inventario de su iPhone, iPhone el proyecto necesita para replicarse toda la validación que también se encuentra en el sitio web de la interfaz de usuario. Esto sería incluso más terrible que la duplicación de validación descrito anteriormente.

A menos que se puede predecir el futuro y puede descartar estas posibilidades, solamente validar los requisitos de dominio agnóstica.

No sé cómo va a jugar para la validación del lado del cliente, pero si la validación parcial es su problema se puede modificar el DataAnnotationsValidationRunner discutido aquí para tomar en una lista de nombres de propiedades IEnumerable<string>, de la siguiente manera:

public static class DataAnnotationsValidationRunner
{
     public static IEnumerable<ErrorInfo> GetErrors(object instance, IEnumerable<string> fieldsToValidate)
     {
           return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>().Where(p => fieldsToValidate.Contains(p.Name))
                  from attribute in prop.Attributes.OfType<ValidationAttribute>()
                  where !attribute.IsValid(prop.GetValue(instance))
                  select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
     }
}

Voy a riesgo de los downvotes y declarar que no haya un beneficio a ViewModels (en ASP.NET MVC), especialmente teniendo en cuenta la sobrecarga de crear y mantener ellos. Si la idea es disociar del dominio, que es indefendible. Una interfaz de usuario desacoplado de un dominio no es una interfaz de usuario para ese dominio. La interfaz de usuario debe dependen del dominio, por lo que está bien va a tener sus acciones Vistas / acoplados al modelo de dominio, o el modelo de vista lógica de gestión acoplado al modelo de dominio. El argumento de la arquitectura es, por tanto discutible.

Si la idea es evitar que los usuarios de la piratería envíos HTTP maliciosos que aprovechan el modelo de ASP.NET MVC unión a mutar campos que no se debe permitir a cambiar, a continuación, a) el dominio debe cumplir este requisito, y B) las acciones deben proporcionar listas blancas de propiedades actualizables al aglutinante modelo.

A menos que sea de dominio está exponiendo algo loco como un gráfico en vivo, en memoria objeto en lugar de copias entidad, ViewModels se desperdician esfuerzos. Así que para responder a su pregunta, mantenga la validación de dominio en el modelo de dominio.

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