2011-05-14 81 views
5

(同样,一个MVC的验证问题,我知道,我知道...)ASP.NET MVC3 Automapper视图模型/型号查看验证

我想使用AutoMapper(http://automapper.codeplex.com/)来验证字段我创建查看不在数据库中的字段(因此不在我的DataModel中)。

示例:我有一个帐户/创建视图,用户可以创建一个新帐户,并且我想要一个密码和ConfirmPassword字段,因此用户必须输入两次密码才能确认。

在数据库中的客户表看起来像这样:

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

我已经生成的ADO.NET实体数据模型,并从,我生成使用ADO.NET自跟踪实体发电机模型。

我还写了一个自定义AccountViewModel验证注释,如[必需的]。

所以,总结一下,这是我的项目结构:

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 

我AccountViewModel的代码如下所示:

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

现在,我创建视图看起来是这样的:

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

我的代码失败了,因为我的模型当然不包含ConfirmPassword字段。 现在,一只小鸟向我耳语,AutoMapper可以为我解决这个问题。但我无法弄清楚...有人可以告诉我,我必须做些什么来完成这项工作?我的AccountController看起来像现在这样:

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(); 
      } 
     } 

但是,这并不工作...(得到了http://weblogs.asp.net/shijuvarghese/archive/2010/02/01/view-model-pattern-and-automapper-in-asp-net-mvc-applications.aspx的例子)

任何人都可以请赐教在这个问题上?非常感谢你,我的道歉文本和数百篇关于同一主题提问的墙......

回答

18

有关代码几句话:

  1. 您的看法是强类型(@model声明)到Account模型,而它应该被输入到AccountViewModel视图模型(如果您没有在视图中使用它,则声明视图模型没有意义)。
  2. AutoMapper不用于验证,仅用于在类型之间转换
  3. 您无需在控制器内为视图模型(AccountViewModel)声明readonly字段。您可以在GET操作中实例化视图模型,并让默认模型联编程序将其实例化为POST操作的操作参数。
  4. 你应该为整个应用程序(最好在Application_Start)做AutoMapper配置(Mapper.CreateMap<TSource, TDest>)只有一次,而不是一个控制器动作
  5. 没有在您的视图模型中没有电子邮件字段这可能是更新的缘故内失败(特别是如果该字段在数据库所需)

因此,这里是你的代码可能看起来怎么样:

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

达林,你救了我一次。这正是我现在一直在寻找的一段时间。非常感谢你! – Matthias 2011-05-14 20:16:01

3

取代第一线的你

01查看
@model AutoMapperTest.AccountViewModel 

此外,您只需调用一次Mapper.CreateMap以获取应用程序的生命周期(例如,在应用程序启动)