7

我刚刚开始使用 ViewModels。你们可以查看此代码以查看我是否遵循最佳实践吗?有什么不正常的吗?你会以不同的方式进行验证吗?

对不起,如果代码很长(它有很多部分)。我试图让它尽可能容易理解。

谢谢!

模型

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

视图模型

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

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

控制器

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

  }

看法

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

3 回答 3

2

让我印象深刻的一件事是:

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

请记住,视图模型非常适合将数据传递给您的控制器并返回给您的模型。我建议您将 IsValid 属性添加到您的视图模型,然后将其设置为 true,而不是调用 Response.Write。然后只需将其添加到局部视图的顶部:

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

您也可以在您的视图中访问 ModelState,但有些人会认为这不是最佳实践。但是,如果您不想将属性添加到您的模型中,您可以在视图中看到您可以这样做:

@if (ViewData.ModelState.IsValid)

另一个挑剔的事情是 MVC 验证属性通常用于 UI 上的验证。这种验证可以在其他领域重复使用,但在某些情况下是次优的。此外,您可能并不总是能够修改您的域模型。因此,为了将我的所有 UI 验证保存在一个地方,我通常将我的域模型包装在我的视图模型中,这样你就会得到这样的结果:

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

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

这似乎是多余的,并不总是值得付出努力,但在使用实体框架域模型或其他难以或不可能修改的类时,这是一个很好的做法。

于 2012-02-18T03:47:30.327 回答
2

我自己刚刚掌握了 MVC 的窍门,但我昨天研究了同样的主题并得出结论,不应该直接在 ViewModel 中包含模型对象。所以我的理解是,将您的 CustomerModel 直接包含在 CustomerViewModel 中是一种不好的做法。

相反,您希望列出您希望包含在 ViewModel 中的 CustomerModel 中的每个属性。然后,您要么想手动将数据从 CustomerModel 映射到 CustomerViewModel,要么使用 AutoMapper 之类的工具,它会在您的操作方法中使用如下代码行自动执行此操作:

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

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

    return View(model);
}

在这种情况下,Mapper.Map 将返回一个 CustomerViewModel,您可以将其传递给您的视图。

您还需要在 Application_Start 方法中包含以下内容:

Mapper.CreateMap<CustomerModel, CustomerViewModel>();

总的来说,我发现 AutoMapper 很容易上手。当字段名称匹配时,它是自动的,如果它们不匹配或者您有嵌套对象,您可以在 CreateMap 行中指定这些映射。因此,如果您的 CustomerModel 使用 Address 对象而不是单个属性,您可以这样做:

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

如果我错了,请任何人纠正我,因为我也只是在了解 MVC。

于 2012-02-23T15:06:06.750 回答
1

我会说您的 ViewModel 实现非常标准。您正在使用 ViewModel 作为您的视图和域模型之间的中间对象。这是一个很好的做法。

我唯一会厌倦的是你如何处理模型错误,而且你的 ViewModel 应该有一些属性。例如,您可能想要使用RegularExpressionAttributeClass:

  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; }
  }
于 2012-02-18T02:48:47.710 回答