【问题标题】:How to deal with Model and ViewModel validation in ASP.Net MVC如何处理 ASP.Net MVC 中的 Model 和 ViewModel 验证
【发布时间】:2014-05-16 17:05:45
【问题描述】:

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

我现在拥有的:

// 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 映射后手动检查模型有效性我在这里找到了相同的想法http://blogs.msdn.com/b/simonince/archive/2010/12/07/view-model-versus-domain-entity-validation-with-mvc.aspx . (手动验证调用对我有用)

在这种情况下,我应该怎么做才能同时支持 API 和 UI 中的验证?

可能是应用架构不够好,我很高兴得到任何建议,但我现在无权更改任何内容。

【问题讨论】:

    标签: asp.net-mvc validation viewmodel


    【解决方案1】:

    正如您已经知道(或想通)的那样,验证可以、将会而且应该在多个层面上进行。

    您需要做的第一件事是区分什么应该是 UI 验证和什么应该是业务规则验证。

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

    假设我的规则如下:

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

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

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

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

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

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

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

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

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

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

    【讨论】:

    • 修复了我在问题中添加了更多源代码并解决了模型上手动调用验证的问题(来自sample which I linked above)这是一个愚蠢的错误我试图在手动验证中使用另一个模型(此代码不在我的存储库中)。
    • 感谢您的回答。一般来说,我明白了你的想法(模型包含更复杂的业务规则和依赖于数据库的验证;视图模型 - 简单验证),我只需要实现一点。如果 ModelView 包含所有简单规则并且 ViewModel 仅在 UI 控制器中有效,我应该如何在 API 控制器中验证模型?我可以提出两种方法:1. 将简单的验证属性移动到模型 2. 对 UI 和 API 使用相同的控制器(不确定这是个好主意,我的老板会支持它) 3. 以某种方式重复验证 4. ?跨度>
    猜你喜欢
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-04
    • 2011-09-22
    • 1970-01-01
    • 2017-05-31
    相关资源
    最近更新 更多