Asp.net mvc 如何在同一视图中显示异常?

Asp.net mvc 如何在同一视图中显示异常?,asp.net-mvc,Asp.net Mvc,我搜索一种通用的方法来显示抛出的异常,而不重定向到错误页面,而是在同一视图中显示它。我在下面尝试了这些: 1我首先尝试通过在global.asax中添加一个自定义筛选器并在属性类中重写public override void OneExceptionExceptionContext filterContext来处理它们,但以这种方式,我无法填充filterContext。由于无法访问视图的旧模型,因此我只能重定向到错误页面,但这不是我想要的结果 2然后我尝试捕获BaseController上的异

我搜索一种通用的方法来显示抛出的异常,而不重定向到错误页面,而是在同一视图中显示它。我在下面尝试了这些:

1我首先尝试通过在global.asax中添加一个自定义筛选器并在属性类中重写public override void OneExceptionExceptionContext filterContext来处理它们,但以这种方式,我无法填充filterContext。由于无法访问视图的旧模型,因此我只能重定向到错误页面,但这不是我想要的结果

2然后我尝试捕获BaseController上的异常。我的所有控制器都继承自BaseController。我再次在控制器中重写public override void OneExceptionExceptionContext filterContext,并在ViewBag中放入异常详细信息等,并通过filterContext.HttpContext.Response.RedirectfilterContext.RequestContext.HttpContext.Request.Path将页面重定向到同一视图;但是ViewBag的内容在重定向页面中丢失了,所以我想不出其他方法了

我怎样才能做到这一点?我在BaseController中编写的代码示例如下:

protected override void OnException(ExceptionContext filterContext) {
    var controllerName = (string)filterContext.RouteData.Values["controller"];
    var actionName = (string)filterContext.RouteData.Values["action"];

    //filterContext.Result = new ViewResult
    //{
    //    ViewName = actionName,
    //    ViewData = new ViewDataDictionary<??>(??),
    //    TempData = filterContext.Controller.TempData,
    //};

    filterContext.ExceptionHandled = true;
    filterContext.HttpContext.Response.Clear();

    filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    ModelState.AddModelError("Error", filterContext.Exception.Message);
    ViewBag.das = "dasd";
    filterContext.HttpContext.Response.Redirect(filterContext.RequestContext.HttpContext.Request.Path);
}

也许可以在BaseController类中设置一个属性,使其具有要使用的视图的名称,并在任何控制器操作中设置该名称来处理请求。然后在OneException中,您可以有一个方法,重定向到控制器操作,只返回与视图名称对应的视图?每个控制器操作在执行其他操作之前都必须设置一个默认视图名称,因为只有它知道它将调用什么视图(如果有的话),以及它可能被什么视图调用

您需要某种返回新视图的BaseController操作

路由可能需要配置,也可能不需要配置,以具有某种可选参数,您可以将这些参数设置为要发送到视图的错误信息。例如,在默认管线中:

