Questa domanda è stata ispirata dalle mie difficoltà con ASP.NET MVC, ma penso che si applichi anche ad altre situazioni.Come "DRY up" gli attributi C# in Models e ViewModels?
Diciamo che ho un modello ORM-generated e due ViewModels (uno per una vista "Dettagli" e uno per una "modifica" vista):
Modello
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; }
}
Modifica ViewModel
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; }
}
Si noti che gli attributi sui ViewModels non sono a secco - un sacco di informazioni viene ripetuta. Ora immagina questo scenario moltiplicato per 10 o 100, e puoi vedere che può diventare rapidamente noioso e soggetto a errori per assicurare la coerenza tra ViewModels (e quindi attraverso Views).
Come è possibile "ASCIUGARE" questo codice?
Prima di rispondere, "Basta mettere tutti gli attributi su FooModel
," Ho provato, ma non ha funzionato perché ho bisogno di mantenere il mio ViewModels "flat". In altre parole, non posso semplicemente comporre ogni ViewModel con un modello - Ho bisogno del mio ViewModel per avere solo le proprietà (e gli attributi) che dovrebbero essere consumati dalla vista, e la vista non può scavare in sotto-proprietà per ottenere i valori.
Aggiornamento
risposta di LukLed suggerisce di usare l'ereditarietà. Ciò riduce decisamente la quantità di codice non DRY, ma non lo elimina. Si noti che, nel mio esempio sopra, l'attributo DisplayName
per la proprietà Category
dovrebbe essere scritto due volte perché il tipo di dati della proprietà è diverso tra la visualizzazione e modifica ViewModels. Questo non sarà un grosso problema su piccola scala, ma man mano che le dimensioni e la complessità di un progetto si ridimensionano (immaginate molte più proprietà, più attributi per proprietà, più visualizzazioni per modello), c'è ancora il potenziale per "ripetendo te stesso" una discreta quantità. Forse sto prendendo DRY troppo lontano qui, ma preferirei avere tutti i miei "nomi amichevoli", i tipi di dati, le regole di convalida, ecc., Digitato una sola volta.
Grazie, jfar e +1. Sì, esattamente, sto cercando di usare DisplayFor() e EditorFor() (anche se, anche nei casi in cui non posso, mi piacerebbe ancora ASCIUGARE i miei ViewModels). La tua idea rimuoverebbe molto bisogno di attributi, il che è di grande aiuto. Mi chiedo, tuttavia, se potessi aggiungere anche una proprietà personalizzata (e un attributo personalizzato parallelo) che indicherebbe se impalcare una particolare proprietà per un particolare ViewModel. Questo mi permetterebbe di avere un ViewModel che gestisce tutte le viste, il che significa che non avrei mai o quasi mai bisogno di ripetere gli attributi. – devuxer
L'unica limitazione è rappresentata dalle proprietà predefinite di ModelMetadata. Se hai bisogno di aggiungere ulteriori informazioni e creare un MyModelMetadata: ModelMetatdata avrai anche creato la tua ViewPage personalizzata con una proprietà MyModelMetadata personalizzata OPPURE lanciare ViewData.ModelMetadata all'interno di qualsiasi file .aspx o .ascx che usi. – jfar