2011-05-14 17 views
5

(Una vez más, una cuestión de validación MVC. Lo sé, lo sé ...)ASP.NET MVC3 AutoMapper modelo de vista/modelo Ver validación

Me gustaría utilizar AutoMapper (http://automapper.codeplex.com/) para validar campos en mi Crear Vistas de campos que no están en mi base de datos (y por lo tanto no en mi DataModel).

Ejemplo: Tengo una Cuenta/Crear vista para que los usuarios creen una nueva cuenta y deseo tanto una contraseña como un campo Confirmar contraseña para que los usuarios tengan que ingresar su contraseña dos veces para confirmarla.

la tabla de cuentas en la base de datos tiene el siguiente aspecto:

Account[Id(PK), Name, Password, Email] 

he generado un modelo de datos de entidad de ADO.NET y de eso, me genera los modelos usando una Entidad ADO.NET Generador de seguimiento automático .

También he escrito un AccountViewModel personalizado para anotaciones de validación como [Obligatorio].

tanto, para resumir, este es mi estructura del proyecto:

Controllers: 
    AccountController 

Models: 
    Database.edmx (auto-generated from database) 
    Model.Context.tt (auto-generated from edmx) 
    Model.tt (auto-generated from edmx) 
    AccountViewModel.cs 

Views: 
    Account 
     Create.cshtml 

El código de mi AccountViewModel se ve así:

public class AccountViewModel 
    { 
     public int Id { get; set; } 

     [Required] 
     public string Name { get; set; } 

     [Required] 
     public string Password { get; set; } 

     [Required] 
     [Compare("Password")] 
     public string ConfirmPassword { get; set; } 
    } 

Ahora, mis Crear vista se parece a esto:

@model AutoMapperTest.Models.Account 
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 
@using (Html.BeginForm()) 
{ 
    @Html.ValidationSummary(true) 
    <fieldset> 
     <legend>Account</legend> 
     <div class="editor-label"> 
      Name 
     </div> 
     <div class="editor-field"> 
      @Html.TextBox("Name") 
      @Html.ValidationMessageFor(model => model.Name) 
     </div> 
     <div class="editor-label"> 
      Email 
     </div> 
     <div class="editor-field"> 
      @Html.TextBox("Email") 
      @Html.ValidationMessageFor(model => model.Email) 
     </div> 
     <div class="editor-label"> 
      Password 
     </div> 
     <div class="editor-field"> 
      @Html.TextBox("Password") 
      @Html.ValidationMessageFor(model => model.Password) 
     </div> 
     <div class="editor-label"> 
      Confirm your password 
     </div> 
     <div class="editor-field"> 
      @Html.TextBox("ConfirmPassword"); 
      @Html.ValidationMessageFor(model => model.ConfirmPassword) 
     </div> 
     <p> 
      <input type="submit" value="Create" /> 
     </p> 
    </fieldset> 
} 
<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

Mi código falla porque mi modelo no contiene el campo ConfirmPassword por supuesto. Ahora, un pajarito me susurró que el AutoMapper podría arreglar eso por mí. Pero no puedo resolverlo ... ¿Puede alguien decirme qué tengo que hacer para que esto funcione? Mi AccountController se parece a esto ahora:

private readonly AccountViewModel _viewModel = new AccountViewModel(); 
private readonly DatabaseEntities _database = new DatabaseEntities(); 

// 
     // GET: /Account/Create 

     public ActionResult Create() 
     { 
      Mapper.CreateMap<AccountViewModel, Account>(); 
      return View("Create", _viewModel); 
     } 

     // 
     // POST: /Account/Create 

     [HttpPost] 
     public ActionResult Create(AccountViewModel accountToCreate) 
     { 
      try 
      { 
       if (ModelState.IsValid) 
       { 
        var newAccount = new Account(); 
        Mapper.Map(accountToCreate, newAccount); 
        _database.Account.AddObject(newAccount); 
     _database.SaveChanges(); 
       } 

       return RedirectToAction("Index"); 
      } 
      catch 
      { 
       return View(); 
      } 
     } 

Pero esto no funciona ... (Tienes el ejemplo de http://weblogs.asp.net/shijuvarghese/archive/2010/02/01/view-model-pattern-and-automapper-in-asp-net-mvc-applications.aspx)

Puede alguien por favor me ilumine sobre este asunto? Muchas gracias, y mis disculpas por el muro de texto y los cientos de preguntas sobre el mismo tema ...

Respuesta

18

algunas observaciones sobre su código:

  1. Su punto de vista es fuertemente tipado (@model declaración) al modelo Account, mientras que debe escribirse en el modelo de vista AccountViewModel (no tiene sentido declarar un modelo de vista si no lo usa en la vista).
  2. AutoMapper no se utiliza para la validación, sólo para la conversión entre tipos
  3. No es necesario declarar un campo readonly para su modelo de vista (AccountViewModel) dentro del controlador. Puede crear una instancia del modelo de vista dentro de la acción GET y dejar el encuadernador de modelo predeterminado instanciarlo como argumento de acción para la acción POST.
  4. Usted debe hacer la configuración AutoMapper (Mapper.CreateMap<TSource, TDest>) sólo una vez para toda la aplicación (idealmente en Application_Start) y no dentro de una acción de controlador
  5. No hay campo de correo electrónico en el modelo de vista que podría ser la razón para que la actualización fallar (especialmente si se requiere este campo en su base de datos)

Así que aquí es como su código podría ser:

public ActionResult Create() 
{ 
    var model = new AccountViewModel(); 
    return View("Create", model); 
} 

[HttpPost] 
public ActionResult Create(AccountViewModel accountToCreate) 
{ 
    try 
    { 
     if (ModelState.IsValid) 
     { 
      var newAccount = Mapper.Map<AccountViewModel, Account>(accountToCreate); 
      _database.Account.AddObject(newAccount); 
      _database.SaveChanges(); 
     } 
     return RedirectToAction("Index"); 
    } 
    catch 
    { 
     return View(); 
    } 
} 
+0

Darin, me has salvado una vez más. Esto es exactamente lo que he estado buscando desde hace bastante tiempo. ¡Muchas gracias! – Matthias

3

reemplazar la primera línea de ver con

@model AutoMapperTest.AccountViewModel 

También solo necesita llamar a Mapper.CreateMap una vez para la vida útil de la aplicación (p. al inicio de la aplicación)

Cuestiones relacionadas