In asp.net 2.0 web site, what is the best way of writing Error page. I have seen following section at following location:
BigBlondeViking's response worked great for me except that I found it did not process 403's (which ASP generates when you try to directly access the /Scripts/ or /Content/ directories.) It appears that this is not propegated as an exception and thus not trappable in the Application_Error handling. (this was identified as a "security vulnerability" by an external firm - don't get me started on that!)
protected void Application_PostRequestHandlerExecute(object sender, EventArgs e)
{
if (!Context.Items.Contains("HasHandledAnError")) // have we alread processed?
{
if (Response.StatusCode > 400 && // any error
Response.StatusCode != 401) // raised when login is required
{
Exception exception = Server.GetLastError(); // this is null if an ASP error
if (exception == null)
{
exception = new HttpException((int)Response.StatusCode, HttpWorkerRequest.GetStatusDescription(Response.StatusCode));
}
HandleRequestError(exception); // code shared with Application_Error
}
}
}
I also made a minor change in my common Error Handling. As we are using ASP.NET MVC, I wanted to explicitly call into a controller, as well as pass the exception object. This allowed me to access the exception itself so that I can log / send detailed e-mail depending on the code;
public ActionResult ServerError(Exception exception)
{
HttpException httpException = exception as HttpException;
if(httpException != null)
{
switch (httpException.GetHttpCode())
{
case 403:
case 404:
Response.StatusCode = 404;
break;
}
// no email...
return View("HttpError", httpException);
}
SendExceptionMail(exception);
Response.StatusCode = 500;
return View("ServerError", exception);
}
In order to pass the exception OBJECT (not just the message and code) I explicitly invoked the controller:
protected void HandleRequestError(Exception exception)
{
if (Context.Items.Contains("HasHandledAnError"))
{
// already processed
return;
}
// mark as processed.
this.Context.Items.Add("HasHandledAnError", true);
CustomErrorsSection customErrorsSection = WebConfigurationManager.GetWebApplicationSection("system.web/customErrors") as CustomErrorsSection;
// Do not show the custom errors if
// a) CustomErrors mode == "off" or not set.
// b) Mode == RemoteOnly and we are on our local development machine.
if (customErrorsSection == null || !Context.IsCustomErrorEnabled ||
(customErrorsSection.Mode == CustomErrorsMode.RemoteOnly && Request.IsLocal))
{
return;
}
int httpStatusCode = 500; // by default.
HttpException httpException = exception as HttpException;
if (httpException != null)
{
httpStatusCode = httpException.GetHttpCode();
}
string viewPath = customErrorsSection.DefaultRedirect;
if (customErrorsSection.Errors != null)
{
CustomError customError = customErrorsSection.Errors[((int)httpStatusCode).ToString()];
if (customError != null && string.IsNullOrEmpty(customError.Redirect))
{
viewPath = customError.Redirect;
}
}
if (string.IsNullOrEmpty(viewPath))
{
return;
}
Response.Clear();
Server.ClearError();
var httpContextMock = new HttpContextWrapper(Context);
httpContextMock.RewritePath(viewPath);
RouteData routeData = RouteTable.Routes.GetRouteData(httpContextMock);
if (routeData == null)
{
throw new InvalidOperationException(String.Format("Did not find custom view with the name '{0}'", viewPath));
}
string controllerName = routeData.Values["controller"] as string;
if (String.IsNullOrEmpty(controllerName))
{
throw new InvalidOperationException(String.Format("No Controller was found for route '{0}'", viewPath));
}
routeData.Values["exception"] = exception;
Response.TrySkipIisCustomErrors = true;
RequestContext requestContext = new RequestContext(httpContextMock, routeData);
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController errorsController = factory.CreateController(requestContext, controllerName);
errorsController.Execute(requestContext);
}