routes.MapRoute(RouteNames.Default,
                "{controller}/{action}/{id}",
                new {controller = "Home", action = "Index", id = "", errorInfo = UrlParameter.Optional}
基本控制器:

protected ActionResult ErrorHandler()
{
    ViewBag.das = (string)filterContext.RouteData.Values["errorInfo"];
    return View(ViewName); 
}

protected string ViewName { get; set; }

protected void GoToErrorView(ExceptionContext context, string exceptionData)
{
    var actionName = "ErrorHandler";
    var newVals = new RouteValueDictionary();
    newVals.Add("errorInfo", exceptionData);
    this.RedirectToAction(actionName, newVals);
}
在BaseController.oneException中:

在从BaseController继承并返回ActionResult(特别是ViewResult)的特定控制器中:


我不久前找到了解决方案,并添加了该解决方案,以便它可以帮助其他人。我使用TempData和_布局显示错误:

public class ErrorHandlerAttribute : HandleErrorAttribute
{
    private ILog _logger;

    public ErrorHandlerAttribute()
    {
        _logger = Log4NetManager.GetLogger("MyLogger");
    }

    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled)
        {
            return;
        }

        if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
        {
            return;
        }

        // if the request is AJAX return JSON else view.
        if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
        {
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    error = true,
                    message = filterContext.Exception.Message
                }
            };
            filterContext.HttpContext.Response.StatusCode = 500;
        }

        // log the error using log4net.
        _logger.Error(filterContext.Exception.Message, filterContext.Exception);

        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();

        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;

        if (filterContext.HttpContext.Request.Headers["X-Requested-With"] != "XMLHttpRequest")
        {
            if (filterContext.Controller.TempData["AppError"] != null)
            {
                //If there is a loop it will break here.
                filterContext.Controller.TempData["AppError"] = filterContext.Exception.Message;
                filterContext.HttpContext.Response.Redirect("/");
            }
            else
            {
                int httpCode = new HttpException(null, filterContext.Exception).GetHttpCode();

                switch (httpCode)
                {
                    case 401:
                        filterContext.Controller.TempData["AppError"] = "Not Authorized";
                        filterContext.HttpContext.Response.Redirect("/");
                        break;
                    case 404:
                        filterContext.Controller.TempData["AppError"] = "Not Found";
                        filterContext.HttpContext.Response.Redirect("/");
                        break;
                    default:
                        filterContext.Controller.TempData["AppError"] = filterContext.Exception.Message;
                        //Redirect to the same page again(If error occurs again, it will break above)
                        filterContext.HttpContext.Response.Redirect(filterContext.RequestContext.HttpContext.Request.RawUrl);
                        break;
                }
            }
        }
    }
}
在Global.asax中:

    protected void Application_Error(object sender, EventArgs e)
    {
        var httpContext = ((MvcApplication)sender).Context;
        var ex = Server.GetLastError();

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

        var routeData = new RouteData();
        routeData.Values["controller"] = "ControllerName";
        routeData.Values["action"] = "ActionName";
        routeData.Values["error"] = "404"; //Handle this url paramater in your action
        ((IController)new AccountController()).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
    }

嘿,请考虑重新格式化你的问题。它看起来有点像一堵文字墙,让那些想帮助你阅读的人很难阅读。试着自己读,我重新格式化了。谢谢答复
public class ErrorHandlerAttribute : HandleErrorAttribute
{
    private ILog _logger;

    public ErrorHandlerAttribute()
    {
        _logger = Log4NetManager.GetLogger("MyLogger");
    }

    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled)
        {
            return;
        }

        if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
        {
            return;
        }

        // if the request is AJAX return JSON else view.
        if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
        {
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    error = true,
                    message = filterContext.Exception.Message
                }
            };
            filterContext.HttpContext.Response.StatusCode = 500;
        }

        // log the error using log4net.
        _logger.Error(filterContext.Exception.Message, filterContext.Exception);

        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();

        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;

        if (filterContext.HttpContext.Request.Headers["X-Requested-With"] != "XMLHttpRequest")
        {
            if (filterContext.Controller.TempData["AppError"] != null)
            {
                //If there is a loop it will break here.
                filterContext.Controller.TempData["AppError"] = filterContext.Exception.Message;
                filterContext.HttpContext.Response.Redirect("/");
            }
            else
            {
                int httpCode = new HttpException(null, filterContext.Exception).GetHttpCode();

                switch (httpCode)
                {
                    case 401:
                        filterContext.Controller.TempData["AppError"] = "Not Authorized";
                        filterContext.HttpContext.Response.Redirect("/");
                        break;
                    case 404:
                        filterContext.Controller.TempData["AppError"] = "Not Found";
                        filterContext.HttpContext.Response.Redirect("/");
                        break;
                    default:
                        filterContext.Controller.TempData["AppError"] = filterContext.Exception.Message;
                        //Redirect to the same page again(If error occurs again, it will break above)
                        filterContext.HttpContext.Response.Redirect(filterContext.RequestContext.HttpContext.Request.RawUrl);
                        break;
                }
            }
        }
    }
}
    protected void Application_Error(object sender, EventArgs e)
    {
        var httpContext = ((MvcApplication)sender).Context;
        var ex = Server.GetLastError();

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

        var routeData = new RouteData();
        routeData.Values["controller"] = "ControllerName";
        routeData.Values["action"] = "ActionName";
        routeData.Values["error"] = "404"; //Handle this url paramater in your action
        ((IController)new AccountController()).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
    }