从ActionFilterAttribute返回带有它的模型的视图

在强类型视图上使用内置validation助手实现error handling时,通常在控制器中创建一个try / catch块,并返回一个视图,其中相应的模型作为View()方法的参数:

控制器

 public class MessageController : Controller { [AcceptVerbs(HttpVerbs.Post)] public ActionResult Create(Models.Entities.Message message) { try { // Insert model into database var dc = new DataContext(); dc.Messages.InsertOnSubmit(message); dc.SubmitChanges(); return RedirectToAction("List"); } catch { /* If insert fails, return a view with it's corresponding model to enable validation helpers */ return View(message); } } } 

风景

 <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>   

我已经以ActionFilterAttribute的forms实现了一个简单的error handling程序,它可以重定向到一般的错误视图,或者重定向到引发exception的视图,并让validation助手恢复生机。

以下是我的ActionFilterAttribute的外观:

 public class ErrorLoggingAttribute : ActionFilterAttribute, IExceptionFilter { private Boolean _onErrorRedirectToGenericErrorView; ///  /// True: redirect to a generic error view. /// False: redirect back the view which threw an exception ///  public ErrorLoggingAttribute(Boolean onErrorRedirectToGenericErrorView) { _onErrorRedirectToGenericErrorView = onErrorRedirectToGenericErrorView; } public void OnException(ExceptionContext ec) { if (_onErrorRedirectToGenericErrorView) { /* Redirect back to the view where the exception was thrown and include it's model so the validation helpers will work */ } else { // Redirect to a generic error view ec.Result = new RedirectToRouteResult(new RouteValueDictionary { {"controller", "Error"}, {"action", "Index"} }); ec.ExceptionHandled = true; } } } 

重定向到抛出exception的视图非常简单。 但这里是踢球者:为了使validation助手工作,你需要为视图提供它的模型。

如何返回抛出exception的视图并提供具有相应模型的视图? (在本例中为Models.Entities.Message )。

我得到了它的工作!

出于某些奇怪的原因,我需要做的就是将ViewData传递给新的ResultView

这是完整的代码:

 public class ErrorLoggingAttribute : ActionFilterAttribute, IExceptionFilter { private String _controllerName, _actionName; private Boolean _redirectToGenericView = false; public ErrorLoggingAttribute() { } public ErrorLoggingAttribute(String actionName, String controllerName) { _controllerName = controllerName; _actionName = actionName; _redirectToGenericView = true; } void IExceptionFilter.OnException(ExceptionContext ec) { // log error if (_redirectToGenericView) { ec.Result = new RedirectToRouteResult(new RouteValueDictionary { {"controller", _controllerName}, {"action", _actionName} }); } else { ec.Result = new ViewResult { ViewName = ((RouteData) ec.RouteData).Values["action"].ToString(), TempData = ec.Controller.TempData, ViewData = ec.Controller.ViewData }; } ec.ExceptionHandled = true; } } 

用法

以下是如何在控制器操作上使用该属性,重定向到相同的视图( 使用它的关联模型),以便在发生exception时启用标准validation帮助程序:

 [ErrorLogging] [AcceptVerbs(HttpVerbs.Post)] public ActionResult Create(Models.Entities.Message message) { var dc = new Models.DataContext(); dc.Messages.InsertOnSubmit(message); dc.SubmitChanges(); return RedirectToAction("List", new { id = message.MessageId }); } 

以下是发生exception时如何使用该属性重定向到通用视图:

 [ErrorLogging("ControllerName", "ViewName")] [AcceptVerbs(HttpVerbs.Post)] public ActionResult Create(Models.Entities.Message message) 

这是一个完全的逻辑分离。 控制器中没有任何东西,但非常基础。

由于您从OnActionExecuting的ActionFilterAttributeinheritance,因此您可以获取模型。

  public override void OnActionExecuting(ActionExecutingContext filterContext) { var model = filterContext.Controller.ViewData.Model as YourModel; ... } 

但是在MVC系统中已经定义了HandleError,为什么不使用这个而不是烘焙自己的。

我建议你在这个问题上阅读这个博客 。

如果您的操作抛出exception,则无法将模型传递给视图,因为模型可能尚未创建 – 或者未完全创建。 这可能是结果为空的原因。 抛出exception后,您无法依赖数据。

但是您可以将传递“默认”模型传递给您的操作filter,如下所示:

 [ErrorLogging(new EmptyModel())] // or to create using Activator [ErrorLogging(typeof(EmptyModel))] // or even set view name to be displayed [ErrorLogging("modelerror", new EmptyModel())] 

这样,您的filter将通过您明确设置为在发生错误时显示的“错误模型”。

 public class MessageController : Controller { public ActionResult Create() { return View(); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Create( Message message ) { try { // Exceptions for flow control are so .NET 1.0 =) // ... your save code here } catch { // Ugly catch all error handler - do you really know you can fix the problem? What id the database server is dead!?! return View(); } } } 

模型的详细信息已经存在于模型状态中。 模型状态中也应该存在任何错误。 您的exception处理程序只需要处理您想要重定向到一般错误页面的情况。 更好/更明显的是抛弃属性,如果要在catch中重定向,则返回重定向结果。