使用 MVC 清理和验证视图模型,如何

本文关键字:视图 模型 如何 验证 MVC 使用 | 更新日期: 2023-09-27 18:33:34

我有一些关于如何通过 asp.net mvc的最佳实践实现DDD原则的最佳方法的问题。实际上,我想知道,您是如何进行验证的(在视图模型或模型中(?

我有这个域模型和视图模型:

public class Product {
   public int Id { get; protected set; }
   public string Name { get; set; }
   public decimal Price { get; set; }
   public int Stock { get; set; }
   public Category Category { get; set; }
   public Supplier Supplier { get; set; }
   public string Code { get; set; } // it has to be unique
}
public class ProductViewModel {
   public int Id { get; set; }
   /* other simple properties */
   public int IdCategory { get; set; }
   public int IdSupplier { get; set; }
   public string Code { get; set; } 
}

还行。该模型与 NHibernate 映射并且工作正常。我想知道,是否最好为 ViewModel 或 DomainModel 创建验证?我的意思是,当我在 asp.net mvc 的操作上接收 ViewModel 时,我会验证它,但是如果我在 viewmodel 上添加业务规则,我会做错吗?我问这个是因为我知道最好将这些业务验证添加到我的域中,但是我应该在坚持之前对我的帖子进行两次验证吗?看看我在 asp.net MVC 上的操作:

[Post]
public ActionResult Update(ProductViewModel viewModel) {
  // what kind of validations should I do here? 
  if (invalid) {
    return View(viewModel);
  } 
  // how can I return the errors to my View?
  // Is here any best pratice to transform from ViewModel to Domain instance?
  Product product = ???
  _repository.Save(product);
  return RedirectToAction("Index");
}

有人可以通过代码做一个例子吗?

使用 MVC 清理和验证视图模型,如何

我会说你应该在两个级别执行验证。在您的视图模型中,您将执行表面验证,例如此字段是必需的,并且此字段必须具有以下格式,而在业务层中,您应该验证业务规则,例如用户名已存在,...

因此,让我们举一个典型的 POST 操作的示例:

[HttpPost]
public ActionResult Update(ProductViewModel viewModel) 
{
    if (!ModelState.IsValid) 
    {
        // The view model is invalid => redisplay the view in order
        // to show the error messages
        return View(viewModel);
    }    
    // at this stage we know that the view model is valid =>
    // now we can map it to a domain model that we want to update:
    Product product = Repository.GetModel(viewModel.Id);
    // I use AutoMapper (http://automapper.org/) to map between 
    // my domain models and my view models. In this example
    // we are updating only the properties of the domain model
    // that were part of the view model and that the user is allowed
    // to modify in this view => we are merging
    Mapper.Map<ProductViewModel, Product>(viewModel, product);
    // now we can process the domain model
    Repository.Update(product);
    return RedirectToAction("Index");
}

如果你想处理域模型错误,有不同的可能性。我个人喜欢TryXXX模式:

string errorMessage;
if (!Repository.TryUpdate(product, out errorMessage))
{
    // the business validation failed => add the error message to the modelstate
    // and redisplay the view
    ModelState.AddModelError("", errorMessage);
    return View(viewModel);
}

另一种可能性是将ModelState字典传递给业务层,并让它直接添加模型状态错误。这样,您可以再次简单地测试视图中的if (!ModelState.IsValid),以了解业务层中是否出了问题,并重新显示相同的视图以显示错误消息。

就视图模型中的验证而言,有不同的方法。您可以使用Microsoft的官方方式,即使用验证属性装饰视图模型属性。例如:

public class ProductViewModel 
{
    [Required]
    public string Foo { get; set; }
    ...
}

就个人而言,我不使用这些属性。我发现它们非常有限,尤其是当您想对依赖属性等进行更复杂的验证时。出于这个原因,我使用 FluentValidation.NET 它与MVC很好地集成 ASP.NET 并允许我轻松地对验证规则进行单元测试。

应用于视图模型的验证规则不一定与域模型的验证规则相同。通常,检查视图模型是否存在输入错误,并检查域模型是否存在业务规则违规。某些验证规则在两个模型中是相同的,这很好,因为您的域模型独立于视图模型,反之亦然。