2012-02-18 6 views
7

Ho appena iniziato a utilizzare ViewModels. Ragazzi potete controllare questo codice per vedere se sto seguendo le migliori pratiche? C'è qualcosa fuori dall'ordinario? Vuoi fare la validazione in modo diverso?Implementazione ViewModel in ASP.NET MVC - Questo codice è la migliore prassi?

Scusate se il codice è lungo (ci sono così tante parti). Ho cercato di renderlo il più facile da capire possibile.

Grazie!

Modello

public class CustomerModel 
    { 
    [Required(ErrorMessage="Primer nombre!")] 
    public string FirstName { get; set; } 

    [Required(ErrorMessage="Segundo nombre!")] 
    public string LastName { get; set; } 

    [Required(ErrorMessage="Edad")] 
    public int? Age { get; set; } 

    public string State { get; set; } 
    public string CountryID { get; set; } 

    [Required(ErrorMessage="Phone Number")] 
    public string PhoneNumber { get; set; } 
    } 

ViewModel

public class CustomerViewModel 
    { 
    public CustomerModel Customer { get; set; } 

    public string Phone1a { get; set; } 
    public string Phone1b { get; set; } 
    public string Phone1c { get; set; } 
    } 

controller

public ActionResult Index() 
    { 
     CustomerViewModel Customer = new CustomerViewModel() 
     { 
     Customer = new CustomerModel(), 
     }; 


     return View(Customer); 
    } 


    [HttpPost] 
    public ActionResult Index(CustomerViewModel c) 
    { 

     //ModelState.Add("Customer.PhoneNumber", ModelState["Phone1a"]); 

     // Let's manually bind the phone number fields to the PhoneNumber properties in 
     // Customer object. 
     c.Customer.PhoneNumber = c.Phone1a + c.Phone1b + c.Phone1c; 

     // Let's check that it's not empty and that it's a valid phone number (logic not listed here) 
     if (!String.IsNullOrEmpty(c.Customer.PhoneNumber)) 
     { 
     // Let's remove the fact that there was an error! 
     ModelState["Customer.PhoneNumber"].Errors.Clear(); 
     } // Else keep the error there. 

     if (ModelState.IsValid) 
     { 
     Response.Write("<H1 style'background-color:white;color:black'>VALIDATED</H1>"); 
     } 
     return View("Index", c); 
    } 

    } 

V iew

@model MVVM1.Models.CustomerViewModel 

@using (Html.BeginForm("Index", "Detail")) 
{ 
    <table border="1" cellpadding="1" cellspacing="1"> 
    <tr> 
     <td>@Html.LabelFor(m => m.Customer.FirstName)</td> 
     <td> 
     @Html.TextBoxFor(m => m.Customer.FirstName) 
     @Html.ValidationMessageFor(m => m.Customer.FirstName) 
     </td> 
    </tr> 
    <tr> 
     <td>@Html.LabelFor(m => m.Customer.LastName)</td> 
     <td> 
     @Html.TextBoxFor(m => m.Customer.LastName) 
     @Html.ValidationMessageFor(m => m.Customer.LastName) 
     </td> 
    </tr> 
    <tr> 
     <td>@Html.LabelFor(m => m.Customer.Age)</td> 
     <td> 
     @Html.TextBoxFor(m => m.Customer.Age) 
     @Html.ValidationMessageFor(m => m.Customer.Age) 
     </td> 
    </tr> 

    <tr> 
     <td>@Html.LabelFor(m => m.Customer.PhoneNumber)</td> 
     <td width="350"> 
     @Html.TextBoxFor(m => m.Phone1a, new { size="4", maxlength="3" }) 
     @Html.TextBoxFor(m => m.Phone1b) 
     @Html.TextBoxFor(m => m.Phone1c) 
     <div> 
     @Html.ValidationMessageFor(m => m.Customer.PhoneNumber) 
     </div> 
     </td> 
    </tr> 
    <tr> 
     <td></td> 
     <td> 
     <input type="submit" value="Submit" /></td> 
    </tr> 
    </table> 
} 

risposta

2

Una cosa che salta fuori di me è questo:

if (ModelState.IsValid) 
    { 
    Response.Write("<H1 style'background-color:white;color:black'>VALIDATED</H1>"); 
    } 
    return View("Index", c); 

Ricordate che vista modelli sono buone per il passaggio di dati al controller e ritorno al tuo modello. Ti consiglio di aggiungere una proprietà IsValid al tuo modello di visualizzazione e di impostarla su true invece di chiamare Response.Write. Poi basta aggiungere questo alla parte superiore della vostra visione parziale:

@if (Model.IsValid) 
{ 
    <H1 style'background-color:white;color:black'>VALIDATED</H1> 
} 

