Search code examples
c#asp.net-mvcexceptioncustom-error-pages

Why I am not getting exception trace in error redirect page?


In my quest to implement best custom error handling practices, I came up with an idea to not use try catch any where in my code. Instead, I have decided to use customErrors mode="On" and redirect to error page and show exception detail in this page.

//My test code from which error will come
public ActionResult Index()
    { 
        AAA aa = null;
        aa.a = "a"; 
    }

//My web.config file
 <customErrors mode="On" defaultRedirect="~/Errors/Error.aspx">
  <error statusCode="404" redirect="~/Errors/404.html" />
</customErrors>

//My error handling page(Error.aspx):
 protected void Page_Load(object sender, EventArgs e)
    {
        Exception error;
        error = Server.GetLastError();            
    }

I believe I should get error message in error in my error handling page. But I always get null.

How do I get the exception message in error handling page?


Solution

  • Let me shed some light in how I generally handle exceptions in the projects I work on. But let's break down into sections.

    Error pages

    The error pages should not show the real exception when on Production. The user has no need to know that the DB had a failure, which could expose your system to security issues. A page with a generic error or a well documented error code would do the job. But, of course, on your dev environment it's ok to show exceptions. I'd suggest to use customErrors mode="RemoteOnly" in this case.

    Error code

    Depending on the system you are developing it would be important to have an error code with the message. For example, the user could see "Unable to connect (XYZ_1234)" or "Unable to connect (ABC_9876)" - same message, different codes - and send it to the support team. If the support team has a document matching the codes with the real exceptions they will be able to send a proper report to the devs.

    Try/Catch blocks

    Try/Catch is your best friend when it comes to exception. Especially because it will help you to customize the exception if necessary. You could have a series of custom exception classes - each with its own characteristic - that would help you to know the problem even before debugging. One simple example:

    public class ExceptionWithCode : Exception
    {
        public ExceptionWithCode(string code, string message) : base(message)
        {
            this.Code = code;
        }
    
        public string Code { get; }
    }
    

    In the code you should approach it in more or less this way:

    try
    {
        // Do whatever database operation here
    }
    catch (SqlException ex)
    {
        // Log the exception
        _logService.Log(ex);
    
        // Throw something else to the user
        throw new ExceptionWithCode("XYZ_1234", "Unable to connect");
    }
    catch (Exception ex)
    {
        // Log the exception
        _logService.Log(ex);
    
        // Throw something else to the user
        throw new ExceptionWithCode("ABC_9876", "Unable to connect");
    }
    

    Notice that I am using 2 catches. The first is because I know this exception may happen, since I am connecting to the DB, the second is in case any other thing may happen. Besides, the user doesn't know the real exception as he/she is getting just a random exception with code instead of a db connection failure.

    Logs

    That's a very important part. Remember: You should never show the real exceptions to the user. Instead, log them in a place where you can easily access. That could be in a file in the server, the database or even in the Windows Event Logs. You don't necessarily need to write your own logging tool, you can use anything available on the internet. My favorite is SeriLog, since I log most of my events/exceptions in text files. But I've used ELMAH for quite some time with .NET Framework and it was pretty good for XML formatted logs.

    That works for me because:

    1. User is informed of the problem and can communicate with the support
    2. I am not tipping off any intruders regarding the flaws of my system (at least not clearly)
    3. I know what kind of exception the user saw thanks to the error code he gave me
    4. There are logs to be analyzed whenever I need