MVC 5使用Autofac时的自定义错误页面

时间:2016-03-15 01:35:13

标签: c# asp.net-mvc autofac

我尝试在我的asp.net mvc 5应用程序中使用我一直使用的相同技术实现自定义错误处理:

    protected void Application_Error(object sender, EventArgs e)
    {
        try
        {

            HandleApplicationErrors();
            Response.TrySkipIisCustomErrors = true;
        }
        catch(Exception ex)
        {
            Response.Write(ex.ToString());
            Response.StatusCode = 500;          
        }
    }

private void HandleApplicationErrors(int? statusCode = null)
    {
        try
        {
            Exception ex = Server.GetLastError();
            Response.Clear();

            HttpException httpEx = ex as HttpException;
            if (statusCode == null && httpEx != null) statusCode = httpEx.GetHttpCode();

            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", "Error");

            switch (statusCode)
            {
                case 404:
                    routeData.Values.Add("action", "NotFound");
                    break;
                case 403:
                    routeData.Values.Add("action", "Forbidden");
                    break;
                default:
                    routeData.Values.Add("action", "ServerError");
                    break;
            }

            routeData.Values.Add("exception", ex);

            Server.ClearError();
            this.Server.ClearError();
            this.Response.TrySkipIisCustomErrors = true;
            IController controller = new ErrorController();
            controller.Execute(new RequestContext(new HttpContextWrapper(this.Context), routeData));
        }
        catch(Exception ex)
        {
            Response.Write(ex.ToString());
            Response.StatusCode = 500;
        }
    }

过去这种方法运行得很好,但是在这个应用程序中,我使用的是Autofac,并且无法解决实例,并且无法从此LifetimeScope创建嵌套生命周期它已被处理掉了。"在控制器上。执行线。我已经尝试将ErrorController从autofac注册中排除(它还没有构造函数参数)并直接构造它。

控制器代码非常简单:

        private CustomErrorModel GetModel(Exception ex)
    {

        var model = new CustomErrorModel();
        model.RequestedUrl = Request.Url.OriginalString;
        model.ReferrerUrl = (Request.UrlReferrer == null || model.RequestedUrl == Request.UrlReferrer.OriginalString) ? null : Request.UrlReferrer.OriginalString;
        model.Exception = ex;
        return model;

    }

    public ActionResult ServerError(Exception ex)
    {
        var model = GetModel(ex);

        Response.StatusCode = (int)HttpStatusCode.InternalServerError;
        Response.Status = "500 Internal Server Error";
        return View(model);
    }

任何人都有任何想法让这项工作?

3 个答案:

答案 0 :(得分:1)

好的,在这里回答我自己的问题。我看了一下堆栈跟踪,看起来异常是由mvc尝试使用容器来查找模型绑定器引起的。所以我使我的操作方法无参数并且解决了它!

在此处发布代码供参考:

    protected void Application_Error(object sender, EventArgs e)
{
    try
    {

        HandleApplicationErrors();
        Response.TrySkipIisCustomErrors = true;
    }
    catch(Exception ex)
    {
        Response.Write(ex.ToString());
        Response.StatusCode = 500;          
    }
}

private void HandleApplicationErrors(int? statusCode = null)
{
    try
    {
        Exception ex = Server.GetLastError();
        Response.Clear();

        HttpException httpEx = ex as HttpException;
        if (statusCode == null && httpEx != null) statusCode = httpEx.GetHttpCode();

        RouteData routeData = new RouteData();
        routeData.Values.Add("controller", "Error");

        switch (statusCode)
        {
            case 404:
                routeData.Values.Add("action", "NotFound");
                break;
            case 403:
                routeData.Values.Add("action", "Forbidden");
                break;
            default:
                routeData.Values.Add("action", "ServerError");
                break;
        }

        //routeData.Values.Add("exception", ex);

        Server.ClearError();
        this.Server.ClearError();
        this.Response.TrySkipIisCustomErrors = true;
        IController controller = new ErrorController();
        controller.Execute(new RequestContext(new     HttpContextWrapper(this.Context), routeData));
    }
    catch(Exception ex)
    {
        Response.Write(ex.ToString());
        Response.StatusCode = 500;
    }
}

和我的控制器方法:

public ActionResult ServerError()
{
  HttpException ex = Server.GetLastError() as HttpException; 
  var model = GetModel(ex);
  Response.StatusCode = (int)HttpStatusCode.InternalServerError;
  Response.Status = "500 Internal Server Error";
  return View(model);
}

答案 1 :(得分:1)

我在我的应用程序中做了类似的事情,包括使用Autofac进行依赖注入,并且没有遇到与您相同的问题。

仔细查看您的HandleApplicationErrors方法,我发现您的路由数据与您的ServerError操作所期望的参数不匹配。

HandleApplicationErrors中,您传递的参数名为 exception

ServerError中,您需要一个名为 ex 的参数

更新路线数据的设置以匹配:

routeData.Values.Add("ex", ex);

将解决问题。

答案 2 :(得分:0)

  

"请求生存期本身在EndRequest事件中处理。您   可以在添加的RequestLifetimeHttpModule中看到这一点   引用MVC集成时自动进入管道。   很可能存在Autofac事件处理程序的竞争条件   在您自己的EndRequest事件处理程序之前触发。这是最多的   现在可能只是因为最近的Autofac集成而出现   试图使模块等的注册更加无缝   开发人员,所以我们在预应用程序启动时注册模块。我们   首先订阅该事件,因此我们首先调用。

     

不幸的是,从那里开始真的没什么可做的   Autofac方面 - EndRequest是管道中的最后一个事件   必须处理生命范围,以便它发生在哪里。

     

如果您在EndRequest处理需要解决的问题,   可能为时已晚。即使在之前的集成中,EndRequest也会如此   一直是个风险。例如,如果您解析了一个对象   实现IDisposable,释放生命周期范围   EndRequest将丢弃该对象,并且您正在处理该对象   物体处于不良状态。

     

我建议您尝试将操作的执行时间移至某个时间   在EndRequest之前。或者,如果你100%确定   链中的对象不具有IDisposable,您可以解析该对象   在较早的事件中,将其存储在HttpContext.Items中,并检索它   从那里开始在你的EndRequest处理程序中使用。"

font:https://github.com/autofac/Autofac/issues/570