0

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?

  • Are you using Asp.Net MVC (Or) Asp.Net? – Rahul Jun 20 '19 at 12:06
  • its asp.net mvc but for error page, I am using .aspx file – CodesDDecodes Jun 20 '19 at 12:07
  • This code doesn't display anything. It just stores the exception in a local variable – Panagiotis Kanavos Jun 20 '19 at 12:08
  • okay, I am getting null in local variable error, and I want the exception that was raised in public ActionResult Index() in this local variable. – CodesDDecodes Jun 20 '19 at 12:09
  • This is far from best practice. – Chris Pickford Jun 20 '19 at 12:10
  • Possible duplicate of [ASP.NET custom error page - Server.GetLastError() is null](https://stackoverflow.com/questions/343014/asp-net-custom-error-page-server-getlasterror-is-null) – Chris Pickford Jun 20 '19 at 12:10
  • Check [Custom error pages in ASP.NET MVC. Easy, right?](https://benfoster.io/blog/aspnet-mvc-custom-error-pages). Using `redirectMode="ResponseRewrite"` is just one of the requirements – Panagiotis Kanavos Jun 20 '19 at 12:11
  • added redirectMode="ResponseRewrite" and I was expecting System.NullReferenceException: 'Object reference not set to an instance of an object.' in Server.GetLastError() but I got The view 'Error' or its master was not found or no view engine supports the searched locations. The following locations were searched: ~/Views/Home/Error.aspx ~/Views/Home/Error.ascx ~/Views/Shared/Error.aspx ~/Views/Shared/Error.ascx ~/Views/Home/Error.cshtml ~/Views/Home/Error.vbhtml ~/Views/Shared/Error.cshtml ~/Views/Shared/Error.vbhtml in error – CodesDDecodes Jun 20 '19 at 12:15
  • Chris, I would love to learn best practise if you can suggest any... – CodesDDecodes Jun 20 '19 at 12:16
  • @CodesDDecodes on the other hand, you can specify any page you want in MVC itself with eg `app.UseExceptionHandler("/Home/Error");` as shown [in this question](https://stackoverflow.com/questions/27626353/asp-net-5-mvc-6-how-to-use-shared-error-cshtml-as-default-error-response) – Panagiotis Kanavos Jun 20 '19 at 12:17
  • Best exception handling practice is to handle your exceptions. In the event something unexpected happens, you should write a global exception handler to log the issue and present something friendly to the user. – Chris Pickford Jun 20 '19 at 12:17
  • @CodesDDecodes as for best practices, there's only one - `don't follow blindly "best practices" without understanding what they mean, what they are for and what they are *not* for`. "Don't use blindly codethat looks relevant" is a corollary. Exceptions should be caught where they can be handled. If you write your methods correctly, limiting side effects, you may only have to handle exceptions at the top level. What you do there though *depends* on the type of exception, the type of application, method, users, support requirements – Panagiotis Kanavos Jun 20 '19 at 12:20
  • For example, you can't display a 500 page to a user editing a grid. The support engineers need logs with enough information to allow them to solve issues. They *don't* need exception stacks, they need a log entry that says `Product ID XYZ not found in the database` or `Database didn't respond`. *Developers* on the other hand require very different logs, with full details. – Panagiotis Kanavos Jun 20 '19 at 12:24

1 Answers1

0

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
Davidson Sousa
  • 1,353
  • 1
  • 14
  • 34