ASP.NET Custom Error Pages

Posted on February 01, 2004   |   Download sample code

68 comments

ASP.NET provides a simple yet powerful way to deal with errors that occur in your web applications. We will look at several ways to trap errors and display friendly meaningful messages to users. We will then take the discussion a step further and learn how to be instantly notified about problems so you can cope with them right away. As a geek touch we will also track the path 404's travel.

In the days of "classic" ASP you used to get cryptic—an often times downright misleading—error messages. "White pages" leave your visitors in the dark who don't know what happened and what to do next besides closing the browser or navigating away.

It's obvious that "white pages" are ugly but there's another angle to this—ASP.NET displays an exception stack trace which may reveal what your code does and how it works. These days, when the word "security" is in vogue, this could be a dangerous side effect.

Custom error pages are not luxury any more, they are a must-have. You have several ways to implement them.

Trapping Errors On Page Level

Every time you create a web form in Visual Studio .NET you see that your page class derives from System.Web.UI.Page. The Page object helps you trap page-level errors. For this to happen you need to override its OnError method as follows:

protected override void OnError(EventArgs e)
{
  // At this point we have information about the error
  HttpContext ctx = HttpContext.Current;

  Exception exception = ctx.Server.GetLastError ();

  string errorInfo = 
     "<br>Offending URL: " + ctx.Request.Url.ToString () +
     "<br>Source: " + exception.Source + 
     "<br>Message: " + exception.Message +
     "<br>Stack trace: " + exception.StackTrace;

  ctx.Response.Write (errorInfo);

  // --------------------------------------------------
  // To let the page finish running we clear the error
  // --------------------------------------------------
  ctx.Server.ClearError ();
	
  base.OnError (e);
}

This works for one page only, you may say. To have every page benefit from this kind of error handing we need to take advantage of the Page Controller pattern. You define a base class and have every page inherit from it. Download sample code for this article and see the CustomError1 project for an example.

Later on in this article you will learn why may need to collect exception information in this manner. Stay tuned.

Trapping Errors On Application Level

The idea of capturing errors on the application level is somewhat similar. At this point we need to rehash our understanding of the Global.asax file.

From the moment you request a page in your browser to the moment you see a response on your screen a complex process takes place on the server. Your request travels through the ASP.NET pipeline.

In the eyes of IIS each virtual directory is an application. When a request within a certain virtual directory is placed, the pipeline creates an instance of HttpApplication to process the request. The runtime maintains a pool of HttpApplication objects. The same instance of HttpApplication will service a request it is responsible for. This instance can be pooled and reused only after it is done processing a request.

Global.asax is optional which means if you are not interested in any session or application events you can live without it. Otherwise the ASP.NET runtime parses your global.asax, compiles a class derived from HttpApplication and hands it a request for your web application.

HttpApplication fires a number of events. One of them is Error. To implement your own handler for application-level errors your global.asax file needs to have code similar to this:

protected void Application_Error(object sender, EventArgs e)
{
}

When any exception is thrown now—be it a general exception or a 404—it will end up in Application_Error. The following implementation of this handler is similar to the one above:

protected void Application_Error(Object sender, EventArgs e)
{
  // At this point we have information about the error
  HttpContext ctx = HttpContext.Current;

  Exception exception = ctx.Server.GetLastError ();

  string errorInfo = 
     "<br>Offending URL: " + ctx.Request.Url.ToString () +
     "<br>Source: " + exception.Source + 
     "<br>Message: " + exception.Message +
     "<br>Stack trace: " + exception.StackTrace;

  ctx.Response.Write (errorInfo);

  // --------------------------------------------------
  // To let the page finish running we clear the error
  // --------------------------------------------------
  ctx.Server.ClearError ();
}

Be careful when modifying global.asax. The ASP.NET framework detects that you changed it, flushes all session state and closed all browser sessions and—in essence—reboots your application. When a new page request arrives, the framework will parse global.asax and compile a new object derived from HttpApplication again.

Setting Custom Error Pages In web.config

