如何在ASP.Net MVC中处理Model和ViewModel验证

时间:2014-05-16 17:05:46

标签: asp.net-mvc validation viewmodel

我有一个包含Model和ViewModel的ASP.Net MVC应用程序,这个应用程序具有通过不同控制器工作的UI和API接口,UI与ViewModel一起工作,API与Model一起工作。 ViewModel已经对数据注释进行了验证(C#属性),而Model现在没有验证,现在API允许将任何不一致的模型保存到DB。

我现在拥有的:

// Model
public class Contact
{
    public string Email { get; set; }
    ...
}

// ViewModel
public class CreateContactViewModel
{
    [Required(ErrorMessage = "*")]
    [EmailAddress(ErrorMessageResourceType = typeof(CreateContact), ErrorMessageResourceName = "Validation_invalid_email", ErrorMessage = null)]
   public string Email { get; set; }
   ...
}

// View
...
<div style="padding-bottom:13px;">
    @Html.TextBoxFor(x => x.Email, new { style = "width:405px;" })
    @Html.ValidationMessage("Email", new { style = "color:red;" })
</div>
...

// UI controller
[HttpPost]
public ActionResult Create(CreateContactViewModel model, GetContactsViewModel contactsModel)
{           
    /* Now validation work only on client side, should be fixed? */
    var newContact = new Contact()
    {           
    Email = model.Email,
        ...
    };

    UnitOfWork.ContactRepository.Insert(newContact);
    UnitOfWork.Save();

    return GetContactsList(contactsModel);
}

// API Controller
public class ContactsController : BaseApiController
{
    ...
    public IHttpActionResult Post(Contact contact)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        UnitOfWork.ContactRepository.Insert(contact);

        try
        {
            UnitOfWork.Save();
        }            
        catch (DbUpdateException)
        {
            if (ContactExists(contact.Id))
            {
                return Conflict();
            }
            else
            {
                throw;
            }
        }
        return Created(contact);
    }
    ...
}

我认为更好的方法是将验证属性移动到模型中(以及将来会添加更复杂的业务逻辑验证)并在从ViewModel映射后手动检查模型有效性我在这里找到了相同的想法{{3 }}。 (手动验证通话适用于我)

在这种情况下,我应该做些什么来支持API和UI中的验证?

可能应用程序架构不够好,我很高兴得到任何建议,但我现在还没有完全有权更改任何内容。

1 个答案:

答案 0 :(得分:3)

正如您已经知道的那样(或计算出来),验证可以,将来也应该发生在许多层面上。

您需要做的第一件事是将UI验证应该与业务规则验证区分开来。

假设我有一个注册<form>...</form>。在该表单中,我有一个简单的电子邮件文本框。

假设我的规则如下:

  • 电子邮件文本框是必填项
  • 电子邮件不应重复

我可以快速区分强制文本框应该是UI验证。

对于“无重复电子邮件”规则,这需要访问数据库以查看给定的电子邮件地址是否尚不存在。对我来说,这是一项业务规则验证。

基本上,我的RegisterViewModel将在email属性上设置[required]数据注释属性。这将负责UI验证。

提交后,我将使用Model.IsValid()验证我的ViewModel以进行服务器端验证。 一旦ViewModel没问题,我就会将ViewModel传递给API(或者有些人喜欢在将ViewModel发送到API之前将其转换为POCO)。

在API中,我会调用数据库并检查给定的电子邮件地址是否已经存在。

如果确实存在,则该方法将返回false(假设您的方法返回true或false)。

Controller将检查返回的值是否为false,并可能向UI添加一些错误。

如果它不存在,那就太好了!将ViewModel(如果之前尚未转换)转换为POCO(或称为Model对象),以便将其保存到数据库中。

在我的示例中(以及我的大多数POCO中)我很少有数据注释我通常将这些注释留给ViewModel,无论我需要什么更复杂的验证,我都会在API层中手动完成。