通常我在将数据提交到数据库之前在action方法中验证我的模型.
[HttpPost] public ActionResult MyActionMethod(MyModelType model){ if (ModelState.IsValid){ //commit changes to database... return View("SuccessView",model); } return View(model); }
但在一些非常罕见的情况下,我需要在提交模型时在业务层中执行一些额外的验证.如果发生验证错误,我想在业务层中引发异常并使用该异常返回带有验证错误的视图.
我正在寻找一种方法来实现它,而无需改变我的控制器中的任何代码.所以我正在寻找避免这种情况的方法:
[HttpPost] public ActionResult MyActionMethod(MyModelType model){ if (ModelState.IsValid){ try { //commit changes to database... } catch (ValidationException e){ ModelState.AddModelError(...); return View(model); } return View("SuccessView",model); } return View(model); }
有没有办法做到这一点?
我正在考虑一个捕获ValidationExceptions的动作过滤器,并在常规[HandleError]过滤器启动之前返回带有验证错误的合适视图.这样的事情可能吗?
解决方法
我在ASP.NET MVC源代码中搜索了一下后才找到解决方案:
它不能用动作过滤器完成,因为在调用动作方法之前和之后调用它,但它实际上并不包含动作方法调用.
但是,它可以使用自定义ActionMethodInvoker完成:
public class CustomActionInvoker : ControllerActionInvoker { protected override ActionResult InvokeActionMethod(ControllerContext controllerContext,ActionDescriptor actionDescriptor,System.Collections.Generic.IDictionary<string,object> parameters) { try { //invoke the action method as usual return base.InvokeActionMethod(controllerContext,actionDescriptor,parameters); } catch(ValidationException e) { //if some validation exception occurred (in my case in the business layer) //mark the modelstate as not valid and run the same action method again //so that it can return the proper view with validation errors. controllerContext.Controller.ViewData.ModelState.AddModelError("",e.Message); return base.InvokeActionMethod(controllerContext,parameters); } } }
然后,在控制器上:
protected override IActionInvoker CreateActionInvoker() { return new CustomActionInvoker(); }