Throwing an HttpException always sends back HTTP 500 error?

Earlz picture Earlz · Apr 10, 2011 · Viewed 38.3k times · Source

I'm trying to throw an HTTP 403 error code back at the client. I've read that HttpException is the cleanest way to accomplish this, but it's not working for me. I throw the exception from within a page like this:

throw new HttpException(403,"You must be logged in to access this resource.");

However, this will only give a standard ASP.Net stack trace(with 500 error) when CustomErrors is off. If CustomErrors is on, then this will not redirect to the page I have setup to be displayed when a 403 error occurs. Should I forget about HttpException and instead set all the HTTP codes myself? How do I fix this?

The custom errors part of my Web.Config is this:

<customErrors mode="On" defaultRedirect="GenericErrorPage.html">
      <error statusCode="403" redirect="Forbidden.html" />
</customErrors>

Instead of getting Forbidden.html, I'll get GenericErrorPage.html

Answer

OscarVGG picture OscarVGG · May 4, 2011

You need to override Application error like this:

    protected void Application_Error()
    {
        var exception = Server.GetLastError();
        var httpException = exception as HttpException;
        Response.Clear();
        Server.ClearError();
        
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "General";
        routeData.Values["exception"] = exception;
        Response.StatusCode = 500;

        if (httpException != null)
        {
            Response.StatusCode = httpException.GetHttpCode();
            switch (Response.StatusCode)
            {
                case 403:
                    routeData.Values["action"] = "Http403";
                    break;
                case 404:
                    routeData.Values["action"] = "Http404";
                    break;
            }
        }

        IController errorsController = new ErrorsController();
        var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
        errorsController.Execute(rc);
    }

Then you've got to add the errorsController:

public class ErrorsController : Controller
{
    public ActionResult General(Exception exception)
    {
        ViewBag.ErrorCode = Response.StatusCode;
        ViewBag.Message = "Error Happened";

        //you should log your exception here

        return View("Index");
    }

    public ActionResult Http404()
    {
        ViewBag.ErrorCode = Response.StatusCode;
        ViewBag.Message = "Not Found";
        return View("Index");
    }

    public ActionResult Http403()
    {
        ViewBag.Message = Response.StatusCode;
        ViewBag.Message = "Forbidden";
        return View("Index");
    }

}

And last create a view in for errorsController. I created just one view called index in Views/Errors/.