If an exception has not been handed by the Page object, or the HttpApplication object and has not been cleared through Server.ClearError() it will be dealt with according to the settings of web.config.

When you first create an ASP.NET web project in Visual Studio .NET you get a web.config for free with a small <customErrors> section:

<customErrors mode="RemoteOnly" />

With this setting your visitors will see a canned error page much like the one from ASP days. To save your face you can have ASP.NET display a nice page with an apology and a suggested plan of action.

The mode attribute can be one of the following:

  • On – error details are not shown to anybody, even local users. If you specified a custom error page it will be always used.
  • Off – everyone will see error details, both local and remote users. If you specified a custom error page it will NOT be used.
  • RemoteOnly – local users will see detailed error pages with a stack trace and compilation details, while remote users with be presented with a concise page notifying them that an error occurred. If a custom error page is available, it will be shown to the remote users only.

Displaying a concise yet not-so-pretty error page to visitors is still not good enough, so you need to put together a custom error page and specify it this way:

<customErrors
       mode="RemoteOnly" 
       defaultRedirect="~/errors/GeneralError.aspx" 
/>

Should anything happen now, you will see a detailed stack trace and remote users will be automatically redirected to the custom error page, GeneralError.aspx. How you apologize to users for the inconvenience is up to you. Ian Lloyd gives a couple of suggestions as to the look and feel of a custom 404 page.

The <customErrors> tag may also contain several <error> (see MSDN) subtags for more granular error handling. Each <error> tag allows you to set a custom condition based upon an HTTP status code. For example, you may display a custom 404 for missing pages and a general error page for all other exceptions:

<customErrors mode="On" defaultRedirect="~/errors/GeneralError.aspx">
     <error statusCode="404" redirect="~/errors/PageNotFound.aspx" />
</customErrors>

The URL to a custom error page may be relative (~/error/PageNotFound.aspx) or absolute (http://www.yoursite.com/errors/PageNotFound.aspx). The tilde (~) in front of URLs means that these URLs point to the root of your web application. Please download sample code for this article and see the CustomErrors3 project.

That's really all there's to it. Before we move on to the next (and last approach) a few words about clearing errors.

Clearing Errors

You probably noticed I chose to call Server.ClearError() in both OnError and Application_Error above. I call it to let the page run its course. What happens if you comment it out? The exception will leave Application_Error and continue to crawl up the stack until it's handled and put to rest. If you set custom error pages in web.config the runtime will act accordingly—you get to collect exception information AND see a friendly error page. We'll talk about utilizing this information a little later.

Handling Errors In An HttpModule

Much is written about HTTP modules. They are an integral part of the ASP.NET pipeline model. Suffice it to say that they act as content filters. An HTTP module class implements the IHttpModule interface (see MSDN). With the help of HttpModules you can pre- and post-process a request and modify its content. IHttpModule is a simple interface:

public interface IHttpModule
{
   void Dispose();
   void Init(HttpApplication context);
}

As you see the context parameter is of type HttpApplication. It will come in very handy when we write out own HttpModule. Implementation of a simple HttpModule may look as follows:

using System;
using System.Web;

namespace AspNetResources.CustomErrors4
{
  public class MyErrorModule : IHttpModule
  {
    public void Init (HttpApplication app)
    {
      app.Error += new System.EventHandler (OnError);
    }

    public void OnError (object obj, EventArgs args)
    {
      // At this point we have information about the error
      HttpContext ctx = HttpContext.Current;

      Exception exception = ctx.Server.GetLastError ();

      string errorInfo = 
            "<br>Offending URL: " + ctx.Request.Url.ToString () +
            "<br>Source: " + exception.Source + 
            "<br>Message: " + exception.Message +
            "<br>Stack trace: " + exception.StackTrace;

      ctx.Response.Write (errorInfo);

      // --------------------------------------------------
      // To let the page finish running we clear the error
      // --------------------------------------------------
      ctx.Server.ClearError ();
    }

    public void Dispose () {}
  }
}

The Init method is where you wire events exposed by HttpApplication. Wait, is it the same HttpApplication we talked about before? Yes, it is. You've already learned how to add handlers for various evens to Global.asax. What you do here is essentially the same. Personally, I think writing an HttpModule to trap errors is a much more elegant solution than customizing your Global.asax file. Again, if you comment out the line with Server.ClearError() the exception will travel back up the stack and—provided your web.config is properly configured—a custom error page will be served.

To plug our HttpModule into the pipeline we need to add a few lines to web.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.web>
  <httpModules>
   <add type="AspNetResources.CustomErrors4.MyErrorModule,«
                                                    CustomErrors4" 
    name="MyErrorModule" />
  </httpModules>
 </system.web>
</configuration>

As MSDN states the type attribute specifies a comma-separated class/assembly combination. In our case MyErrorModule is the name of a class from the AspNetResources.CustomErrors4 assembly. Tim Ewald and Keith Brown wrote an excellent article for MSDN Magazine on this subject.

You will find a full-fledged sample in the CustomErrors4 project in code download.

To gain deeper understanding of HttpModules and their place in the HTTP pipeline I encourage you to search the web since the nuts and bolts are not relevant to the topic of error handling.

What about HTML pages?

What happens if you request a non-existent HTML page? This question comes up in news groups very often.

By default you will get a canned "white page". When you install the .NET Framework is maps certain file extensions to the ASP.NET ISAPI, aspnet_isapi.dll. Neither HTML nor HTM files are mapped to it (because they are not ASP.NET pages). However, you can configure IIS to treat them as ASP.NET pages and serve our custom error pages.

  1. Run the IIS Manager
  2. Select a web application
  3. Right click and go to Properties
  4. On the Virtual Directory tab click Configuration
  5. In the Extension column find .aspx, double click and copy the full path to aspnet_isapi.dll. It should be something like C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\«
    aspnet_isapi.dll
  6. Click Add and paste the path in the Executable box
  7. In the Extension box type .html
  8. Make sure Check that file exists is NOT checked
  9. Dismiss all dialogs

If you type a wrong URL to an HTML page now you should get our user-friendly error page.

Analyze That

The reason we went this far with error trapping is the insight we gain about the problem. As strange as it may sound, exceptions are your friends because once you trap one you can alert responsible people right away. There are several ways to go about it:

  • Write it to the system event log. You could have WMI monitor events in the log and act on them, too. See MSDN for more information
  • Write it to a file
  • Email alerts

Please refer to an excellent whitepaper, Exception Management Architecture Guide from Microsoft for a comprehensive discussion of different aspects of error handling.

I've implemented the last option—email alerts—in a production environment and it worked great. Once someone pulls up a (custom) error page we get an email and jump right on it. Given the fact that users grow impatient with faulty sites and web applications, it's critical to be notified of errors right away.

The Path of 404

As I was researching the topic of custom error pages I couldn't help wondering where 404s originate from and how we end up seeing custom 404 pages. To follow this exercise you will need MSDN and Lutz Roeder's Reflector.

HttpApplication Lifetime

When IIS receives a resource request it first figures out if it will process it directly or match against an ISAPI. If it is one of the ASP.NET resources, IIS hands the request to the ASP.NET ISAPI, aspnet_isapi.dll.

For example, when a request for an .aspx page comes the runtime creates a whole pipeline of objects. At about this time an object of type HttpApplication (which we already talked about) is instantiated. This object represents your web application. By tapping into the various events of HttpApplication you can follow request execution every step of the way (the image on the left shows the sequence of these events).

Next, HttpApplication calls its MapHttpHandler method which returns an instance of IHttpHandler (an object that implements IHttpHandler, to be more precise). The IHttpHandler interface is a very simple one:

public interface IHttpHandler
{
   void ProcessRequest(HttpContext context);
   bool IsReusable { get; }
}

The IsReusable property specifies if the same instance of the handler can be pooled and reused repeatedly. Each request gets its own instance of HttpHandler which is dedicated to it throughout the lifetime of the request itself. Once the request is processed its HttpHandler is returned to a pool and later reused for another request.

The ProcessRequest method is where magic happens. Ultimately, this method processes a request and generates a response stream which travels back up the pipeline, leaves the web server and is delivered to the client. How does HttpApplication know which HttpHandler to instantiate? It's all pre-configured in machine.config:

...
<httpHandlers>
 <add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
 <add verb="*" path="*.ashx" 
      type="System.Web.UI.SimpleHandlerFactory"/>
 <add verb="*" path="*.asax" type="System.Web.HttpForbiddenHandler"/>
...
</httpHandlers>

This is only an excerpt. You have more HttHandlers configured for you. See how .aspx files are mapped to the System.Web.UI.PageHandlerFactory class?

To instantiate the right handler HttpApplication calls its MapHttpHandler method:

internal IHttpHandler MapHttpHandler (
          HttpContext context, string requestType, 
          string path, string pathTranslated, 
          bool useAppConfig);

If you follow the assembly code of this method you will also see a call to the PageHandlerFactory.GetHandler method which returns an instance of HttpHandler:

L_0022: call HttpApplication.GetHandlerMapping
L_0027: stloc.2 
L_0028: ldloc.2 
L_0029: brtrue.s L_004a
L_002b: ldc.i4.s 42
L_002d: call PerfCounters.IncrementCounter
L_0032: ldc.i4.s 41
L_0034: call PerfCounters.IncrementCounter
L_0039: ldstr "Http_handler_not_found_for_request_type"
L_003e: ldarg.2 
L_003f: call HttpRuntime.FormatResourceString
L_0044: newobj HttpException..ctor
L_0049: throw 
L_004a: ldarg.0 
L_004b: ldloc.2 
L_004c: call HttpApplication.GetFactory
L_0051: stloc.3 
L_0052: ldloc.3 
L_0053: ldarg.1 
L_0054: ldarg.2 
L_0055: ldarg.3 
L_0056: ldarg.s pathTranslated
L_0058: callvirt IHttpHandlerFactory.GetHandler

Every ASP.NET page you write, whether you insert a base class in-between or not, ultimately derives from the System.Web.UI.Page class. It's interesting to note that the Page class inherits the IHttpHandler interface and is an HttpHandler itself! What that means is the runtime will at some point call Page.ProcessRequest!

Page.ProcessRequest request delegates all work to its internal method, ProcessRequestMain:

if (this.IsTransacted)
 { this.ProcessRequestTransacted(); }
else
 { this.ProcessRequestMain(); }

Finally, ProcessRequestMain is where all the fun stuff happens. Among all the many things it does, it defines an exception handler as follows:

Try
{
  // code skipped 
  catch (Exception exception4)
  {
    exception1 = exception4;
    PerfCounters.IncrementCounter(34);
    PerfCounters.IncrementCounter(36);
    if (!this.HandleError(exception1)) { throw; }
  }
}

If you follow HandleError further you'll notice that it will try to look up the name of your custom error page and redirect you to it:

if ((this._errorPage != null) && 
     CustomErrors.GetSettings(base.Context).«
                                 CustomErrorsEnabled(this._request))
{
  this._response.RedirectToErrorPage(this._errorPage);
  return true; 
}

internal bool RedirectToErrorPage(string url)
{ 
  bool flag1;
  try
  {
   if (url == null)
   {
    flag1 = false;
    goto L_0062;
   }
	 
   if (this._headersWritten)
   {
    flag1 = false;
    goto L_0062;
   }

   if (this.Request.QueryString["aspxerrorpath"] != null)
   {
    flag1 = false;
    goto L_0062;
   }

   if (url.IndexOf(63) < 0)
   {
    url = string.Concat(url, "?aspxerrorpath=", this.Request.Path);
   }
   
   this.Redirect(url, 0);
 }
 catch (Exception exception1)
 {
  flag1 = false;
  goto L_0062;
 }

 return true; 
 L_0062:
 return flag1; 
}

This method does you a favor by appending the offending URL. You can see ?aspxerrorpath= in the URL each time a custom 404 page is displayed.

If everything goes smooth—no exceptions thrown, no redirects to custom error pages—ProcessRequest finishes its job, and the response travels back through the pipeline.

Conclusion

This article gave a detailed overview of ASP.NET custom error pages and several different approaches of setting them up. It's important that users see meaningful, friendly error pages. By the same token it's important that people on the other end are alerted about problems right away. ASP.NET provides a powerful and flexible framework to achieve both goals.

68 comments

jon dalberg
on July 28, 2004

Great article! My question is: What happens when i set the Response.StatusCode programmatically? For example, I have configured a custom error page for status code 404 named 404.aspx. If I set the Response.StatusCode=404 nothing happens and the page continues to process. Next I tried calling Response.End() which caused the generic 404 page, not my 404.aspx page. Response.Flush() caused the generic ASP.Net 404 error page instead of my 404.aspx page. Any ideas why it would behave this way?

Thanks.


Milan Negovan
on July 28, 2004

Good question. I've played with the StatusCode property a little bit and haven't had much luck figuring it out. I'll post an update if I can trace it through the disassembled code.


Shawn C
on September 08, 2004

Try trapping 401's - Not possible.


Mike
on January 04, 2005

nice article, thank you!


Floook
on January 19, 2005

Thanks for the data. I just got an exception I was not able to handle today because it didn't say what file or line it occurred in.

I added your function to my class and voila! It told me what line the exception occurred at and I was able to debug the script immediately.

Thanks a lot!


jkgreer
on March 23, 2005

lately i've been using elmah.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/elmah.asp
for server wide/cluster exception handling you can't beat it. there is a sql provider and by adding a few lines to your machine.config and one assembly to the gac the entire machine logs. i've built real time reports and graphs showing when servers or apps are going balistic. then i try and code very aggressivly for a resonable (documented) set of behavior to avoid exceptions and let the serious ones fall through and fix the true mistakes as i see them. throwing and catching exceptions can be a pretty expensive operation.

i am curious though, if anyone has found a really clean way to balance what errors should be globally catched and what errors get translated into a user friendly displayable error. There always seems to be a gray area of what should fall through and what should be reported back to a user.


Monica
on June 13, 2005

Very nice article! I'm trying the CustomErrors4 and instead of raising a general exception, I'm trying to cause the page not found with:

Server.Transfer("NoPage.aspx");

But it keeps going to the GeneralError.aspx.


Marcus
on June 13, 2005

I've managed to trap the .htm and .html files by adding them into my Application mappings, however I'm still wanting to trap other errors, such as folder names, and word documents. If I go to http://www.mysite.com/foldername (and presuming foldername doesn't exist) I get the standard 404, not my custom 404.

Likewise for word documents, something tells me I probably shouldn't map .doc, .pdf, .gif, .jpg, .png all to the .net dll, but I still want them to go to my custom error page. Any thoughts?


Milan Negovan
on June 14, 2005

With a non-existing folder the approach is pretty much the same as with pages---you need to configure IIS to redirect to the ASP.NET ISAPI. As to files with the extensions you listed, you can still map ASP.NET to serve them if you need to, and then they become subject to your custom error pages.


Mauricio Quiros
on June 30, 2005

Great article, simple and clear and the results are so cool. One doubt I have is while debuggin this aproach I always get the same error (message) in the example output. I debug to figure it out what's the reason and I find out that the exact problem is in the Inner Exception. Within the Exception. So this is right? or Im doing something wrong, thanks.


Milan Negovan
on July 01, 2005

Mauricio, it really depends on what kind of exceptions you catch. For example, HTTP exceptions are quite generic (and cryptic, at that) with the real, meaningful exceptions stored in the InnerException property.

Generally, though, you don't have to dig into the InnerException.


Mauricio Quiros
on July 01, 2005

Thanks a lot for your fast answer. I'm still kind of confuse about this because no matter what Exception I throw(Like the example: throw new Exception ("Silly exception");) I always get the same error.

Message: Exception of type System.Web.HttpUnhandledException was thrown.

Probably I'm doing something bad, I'll review it all again, but I really want the details of what was the exception (Just can see it in the Inner...), and in my case using the "CustomErrors4 PRoject Example" I always get the same error message too.

That's it and again, Thanks a lot for your time to answer.


Henrique
on July 22, 2005

Well fellows, i might have some aswers let me post this code:
when u want to raise a not founded code:
throw new HttpException(404,"File Not Founded");
and in the web.config
< error statusCode="401" redirect="/Denied.aspx" />

quite simple??


chris mcbride
on August 18, 2005

this is all quite handy, and i'm using the OnError overload right now. It doesn't perform like I want it too, though...

When I trap the error in application_error, the page output is displayed. WHen I trap in OnError at the page level, the page output isn't shown (that is, the first way my header and footer are still in the output stream surrounding the error message. With OnError, I'm only getting a white page with my error message).

