我对在 asp.net mvc 中用于进行业务规则验证的方法有疑问。
目前我有一个异常类,看起来像这样
public class ValidationException : Exception
{
private ModelStateDictionary State { get; set; }
public ValidationException(ModelStateDictionary state)
{
State = state;
}
public void MergeModelStates(ModelStateDictionary state)
{
state.Merge(this.State);
}
}
和一个看起来像这样的验证器
public void Validate(IEntity entity)
{
ModelStateDictionary state = new ModelStateDictionary();
if (entity.Contact != null && _service.GetBy(entity.Contact.Id) == null)
state.AddModelError("Contact", "Invalid Contact.");
if (entity.Title.Length > 8)
state.AddModelError("title", "Title is too long...");
... etc
if (!state.IsValid)
throw new ValidationException(state);
}
和一个执行类似操作的控制器
public ActionResult Add()
{
var entity = new InputModel;
try
{
TryUpdateMode(inputModel);
..... Send input to a Repository (Repository calls Validate(entity);
}
catch (ValidationException validationException)
{
validationException.MergeModelStates(this.ModelState);
TryUpdateModel(inputModel);
return View("Add",inputModel);
}
return View("List");
}
使用异常来做这样的事情是错误的吗?
有更好方法的例子吗?我真的不想将验证添加到模型实体本身。我见过的唯一其他方法是将控制器 ModelState 注入到存储库层,但这对我来说似乎很草率。
谢谢你的帮助
异常通常应该用于特殊情况,而不是处理程序正常执行期间可能经常发生的事情。造成这种情况的原因有很多——以下是我经常遇到的一些原因:
- 性能问题 - 异常通常是相当昂贵的操作 - 如果定期抛出异常,您的性能可能会受到影响。
- 处理未捕获的验证异常 - 如果您碰巧使用代码而不处理异常,您将显示验证错误直至“黄屏”或崩溃处理程序 - 可能不是最好的用户体验。
- 异常的结构方式无法提供良好的面向用户的信息。看一下异常类 - 没有太多设置可以提供良好的面向用户的信息,而您需要将信息转发回用户。每当我尝试以这种方式使用异常时,我都会得到一大堆带有附加属性的子类,而这些属性对于异常来说并没有多大意义。
我通常喜欢做的一种方法是提供一个公共 Validate 方法,该方法返回错误列表(但从不抛出异常本身),然后提供一个 Save 方法,该方法调用 Validate() 并在出现任何错误时抛出异常。您将行为从“如果模型无效则抛出”切换为“如果代码在模型处于无效状态时尝试保存则抛出”。
为了解决下面有关 Validate 与 Save 中抛出的性能的评论 - 在 Save() 中抛出将具有与在 Validate() 中抛出完全相同的性能损失。然而,关键的区别是这种情况永远不应该发生——您是在防止开发人员不正确地使用您的类,而不是使用异常作为验证方法。如果编写正确,调用 save 方法的代码应类似于:
ValidationResult result = obj.Validate();
if (result.IsValid) {
obj.Save();
} else {
// display errors to the user
}
仅当开发人员在保存之前忘记检查验证状态时才会引发异常。这样做的好处是既可以在不使用异常的情况下进行验证,又可以通过不允许保存无效实体来保护数据库。理想情况下,您根本不会捕获控制器中的异常,并让一般错误处理例程处理它,因为问题不再是用户输入,而是开发人员的错误。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)