【问题标题】:How to keep the Server.GetLastError after Response redirecting in MVC在 MVC 中重定向响应后如何保留 Server.GetLastError
【发布时间】:2014-02-02 12:30:17
【问题描述】:

在我的 Global.asax 中,我定义了 Application_error 方法:

protected void Application_Error(object sender, EventArgs e)
{
    // Code that runs when an unhandled error occurs

    // Get the exception object.
    var exc                         = Server.GetLastError();

    //logics

    Response.Redirect(String.Format("~/ControllerName/MethodName?errorType={0}", errorAsInteger));
}

并且 exc 变量确实保留了最后一个错误,但是在从响应方法(方法名称)中的响应重定向之后,Server.GetLastError() 为空。如何保留它或将其传递给Response.Redirect(String.Format("~/ControllerName/MethodName?errorType={0}",以便我的方法体中可以将异常作为对象?

【问题讨论】:

    标签: asp.net-mvc model-view-controller response global-asax application-error


    【解决方案1】:

    TempData 的值会一直存在,直到它被读取或会话超时。以这种方式持久化 TempData 可以实现重定向等场景,因为 TempData 中的值在单个请求之外可用。

    Dictionary<string, object> tempDataDictionary = HttpContext.Current.Session["__ControllerTempData"] as Dictionary<string, object>;
                if (tempDataDictionary == null)
                {
                    tempDataDictionary = new Dictionary<string, object>();
                    HttpContext.Current.Session["__ControllerTempData"] = tempDataDictionary;
                }
                tempDataDictionary.Add("LastError", Server.GetLastError());
    

    然后在你的行动中你可以使用

    var error = TempData["LastError"];
    

    但这里有其他解决方案,您可以在没有重定向的情况下完成

    protected void Application_Error(object sender, EventArgs e)
            {
                Exception exception = Server.GetLastError();
    
                Response.Clear();
                var httpException = exception as HttpException;
                var routeData = new RouteData();
                routeData.Values.Add("controller", "Error");
    
                if (httpException == null)
                {
                    routeData.Values.Add("action", "HttpError500");
                }
                else
                {
                    switch (httpException.GetHttpCode())
                    {
                        case 404:
                            routeData.Values.Add("action", "HttpError404");
                            break;
                        default:
                            routeData.Values.Add("action", "HttpError500");
                            break;
                    }
                }
    
                routeData.Values.Add("error", exception);
                Server.ClearError();
                IController errorController = DependencyResolver.Current.GetService<ErrorController>();
                errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
            }
    

    然后在Controller中你可以添加动作

    public ActionResult HttpError500(Exception error)
            {
                return View();
            }
    

    【讨论】:

    • 但是 tempDataDictionary 是这里的局部变量。我应该如何在我被 Response.RidirectoTo 重定向的方法中使用它
    • 好吧字典是引用类型。所以你不支持局部变量而是指向内存的指针,我也更新了关于第二种可能解决方案的文档
    • 在这种情况下,网址不会改变。我试过了。另外,这样我可以在控制器方法中执行 Server.GetLastError() 并返回正确的值。
    • @mathinvalidnik 然后是保存到临时数据时的第一个选项,重定向后您可以在 mvc 中使用 TempData
    【解决方案2】:

    建议您在出现错误时不要重定向,以便保留 URL 并设置正确的 HTTP 状态代码。

    相反,在 Application_Error 中执行你的控制器

    protected void Application_Error(object sender, EventArgs e)
    {
        var exception = Server.GetLastError();
    
        var httpContext = ((HttpApplication)sender).Context;
        httpContext.Response.Clear();
        httpContext.ClearError();
        ExecuteErrorController(httpContext, exception);
    }
    
    private void ExecuteErrorController(HttpContext httpContext, Exception exception)
    {
        var routeData = new RouteData();
        routeData.Values["controller"] = "Error";
        routeData.Values["action"] = "Index";
        routeData.Values["errorType"] = 10; //this is your error code. Can this be retrieved from your error controller instead?
        routeData.Values["exception"] = exception;
    
        using (Controller controller = new ErrorController())
        {
            ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
        }
    }
    

    那么ErrorController就是

    public class ErrorController : Controller
    {
        public ActionResult Index(Exception exception, int errorType)
        {
            Response.TrySkipIisCustomErrors = true;
            Response.StatusCode = GetStatusCode(exception);
    
            return View();
        }
    
        private int GetStatusCode(Exception exception)
        {
            var httpException = exception as HttpException;
            return httpException != null ? httpException.GetHttpCode() : (int)HttpStatusCode.InternalServerError;
        }
    }
    

    【讨论】:

    • MVC 5 使用的绝佳答案!我想补充一点,对于任何遇到请求输出被发送并显示为纯文本的问题的人,请在routeData.Values["exception"] = exception; 下使用httpContext.Response.ContentType = "text/html";,这应该可以解决。
    • 有人能解释一下“routeData.Values["errorType"] = 10; //这是你的错误代码。可以从你的错误控制器中检索吗?”我不明白errorType = 10代表什么或它背后的评论是什么意思。
    猜你喜欢
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-21
    • 2015-02-05
    • 1970-01-01
    相关资源
    最近更新 更多