Is there any way to get the whole output stream with onError?


Niktu
on September 09, 2005

Yup, I'm trying to resume page generation too (after catching with overload of OnError, or possily bit more elegant Page_Error tied to Error Event ...).


atul
on October 20, 2005

This is the far the best article on handling error i have read...

Thanks


Matt Jensen
on November 03, 2005

Nice article - thanks.
Just wondering, in the case where you're webserver runs htm, .asp and .aspx pages, is there a way to also map classic ASP pages to this error handling method? It would be good to be able to just use one method (e.g. web.config to handle all errors), rather than web.config for .aspx and .htm errors, and the IIS settings for classic ASP.
This may be a stupid question, but can you map classic asp pages to the asp.net isapi also? I presume you can't, but thought it vaguely possible that the .net isapi is 'backwards' compatible, as it were?
Thanks
Cheers
Matt


Vishal Kaushik
on November 24, 2005

Very informative. nice done! Loved it.


Milan Negovan
on November 26, 2005

Matt, you can map just about any extensions to the ASP.NET ISAPI. But remember: once you do that, you're responsible for serving those types of files. It opens a whole can of worms.


Sean Smith
on February 07, 2006

This article really helped me fix the problem quickly. Thank you for an excellent, well laid-out resource.


Dave
on February 14, 2006

