简体   繁体   中英

Where should I place try catch?

Learning to log errors. This is a basic structure of code all through my project.

I have been advised that the try block has to be placed only in Event Handlers. But when logging the error, it is required to know, which method caused the error. So, in such cases, should I also keep try block in AllIsFine() & SaveData() . If yes, then should it log the error or just throw .

What is the best/Standard practice.

DataContext objDataContext = new DataContext();
protected void btn_Click(object sender, EventArgs e)
{
  try
   {
     if(AllIsFine())
      {
        objDataContext.SaveData();
      }
   }
  catch(Exception ex)
   {
     //some handling
   }
}

private bool AllIsFine()
{
   //some code
}

EDIT : Ofcourse, we would try to see that it never raises an exception, but not practical. I am looking at it this way. When deployed, the only access I have is to the logs and need to get as much info as possible.So in such cases, (and with this kind of a structure), where do you advise to keep the try catch

I have been advised that the try block has to be placed only in Event Handlers

This is not true.
There are different type of exceptions, some you need to handle, some you should throw, some you should catch, some you should not. Read this please.

Summary:

  • You should catch exceptions that you can do something with them
  • If you want to just log exceptions catch, log, and then use throw not throw ex (it resets the call stack)
  • Prevent exception from happening if you can, check for conditions that prevent exceptions( IndexOutOfRangeException , NullPointerException , ArgumentNullException ) do that instead of executing the action and catch the exception
  • Don't catch fatal exceptions; nothing you can do about them anyway, and trying to generally makes it worse.
  • Fix your code so that it never triggers a boneheaded exception – an "index out of range" exception should never happen in production code.
  • Avoid vexing exceptions whenever possible by calling the “Try” versions of those vexing methods that throw in non-exceptional circumstances. If you cannot avoid calling a vexing method, catch its vexing exceptions.
  • Always handle exceptions that indicate unexpected exogenous conditions; generally it is not worthwhile or practical to anticipate every possible failure. Just try the operation and be prepared to handle the exception.

The try-catch statement consists of a try block followed by one or more catch clauses, which specify handlers for different exceptions.

object o2 = null;
try
{
    int i2 = (int)o2;   // Error
}

It is possible to use more than one specific catch clause in the same try-catch statement. A throw statement can be used in a catch block to re-throw the exception that is caught by the catch statement. You can catch one exception and throw a different exception. When you do this, specify the exception that you caught as the inner exception

catch (FileNotFoundException ex)
{
    // FileNotFoundExceptions are handled here.
}
catch (InvalidCastException ex) 
{
    // Perform some action here, and then throw a new exception.
    throw new YourCustomException("Put your error message here.", ex);
}

throw ex; is basically like throwing an exception from that point, so the stack trace would only go to where you are issuing the throw ex; statement

But when logging the error, it is required to know, which method caused the error.

You should use the call stack for that.

Try as much as possible to Prevent the Exceptions, and not catching them, if you would Catch an error, try to catch a specific Error, what I mean by that, not try to Catch Exception but something like specific like InvalidCastException.

After catching an Error you should log the exception, but not throwing an exception to log it.

I thought about your question for a while and even if it is already answered, I wanted to share my thoughts.

general

When talking about exception handling, you have to keep in mind what an exception is : An exception occurs when code cannot run as expected, causing an inconsistent behaviour/state of your application. This thought leads us to an important rule: Do not catch exceptions that you can't handle! The Exception system provides security. Think about an accounting software that connects to a database and the connection throws an exception. If you only log the exception and don't provide any notification about this to the user, he will start to work with the software and when he tries to save, the data will be lost!

You see, it is important where to handle exceptions:

  • Some of them will be handled by the user (usually in the UI-Layer eg View in MVVM/MVC) like the Database exception from the example – only the user can decide if the database is required, the connection string has changed or if a retry will fix the issue.
  • Others can be handled where they occur; for example code that interacts with some sort of hardware often implements methods with some sort of retry or circuit-breaker logic.

architecture

The where decision is also influenced by the architecture: Let's come back to the Database exception scenario: You cannot handle specific exceptions like a MySQL specific Exception ( MySqlException ) in the UI-Layer because that causes a boundary from you View layer to the specific Model layer implementation and the layering architecture will be broken. However, this is not the topic since your question is about logging exceptions, but you should keep that in mind and probably think about it like this: Catch exceptions of concrete libraries or those that belong to a specific layer/dependency where they occur and log them there and throw new , more generic (probably self-created) exceptions. Those exceptions can be handled in the View-layer and presented to the user.

implementation

The question of where is also important. Since logging is seen as a cross cutting concern. You could think about an AOP framework or, as I have suggested in a comment, by using a decorator pattern. You can compose the logging decorators by basic inversion of control usage and your code will be much cleaner by wrapping everything in try-catch blocks. If you are using (or planning to use) a DI-container in your application, you could also make use of interception, which would allow you to dynamically wrap you method calls by specified behaviour (like try-catch ).

summary

handle your exceptions where you can handle them and log them where you get the most relevant data (eg context) from to reproduce the error. But keep in mind that an exception is a security mechanism – it will stop your application when it is no longer in a secure state – when you don't forward your exceptions (by using throw ) and just log them, this could cause not the best user experience.

If you want any code examples, simply ask for them ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM