我有一个包含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中的验证?
可能应用程序架构不够好,我很高兴得到任何建议,但我现在还没有完全有权更改任何内容。
答案 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层中手动完成。