从 ActionFilterAttribute 返回视图及其模型

发布于 2024-08-10 01:53:09 字数 2587 浏览 1 评论 0原文

在强类型视图上使用内置验证帮助程序实现错误处理时,通常会在控制器中创建一个 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<Models.Entities.Message>" %>

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

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

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

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

<% } %>



我以 ActionFilterAttribute 的形式实现了一个简单的错误处理程序,它将能够重定向到通用错误视图,或者重定向到引发异常的视图,并让验证帮助程序发挥作用。

下面是我的 ActionFilterAttribute 的外观:

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

重定向到引发异常的视图相当简单。但关键在于:为了使验证助手正常工作,您需要提供视图及其模型。

如何返回引发异常的视图并为该视图提供相应的模型? (在本例中Models.Entities.Message)。

When implementing error-handling using the built-in validation-helpers on a strongly-typed view, you usually create a try/catch block within the controller and return a view with it's corresponding model as a parameter to the View() method:

The controller

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

The view

<%@ 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>

<% } %>

I've implemented a simple error-handler in the form of an ActionFilterAttribute, which will be able to either redirect to a generic error view, or redirect to the view which threw an exception, and let the validation-helpers spring to life.

Here's how my ActionFilterAttribute looks:

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

Redirecting to the view which threw the exception is fairly simple. But here's the kicker: In order for the validation helpers to work, you need to provide the view with it's model.

How would you return the view which threw an exception and provide the view with it's corresponding model? (In this case Models.Entities.Message).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

淡看悲欢离合 2024-08-17 01:53:09

我让它工作了!

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

这是逻辑的完全分离。控制器中只有最基本的内容。

I got it to work!

For some odd reason, all I needed to do was to pass on the ViewData to a new ResultView.

Here's the complete code:

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

Usage

Here's how you would use the attribute on a controller-action, to redirect to the same view (with it's associated model) to enable standard validation-helpers to kick in, when an exception occurs:

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

And here's how you would use the attribute, to redirect to a generic view, when an exception occurs:

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

This is a complete separation of logic. Nothing in the controller but the very basics.

染柒℉ 2024-08-17 01:53:09

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

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

        ...
    }

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

我建议您阅读这篇博客关于这个问题。

Since you inherit from ActionFilterAttribute From OnActionExecuting, you can grab your model.

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

        ...
    }

But there is already HandleError defined in MVC system, why don't you use this one instead of baking your own.

I suggest you read this blog on this issue.

随遇而安 2024-08-17 01:53:09

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

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

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

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

If your action throws exception, there's no way to pass the model to the view since the model is not probably created yet - or not fully created. That's probably why the result is null. You can't rely on the data after exception was thrown.

But you can pass pass "default" model to your action filter like this:

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

This way your filter will pass this "error model" that you explicitely set to be displayed when an error happened.

等数载,海棠开 2024-08-17 01:53:09
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();
    }
  }
}

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

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

The details of the model are already present in modelstate. Any errors should also already be present in modelstate. Your exception handler only needs to handle the case where you want to redirect to a generic error page. Better / more obvious is to throw the attribute away and if you want to redirect in the catch, return a redirect result.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文