19

我的 web.config 中有以下内容:

 <customErrors mode="On" defaultRedirect="Error">
  <error statusCode="404" redirect="Error/NotFound" />
</customErrors>

我有一个

 [HandleError]

在我的 HomeController 类的顶部。为了测试,我创建了一个简单地抛出异常的动作。. 它重定向到我的

 ErrorController/Index

方法,但是当它到达绑定到 HandleErrorInfo 的视图时,我的模型为空,所以我不知何故丢失了对错误的引用。

我确信它与错误在重定向中丢失有关,所以我想看看我是否遗漏了一些东西,以及是否有人建议我可以查看显示 Stacktrace 和错误消息的视图。

4

3 回答 3

25

我可以看到误解。你想要做的MVC事情和redirect控制器动作。

defaultRedirect它本身就是一种Web Form约定,因此受到限制。当您重定向到另一个控制器时,您将丢失您的HttpContext,从而丢失您的HandleErrorInfoObject

您的[HandleError]Attribute 需要View将其错误消息定向到。按照上面的示例,我假设您有一个Views/Error文件夹ErrorController,其中有一个Index视图。如果您希望您的过滤器上下文将HandleErrorInfo对象发送到该视图,

试试这个语法:

[HandleError(View="~/Views/Error/Index")]
Public class HomeController : Controller

但是记录呢?!?!?

我怀疑您的意图不仅仅是向用户显示错误堆栈。事实上,我怀疑你根本没有这样的意图。我怀疑您的真正目的是记录您的错误(可能是 db)并向您的用户显示一些乏味的消息。

到目前为止,我所解释的是“在我看来,显示未处理异常的最佳方法是什么”。该[HandleError]属性对此有好处。

但是当你想进入下一步(记录错误)时,你有几个选择:

1)覆盖您的基本控制器的 On Exception 方法;创建您自己的Controller从 MVC 控制器类继承但覆盖 On Exception 方法。这种方法可以与 [HandleError] 属性结合使用

2)创建自定义异常处理程序创建您自己的记录错误的异常处理程序。然后,您的异常处理程序可以调用选择的视图,或者可以与过滤器属性一起使用,[HandleError(order=2)]因为过滤器属性可以采用应用优先级的顺序参数。


Nitin Sawant询问错误视图是什么样的。这

@model System.Web.Mvc.HandleErrorInfo
<h2>Exception details</h2>
<p> Controller: @Model.ControllerName </p>
<p> Action: @Model.ActionName </p>
<p> Exception: @Model.Exception </p>
于 2013-05-08T04:33:12.240 回答
6

我做了类似于 maxlego 的事情来处理所有错误(不仅仅是那些发生在具有 HandleError 属性的控制器中的错误)。

我的 MvcApplication 类(在 global.asax.cs 中)有这个:

public class MvcApplication : HttpApplication
{
    // usual stuff here...

    protected void Application_Error(object sender, EventArgs e)
    {
        Server.HandleError(((MvcApplication)sender).Context);
    }
}

上面的代码使用了我的 MVC 库中有用的东西的扩展方法。有了这个,我不需要任何错误处理属性、customErrors 配置或自定义过滤器。相反,扩展方法将记录错误详细信息,然后调用适当的视图,或者:

  • 拒绝访问
  • 未找到
  • 内部服务器错误

使这项工作的扩展方法代码是:

public static class HttpServerUtilityExtensions
{
    private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

    public static void HandleError(this HttpServerUtility server, HttpContext httpContext)
    {
        var currentController = " ";
        var currentAction = " ";
        var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));

        if (currentRouteData != null)
        {
            if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
                currentController = currentRouteData.Values["controller"].ToString();

            if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
                currentAction = currentRouteData.Values["action"].ToString();
        }

        var exception = server.GetLastError();
        Logger.ErrorException(exception.Message, exception);

        var controller = DependencyResolver.Current.GetService<ErrorController>();
        var routeData = new RouteData();
        var action = "InternalServerError";

        if (exception is HttpException)
        {
            var httpEx = exception as HttpException;

            switch (httpEx.GetHttpCode())
            {
                case 404:
                    action = "NotFound";
                    break;

                case 401:
                    action = "AccessDenied";
                    break;
            }
        }

        httpContext.ClearError();
        httpContext.Response.Clear();
        httpContext.Response.StatusCode = exception is HttpException ? ((HttpException)exception).GetHttpCode() : 500;
        httpContext.Response.TrySkipIisCustomErrors = true;

        routeData.Values["controller"] = "Error";
        routeData.Values["action"] = action;

        controller.ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction);
        ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
    }
}

请注意,上面使用 NLog 记录错误详细信息,但可以轻松更改以支持其他内容。此外,此方法在解析 ErrorController 时尊重您的 IoC 容器。

于 2013-05-08T19:02:29.620 回答
2

我已经使用这段小代码来显示用户处理的错误页面。是否找不到页面或发生其他错误。

    void Application_Error(object sender, EventArgs e)
    {
        // this value can be fetched from config or depend on DEBUG smybol
        if (!handleErrors)
            return;

        var error = Server.GetLastError();
        var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500;

        if (code == 404)
        {
            // do something if page was not found. log for instance
        }
        else
        {
            // collect request info and log exception
        }

        // pass exception to ErrorsController
        Request.RequestContext.RouteData.Values["ex"] = error;

        // execute controller action
        IController errorController = new ErrorsController();
        errorController.Execute(new RequestContext(new HttpContextWrapper(Context), Request.RequestContext.RouteData));
    }

错误控制器看起来像这样。如果您需要详细的异常,可以通过 RouteData 访问

public class ErrorsController : Controller
{
    /// <summary>
    /// Page not found
    /// </summary>
    /// <returns></returns>
    public ActionResult Http404()
    {
        return View();
    }

    /// <summary>
    /// All other errors
    /// </summary>
    /// <param name="actionName"></param>
    protected override void HandleUnknownAction(string actionName)
    {
        // in case detailed exception is required.
        var ex = (Exception) RouteData.Values["ex"];
        return View();
    }
}

您可以为每个 http 代码添加不同的视图。只需执行动作 Http{Code}

于 2013-05-08T12:20:40.797 回答