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

时间:2009-11-03 19:18:38

标签: c# asp.net-mvc asp.net-mvc-routing

在强类型视图上使用内置验证助手实现错误处理时,通常在控制器中创建一个try / catch块,并返回一个视图,其中相应的模型作为{{1的参数}} 方法:


控制器

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);
        }
    }
}



我已经以ActionFilterAttribute的形式实现了一个简单的错误处理程序,它可以重定向到一般错误视图,或者重定向到引发异常的视图,并让验证助手恢复生机。 / p>

以下是我的ActionFilterAttribute的外观:

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

<%= Html.ValidationSummary("Fill out fields marked with *") %>

<% using (Html.BeginForm()) { %>

    <div><%= Html.TextBox("MessageText") %></div>

    <div><%= Html.ValidationMessage("MessageText", "*") %></div>

<% } %>

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

如何返回引发异常的视图并提供具有相应模型的视图? (在这种情况下为public class ErrorLoggingAttribute : ActionFilterAttribute, IExceptionFilter { private Boolean _onErrorRedirectToGenericErrorView; /// <param name="onErrorRedirectToGenericErrorView"> /// True: redirect to a generic error view. /// False: redirect back the view which threw an exception /// </param> 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; } } } )。

4 个答案:

答案 0 :(得分:6)

我得到了它的工作!

出于某些奇怪的原因,我需要做的就是将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;
    }
}


用法


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

[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 });
}

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

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


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

答案 1 :(得分:1)

由于您从OnActionExecuting的ActionFilterAttribute继承,您可以获取模型。

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

        ...
    }

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

我建议你在这个问题上阅读blog

答案 2 :(得分:0)

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

但是你可以将传递“默认”模型传递给你的动作过滤器:

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

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

答案 3 :(得分:0)

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();
    }
  }
}

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