2012-02-18 11 views
7

Acabo de empezar a usar ViewModels. ¿Pueden ver este código para ver si estoy siguiendo las mejores prácticas? ¿Hay algo fuera de lo común? ¿Harías la validación de manera diferente?Implementación de ViewModel en ASP.NET MVC: ¿es este código una práctica recomendada?

Lo sentimos si el código es extenso (hay tantas partes). Intenté que sea tan fácil de entender como sea posible.

Gracias!

Modelo

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

Respuesta

2

Una cosa que salta a mí es la siguiente:

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

Recuerde que Ver modelos son buenos para pasar datos a su controlador y la espalda a tu modelo. Le recomiendo que agregue una propiedad IsValid a su modelo de vista y luego establezca eso en verdadero en lugar de llamar a Response.Write. Entonces sólo tiene que añadir esto a la parte superior de la vista parcial:

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

También puede llegar a ModelState en su opinión, pero algunos podrían argumentar que no es una buena práctica. Sin embargo, si usted no desea añadir una propiedad a su modelo de algo que sólo puede ver en la vista sólo se puede hacer esto:

@if (ViewData.ModelState.IsValid) 

Otra cosa es que nitpicky atributos de validación MVC son típicamente utilizan para la validación en la UI. Esta validación se puede reutilizar en otras áreas, pero en algunos casos no es óptima. Además, es posible que no siempre puedas modificar tus modelos de dominio. Por lo tanto, para mantener toda mi validación de la interfaz de usuario en un solo lugar por lo general envolver mis modelos de dominio en mis modelos de vista para que pueda obtener algo como esto:

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

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

Esto puede parecer redundante y no es siempre la pena el esfuerzo pero es una buena práctica considerar al usar modelos de dominio de Entity Framework u otras clases que son difíciles o imposibles de modificar.

+0

Realmente buenos puntos. Buena idea sobre la creación de una propiedad IsValid. – SaltProgrammer

1

, diría que su aplicación modelo de vista es bastante estándar. Está utilizando ViewModel para actuar como el objeto intermedio entre su Vista y su Modelo de Dominio. Lo cual es una buena práctica.

Lo único que me cansaría es cómo maneja los errores del Modelo, y también su ViewModel debería tener algunos atributos. Por ejemplo, es posible que desee utilizar el RegularExpressionAttribute Clase:

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

Al final esto generalmente nunca funciona. Los modelos casi siempre terminan teniendo datos que no desea mostrar al usuario. Ahora no puedes hacer el editor de los modelos, y corres el riesgo de publicarlos y publicarlos en presentaciones. Sé que es una gran cantidad de mapas, pero he descubierto que generalmente es mejor tener modelos de vista 'simple' –

+0

Buena idea sobre el uso de atributos RegExp adicionales. – SaltProgrammer

+0

¿El modelo de cliente realmente necesita anotaciones para verificar la validez? Creo que solo ViewModel necesita los atributos de Requisito. –

2

Apenas me estoy acostumbrando a MVC, pero ayer investigué sobre este mismo tema y llegué a la conclusión de que uno no debería incluir directamente un objeto modelo en el ViewModel. Por lo tanto, tengo entendido que sería una mala práctica incluir su modelo de cliente directamente en el modelo de CustomerView.

En su lugar, desea enumerar cada una de las propiedades de CustomerModel que desea incluir en su ViewModel. A continuación, o bien desea asignar manualmente los datos de CustomerModel a la CustomerViewModel o utilizar una herramienta como AutoMapper la que lo hace automáticamente con una línea de código como el interior de su método de acción:

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

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

    return View(model); 
} 

En este caso, Mapper.Map devolverá un ClienteViewModel que puede pasar a su Vista.

También tendrá que incluir lo siguiente en su método Application_Start:

Mapper.CreateMap<CustomerModel, CustomerViewModel>(); 

En general me pareció AutoMapper bastante fácil para llegar al trabajo. Es automático cuando los nombres de los campos coinciden, si no lo hacen o si tiene un objeto anidado, puede especificar esas asignaciones en la línea CreateMap. Así que si su CustomerModel utiliza un objeto de dirección en lugar de las propiedades individuales, se podría hacer esto:

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

Por favor, que alguien me corrija si estoy equivocado como yo estoy haciendo mi cabeza alrededor de MVC también.

Cuestiones relacionadas