This article is the best I've read on error handling in ASP.NET and has been a good learning guide. Is it possible however to provide a VB version instead of C# so I can attempt the more complicated stuff using httpModules??? Thanks!


Erik
on March 15, 2006

When your not using .NET's custom errorpage, and your page has an error you will normaly receive a HTTP 500 error in your HTTP Header.

With Custom error turned on you first get a HTTP 302 header (redirect) and secondly - when error.aspx is get - a HTTP 200 header.

So IIS doesn't log any HTTP 500 (404 etc.) errors anymore,

This gives a wrong picture when using IIS log analysers. And search engines can't detect 404 anymore because eventually 200 is returned.

What can I do to correct this?


Benjamin
on March 30, 2006

Clear and to the point. Thanks!


Milan Negovan
on April 24, 2006

Erik: I think it would be enough to set HttpContext.Current.Response.StatusCode = 404 somewhere on the page.


MousePad
on May 16, 2006

Useful!


chirag
on May 31, 2006

Hi,
in C# & Asp.net
I have a error in config file(Configuration Error) so is ther any way tht i can catch the configuration error & display a particular message.


Milan Negovan
on May 31, 2006

I don't think you can trap errors that occur in config files. I might be wrong, so if anyone knows, please leave a comment.


Dave
on June 07, 2006