Si può anche arrivare a ModelState nella vostra vista, ma alcuni sostengono che non è una buona pratica. Tuttavia, se non si vuole aggiungere una proprietà al modello per qualcosa che si può vedere solo a suo avviso si può semplicemente fare questo:

@if (ViewData.ModelState.IsValid) 

Un'altra cosa nitpicky è che gli attributi di validazione MVC sono tipicamente usati per la convalida sull'interfaccia utente. Questa convalida può essere riutilizzata in altre aree, ma in alcuni casi è sub-ottimale. Inoltre, potresti non essere sempre in grado di modificare i tuoi modelli di dominio. Pertanto, per mantenere tutta la mia convalida interfaccia utente in un unico luogo di solito avvolgere le mie modelli di dominio nei miei modelli vista in modo da ottenere qualcosa di simile:

public class CustomerViewModel      
{      
    public CustomerModel Customer { get; set; } 

    [Required(ErrorMessage="Primer nombre!")]       
    public string FirstName 
    { 
     get { return Customer.FirstName; } 
     set { Customer.FirstName = value; } 
    } 
... 

Questo può sembrare ridondante e non è sempre vale la pena ma è una buona pratica considerare quando si utilizzano i modelli di dominio di Entity Framework o altre classi che sono difficili o impossibili da modificare.

+0

Davvero buoni punti. Buona idea sulla creazione di una proprietà IsValid. – SaltProgrammer

1

direi l'implementazione ViewModel è abbastanza standard. Stai usando ViewModel per agire da oggetto intermedio tra la tua vista e il tuo modello di dominio. Che è una buona pratica

L'unica cosa di cui mi stanco è il modo in cui gestisci gli errori del modello e anche il tuo ViewModel dovrebbe avere alcuni attributi. Per esempio, si potrebbe desiderare di utilizzare il RegularExpressionAttribute Classe:

public class CustomerViewModel 
    { 
    public CustomerModel Customer { get; set; } 

    [RegularExpression(@"^\d{3}$")] 
    public string Phone1a { get; set; } 
    [RegularExpression(@"^\d{3}$")] 
    public string Phone1b { get; set; } 
    [RegularExpression(@"^\d{4}$")] 
    public string Phone1c { get; set; } 
    } 
+2

Alla fine questo di solito non funziona mai. I modelli finiscono quasi sempre per avere dati che non vuoi mostrare all'utente. Ora non puoi semplicemente creare editor per i modelli e rischi di postare e pubblicare post su submission. So che è un sacco di mappature, ma ho scoperto che di solito è meglio avere modelli di visualizzazione "semplici" –

+0

Buona idea sull'utilizzo di attributi RegExp aggiuntivi. – SaltProgrammer

+0

Il CustomerModel ha effettivamente bisogno di annotazioni per verificare la validità? Penso che solo il ViewModel abbia bisogno degli attributi Requisito. –

2

Sto acquisendo il controllo di MVC da solo, ma ho ricercato lo stesso argomento ieri ed è giunto alla conclusione che non si dovrebbe includere direttamente un oggetto modello nel ViewModel. Quindi la mia comprensione è che sarebbe una cattiva pratica includere il proprio CustomerModel direttamente in CustomerViewModel.

Invece, si desidera elencare ciascuna proprietà da CustomerModel che si desidera includere nel ViewModel. Poi si sia desidera mappare manualmente i dati dal CustomerModel al CustomerViewModel o utilizzare uno strumento come automapper che lo fa automaticamente con una linea di codice come questo all'interno del vostro metodo di azione:

public ViewResult Example() 
{ 
    // Populate/retrieve yourCustomer here 
    Customer yourCustomer = new CustomerModel(); 

    var model = Mapper.Map<CustomerModel, CustomerViewModel>(yourCustomer); 

    return View(model); 
} 

In questo caso, Mapper.Map restituirà un CustomerViewModel che puoi passare alla tua vista.

Sarà inoltre necessario includere quanto segue nel metodo Application:

Mapper.CreateMap<CustomerModel, CustomerViewModel>(); 

In generale ho trovato automapper abbastanza facile per andare al lavoro. È automatico quando i nomi dei campi corrispondono, se non lo fanno o hai un oggetto nidificato, puoi specificare quei mapping nella linea CreateMap. Così, se il CustomerModel utilizza un oggetto indirizzo invece di singole proprietà, si dovrebbe fare questo:

Mapper.CreateMap<CustomerModel, CustomerViewModel>() 
    .ForMember(dest => dest.StreetAddress, opt => opt.MapFrom(src => src.Address.Street)); 

Si prega di qualcuno mi corregga se sbaglio come sto solo ottenere la mia testa intorno MVC pure.

Problemi correlati