rss search

How to inject exception data to Razor View

line

First lets get things straight,

If you want to inject Exception Data into the view page, you would use “redirectMode=”ResponseRewrite” and the reason is if you used “ResponseRedirect”, then you would end up losing all the exception data you wanted to inject. ResponseRewrite uses Server.Transfer method in order to change the page to the error page. But Server.Transfer doesn’t work with MVC routes as it looks for physical page in a file system and we don’t deal with physical pages but actions methods here. You can use a physical page but this time we need to use either Asp.NET Web Forms page (not MVC) or an html page in that we cannot render actual error description.

Well, most of the time, for security reasons I don’t recommend you to show stack trace and exception description but you can use something like below in order to show the exception in DEBUG mode:

if(HttpContext.IsDebuggingEnabled)
{
  //show your stack trace and other exception data here 
}

Please remember! Using #IF DEBUG directive in Razor Views are useless. You can find more info about it here.

This is the solution I’ve found nice but of course I would be more than happy if you share your awesome solution too:

I am using Application_Error event handler within Global.asax. This is fired every time an error occurs so I can easily deal with what ever is thrown :

I am too lazy to write the whole code from scratch so I copied the sample codes from this address here.

protected void Application_Error(object sender, EventArgs e)
{
    if (Context.IsCustomErrorEnabled)
        ShowCustomErrorPage(Server.GetLastError());
}

private void ShowCustomErrorPage(Exception exception)
{
    HttpException httpException = exception as HttpException;
    if (httpException == null)
        httpException = new HttpException(500, "Internal Server Error", exception);

    Response.Clear();
    RouteData routeData = new RouteData();
    routeData.Values.Add("controller", "Error");
    routeData.Values.Add("fromAppErrorEvent", true);

    switch (httpException.GetHttpCode())
    {
        case 403:
            routeData.Values.Add("action", "AccessDenied");
            break;

        case 404:
            routeData.Values.Add("action", "NotFound");
            break;

        case 500:
            routeData.Values.Add("action", "ServerError");
            break;

        default:
            routeData.Values.Add("action", "OtherHttpStatusCode");
            routeData.Values.Add("httpStatusCode", httpException.GetHttpCode());
            break;
    }

    Server.ClearError();

    IController controller = new ErrorController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}

In the code above, we simply handle our error gracefully and inject the data as Route Data into our Controller class which looks like the following:

public class ErrorController : Controller
{
    [PreventDirectAccess]
    public ActionResult ServerError()
    {
        return View("Error");
    }

    [PreventDirectAccess]
    public ActionResult AccessDenied()
    {
        return View("Error403");
    }

    public ActionResult NotFound()
    {
        return View("Error404");
    }

    [PreventDirectAccess]
    public ActionResult OtherHttpStatusCode(int httpStatusCode)
    {
        return View("GenericHttpError", httpStatusCode);
    }

    private class PreventDirectAccessAttribute : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            object value = filterContext.RouteData.Values["fromAppErrorEvent"];
            if (!(value is bool && (bool)value))
                filterContext.Result = new ViewResult { ViewName = "Error404" };
        }
    }

Well this is all. I am sure you are smart enough to understand what this code means but in case you don’t , then please leave a comment so I can answer. I don’t like talking too much but this solution helped me when I was having some trouble converting some Error.aspx file to Error.cshtml while keeping the same functionality.



Leave a Reply