I have run into a problem with custom 404 erros. I developed a 404.aspx page with a Close button on. I use session variables to determine which page the user will returned to depending on the page they arrived at this erorr. I have a linkbutton with code behind to redirect to the proper page. Everything renders fine except this link button. It doesn't center the link nor does it display as a link, just shows the text 'Close'

< asp:table runat="server" id="tblClick">
< asp:TableRow HorizontalAlign="center">
< asp:TableCell>
< asp:LinkButton ID="lkbClose" runat="server" OnClick="Close_Click">Close
< /asp:TableCell>
< /asp:TableRow>
< /asp:table>

Code behind:

public void Close_Click(object sender, EventArgs e)
{
Response.Redirect(Session["Pagepath"].ToString() + Session["PageName"].ToString() + "?qstrKey=" + Session["iKey"].ToString());
}

Web config:

< customErrors defaultRedirect="~/Error/GenericError.aspx" mode="On">
< error statusCode="404" redirect="~/Error/404.aspx" />



For now I just have the user click the browser back button but I really don't like that solution.

Any assistance would be greatly appreciated -
If you could please respond via e-mail
Dave


Leblanc Meneses
on August 04, 2006

jkgreer great link!

i normally use exception handlers to log to db
then forward user to error.php?code=unhandledexception
error.php?code=404


