Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep the Server.GetLastError after Response redirecting in MVC

In my Global.asax I have defined the Application_error method :

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

And the exc variable does keep the last error but After being redirected from the response in the responding method(MethodName) the Server.GetLastError() is null. How can I keep it or pass it to the Response.Redirect(String.Format("~/ControllerName/MethodName?errorType={0}" so I can have the exception in my method body as an object ?

like image 288
mathinvalidnik Avatar asked Nov 30 '22 19:11

mathinvalidnik


2 Answers

I would like to advise you to not redirect when there is an error so that the URL is preserved and the correct HTTP status code is set.

Instead, execute your controller inside 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));
    }
}

Then ErrorController is

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;
    }
}
like image 158
LostInComputer Avatar answered Dec 04 '22 04:12

LostInComputer


The value of TempData persists until it is read or until the session times out. Persisting TempData in this way enables scenarios such as redirection, because the values in TempData are available beyond a single request.

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

Then in your action you can use

var error = TempData["LastError"];

But here is other solution which you can do without redirect

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

then in Controller you can add action

public ActionResult HttpError500(Exception error)
        {
            return View();
        }
like image 34
Vova Bilyachat Avatar answered Dec 04 '22 04:12

Vova Bilyachat