Esta pregunta se inspiró en mi lucha con ASP.NET MVC, pero creo que se aplica a otras situaciones también.¿Cómo "SECAR" los atributos de C# en Modelos y Modelos de Vista?
Digamos que tengo un modelo generado por ORM-y dos ViewModels (uno para una vista "Detalles" y uno para un "editar" vista):
Modelo
public class FooModel // ORM generated
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
public int CategoryId { get; set; }
}
Display ViewModel
public class FooDisplayViewModel // use for "details" view
{
[DisplayName("ID Number")]
public int Id { get; set; }
[DisplayName("First Name")]
public string FirstName { get; set; }
[DisplayName("Last Name")]
public string LastName { get; set; }
[DisplayName("Email Address")]
[DataType("EmailAddress")]
public string EmailAddress { get; set; }
public int Age { get; set; }
[DisplayName("Category")]
public string CategoryName { get; set; }
}
Editar modelo de vista
public class FooEditViewModel // use for "edit" view
{
[DisplayName("First Name")] // not DRY
public string FirstName { get; set; }
[DisplayName("Last Name")] // not DRY
public string LastName { get; set; }
[DisplayName("Email Address")] // not DRY
[DataType("EmailAddress")] // not DRY
public string EmailAddress { get; set; }
public int Age { get; set; }
[DisplayName("Category")] // not DRY
public SelectList Categories { get; set; }
}
Tenga en cuenta que los atributos de los ViewModels no son en seco - una gran cantidad de información se repite. Ahora imagina este escenario multiplicado por 10 o 100, y puedes ver que puede volverse bastante tedioso y propenso a errores para garantizar la coherencia entre ViewModels (y, por lo tanto, entre Views).
¿Cómo puedo "SECAR" este código?
Antes de responder, "Sólo hay que poner todos los atributos de FooModel
," lo he intentado, pero no funcionó porque tengo que mantener mis ViewModels "plana". En otras palabras, no puedo simplemente componer cada ViewModel con un modelo; necesito que mi ViewModel tenga solo las propiedades (y atributos) que debe consumir la vista, y la vista no puede excavar en sub-propiedades para obtener los valores.
actualización
respuesta de LukLed sugiere el uso de la herencia. Esto definitivamente reduce la cantidad de código no DRY, pero no lo elimina. Tenga en cuenta que, en mi ejemplo anterior, el atributo DisplayName
para la propiedad Category
debería escribirse dos veces porque el tipo de datos de la propiedad es diferente entre la visualización y la edición de ViewModels. Esto no va a ser un gran problema a pequeña escala, pero a medida que aumenta el tamaño y la complejidad de un proyecto (imagina muchas más propiedades, más atributos por propiedad, más vistas por modelo), aún existe la posibilidad de que "repitiéndose" una cantidad justa. Tal vez estoy tomando DRY demasiado lejos aquí, pero aún prefiero tener todos mis "nombres amistosos", tipos de datos, reglas de validación, etc. mecanografiados solo una vez.
Gracias, jfar y +1. Sí, exactamente, estoy tratando de usar DisplayFor() y EditorFor() (aunque, incluso en los casos en que no puedo, aún me gustaría SECAR mis ViewModels). Su idea eliminaría la necesidad de atributos, lo que es de gran ayuda. Me pregunto, sin embargo, si también podría agregar una propiedad personalizada (y un atributo personalizado paralelo) que indique si se debe andamiar una propiedad particular para un modelo de vista particular. Esto me permitiría tener un ViewModel que maneje todas las vistas, lo que significa que nunca o casi nunca necesitaré repetir atributos. – devuxer
Bueno, la única limitación son las propiedades predeterminadas de ModelMetadata. Si necesita agregar más información y crear un MyModelMetadata: ModelMetatdata, también tendrá que crear su propia página de vista personalizada con una propiedad MyModelMetadata personalizada O emitir el ViewData.ModelMetadata dentro de los archivos .aspx o .ascx que use. – jfar