Udi
on August 08, 2006

I get all aspx errors reported, but if I mistakenly forget to upload for example a .cs page to the production server,
the clients get an error page, but I don't get a report on such scenarios.

I guess such an error is on compilation on the production server itself and the HTTPHandler is not getting them.

Is there a solution for this kind of problem?


Milan Negovan
on August 15, 2006

I don't know if it's possible to trap errors this early in the page life cycle with the technique I described in the article. I believe the problem is that the HTTP pipeline is not available yet, so you need some other, low-level way of detecting errors.


Migel Ángel
on September 09, 2006

Hi everybody:
I have found this code very interesting if you want to capture only the error 40*, for example, the 404, as you know, when you use a module or the global.asax to get the unhandled errors, you capture the 404 errors too, so with these lines of codes you can react:

System.Exception appException = Server.GetLastError();

if (appException is HttpException)
{
HttpException checkException = (HttpException)appException;
switch (checkException.GetHttpCode())
{
case 403:
{
errMessage.Append("You are not allowed to view that page.");
break;
}
case 404:
{
errMessage.Append("The page you requested cannot be found.");
break;
}
}

Saludos,
Dactivo
http://www.d-activo.com


Adi
on October 05, 2006

Milan, Udi,

Yes, there is. You can handle such an exception in Application_Error. I did not reproduced Udi's case, but let's have a quick test. Taking this same URL we're on now, insert the character | anywhere in between the domain and the aspx extension. You'll get an exception that can be handled in your Application class. The compilation would happen after getting the path to the resource so, if you can handle the first (invalid path), you can handle the second.

If anyone did tested, please comment.


Swetha
on October 10, 2006

Nice article. Do expect more.
Thanks
Swetha


Mark Petersen
on November 28, 2006

What about using IIS to handle the different HTML error codes? In IIS, go to the Properties of a website, click the Custom Errors tab. For each Html error, you can specify a message type of Url, which you could point to an aspx page that would get the last error and display accordingly.

I'm not entirely sure whether IIS does a full redirect (where you lose the ability to get the last error) or not.


Ashok
on January 08, 2007

Can we get entire response stream with forms, controls with value when the error occured? So that we can easily diagnosis the error.


Hunt
on January 15, 2007

Eric,
I've seen this...
<%
Response.Status = "404 Not Found"
%>

Put the above in your 404.html page to keep Google and others happy

Above has not been tested.


Bryan Siebuhr
on January 17, 2007

Is anyone successfully using this approach to trap exceptions related to file uploads that exceed maxRequestLength? Does this approach break down when the request is too big?

I have been able to catch the exception in global.asax using the Application_OnError event. I can extract the exception codes and messages just fine and see them in my Watch windows in VS, and I can execute the Server.ClearError(). However, when I try to display the codes and messages using Response.Write or I try a Response.Redirect to another page all I get is the generic "can't display the page" error display.

Any ideas would be appreciated


huzz
on March 15, 2007

Thanks for the brilliant article..


Duc Bui
on March 21, 2007

Good article from which I've learnt a lot. Thanks everyone!!!


Matt
on March 30, 2007

Nice example. Very worthwhile.

-M


Abhilash
on April 17, 2007

This was really useful.

Thanks


Robin
on April 19, 2007

Nice article. Explained the details beautifully!
Thanks!


Mark Kamoski
on May 02, 2007

When I call GetLastError() on the page that is set as the defaultRedirect in web.config that call always returns null?


venkatesh
on November 20, 2007

Great Article. I have a small query.
I have a website (ASP.NET 2.0+C#+SQL Server 2000) published on the test server. The server's disk space runs out and so the website is no longer viewable to the user. I would like to provide a custom message to the user, if the server space is low.

How to provide the customized message to the user, incase the disk space runs out?


Milan Negovan
on November 26, 2007

Venkatesh, you can have an HttpModule check for disk space on every page request, or you can have a superclass for all your pages to derive from where you can conduct this check.


James Devlin
on April 14, 2008

Good post, I've included it in my Custom ASP.NET 404 Error Page Manifesto.

Just in case that links doesn't turn out properly (no BBCode?):

http://www.codingthewheel.com/archives/custom-asp-net-404-error-page-manifesto


James Devlin
on April 14, 2008

By the way, that's a work in progress. :-)


mike carn
on April 17, 2008

Very clear and concise article with plenty or references and source code example. Doesn't get any better than this unless it was written in VB.net :) thanks.


kiso
on April 19, 2008

nice one


Tobias
on August 12, 2008

Apart from using goto's the article is ok.


Sergey
on August 26, 2008

Great article . Thank you


Asif
on October 09, 2008

Best Asp.net error handling article !


Parimanam
on November 12, 2008

very useful article in error handling in asp.net
Thans Milan


John
on January 16, 2009

Great Article!!! Thanks :)


Leo schoonbroodt
on February 12, 2009

I use a custom 404.aspx page to which IIS transfers when a 404 file not found exists. The page also executes correct except for the fact that when i use a server.transfer("BLdeny.aspx ") in this 404.aspx page (i test if the IP is blacklisted in the database and peridically transer this list of blacklisted IP's to IIS), this server.transfer("BLdeny.aspx ") will not execute.
Any suggestions will be appreciated
Leo Schoonbroodt


Ben
on March 03, 2009

I am allowing .net to handle the errors and redirect the user to a standard error page. The erros are logged to the event view, but of type "Warning". Can you change the type that asp.net logs these errors to "Critical"

Thanks

Ben


Jimmy Dean
on March 06, 2009

What, no VB.NET code? VB.NET is twice as popular as 'C sharpie'.


Milan Negovan
on March 08, 2009

Unhandled exceptions are logged into the even viewer by the health monitoring feature of ASP.NET. This happens out of the box.

You *can* override this if you configure health monitoring by hand (see my article).


daniella
on May 20, 2009

Thank you! very usefull.


Alexey
on May 28, 2009

Migel Ángel,

Thank you!!!

I was going mad receiving StatusCode=200 instead of 404... I was trying Response.StatusCode


Jack
on October 15, 2009

Great! I learn a lot from this topic


Eddlove
on October 16, 2009

What about 401 errors, it isn't easy to catch for me!


bwolf
on January 30, 2010

Excellent, thanks a lot!


Janet
on March 16, 2010

I'm trying to set up custom errors for asp.net in webconfig/global.asax on Server 2003, IIS 6. Got it working find for .aspx pages but not for any htm or html pages. So I found the article describing how to open IIS manager, click configuration, copy path for .aspx extension and add one for .htm Restarted website: Now I get the blank white page explaining there's a problem but not the 404 page not found Restarted web services: same thing Anybody got any tips?

Janet


Janet
on March 16, 2010

Great article, btw. I don't see how to get ctx.Request.Url.ToString ?


Milan Negovan
on March 22, 2010

Janet, it's like this:

HttpContext ctx = HttpContext.Current;
ctx.Request.Url.ToString ();


Milan Negovan
on March 22, 2010

Janet, to your previous question: Internet Explorer displays its own error page if the response is too short (less than 512 bytes). See this post about the issue.

Try filling the page with Lorem Impsum. Also, look in the system Event Log. All kinds of errors get logged there.