Exception Handling Refactoring

In one of my classes, I have a call to the repository that has some error handling on it. I would like to reorganize the error handling code because it is quite repetitive and the only thing that really changes is the message.

My code currently looks something like this:

public IList<User> GetUser() { try { return _repository.GetUsers(); } catch (WebException ex) { ErrorMessages.Add("..."); _logger.ErrorException("...", ex); } catch (SoapException ex) { ErrorMessages.Add("..."); _logger.ErrorException("...", ex); } ... etc } 

I could replace these lines in my catch block with a call to another method that takes the value of the error message and the value of the log message. However, I believe that I could also do this using the Action <> parameter, but I am very inexperienced in using Func <> and Action <> and do not see what benefit I would use using one of the methods.

My question is really the best way to refactor this code and why one of the methods can help the other (as in my example above).

Thanks for any help.

+4
source share
3 answers

Assuming the exception types are always the same, but the messages are different, you can do this:

 static public T Try<T>(string webMessage, string soapMessage, Func<T> func) { try { return func(); } catch (WebException ex) { ErrorMessages.Add(webMessage); _logger.ErrorException(webMessage, ex); } catch (SoapException ex) { ErrorMessages.Add(soapMessage); _logger.ErrorException(soapMessage, ex); } } 

This Try-method will use a delegate of type Func<T> to call the function and return its value. The function will be inside one try-catch block. Messages are provided through options. Now, somewhere else in your code, you can call it like this:

 var users = Try("My web message.", "My soap message.", () => _repository.GetUsers()); 

Or, in your case, even shorter (if you do not use the parameters):

 var users = Try("My web message.", "My soap message.", _repository.GetUsers); 

Of course, you can change and arrange the Try parameters as you wish.

If you mix a method with and without return types, it’s better not to use Func , but Action . This will allow you to fulfill all situations:

 static public void Try(string webMessage, string soapMessage, Action action) { try { action(); } catch (WebException ex) { ErrorMessages.Add(webMessage); _logger.ErrorException(webMessage, ex); } catch (SoapException ex) { ErrorMessages.Add(soapMessage); _logger.ErrorException(soapMessage, ex); } } 

But this solution makes the code a little harder to read / maintain:

 IList<User> users; Try("My web message.", "My soap message.", () => users = _repository.GetUsers()); 
+3
source

You can use lambdas to help with this.

If you define your general-purpose error handler to accept a parameter of type Action , you can call this action in the error handler.

You don't need to worry about the return values, because this lambda that you write at the dial peer can take care of this.

For example, your regular handler might look like this:

 public void AttemptAction(Action action) { try { action(); } catch (WebException ex) { ErrorMessages.Add("..."); _logger.ErrorException("...", ex); // Rethrow? } catch (SoapException ex) { ErrorMessages.Add("..."); _logger.ErrorException("...", ex); // Rethrow? } } 

And then you can use it as follows:

 public IList<User> GetUser() { IList<User> result = null; AttemptAction(() => result = _repository.GetUsers()); return result; } 
+3
source

You can use Aspect-Oriented Programming http://en.wikipedia.org/wiki/Aspect-oriented_programming . The idea is to put all the repeating code in special classes called aspect.

Your code will look in PostSharp

 [ExceptionLogger] public IList<User> GetUser() { return _repository.GetUsers(); } public class ExceptionLogger: OnMethodBoundaryAspect { //getting _logger and ErrorMessages public override void OnException(MethodExecutionArgs args) { ErrorMessages.Add("..."); _logger.ErrorException("...", ex); } } 

For C # you can use PostSharp, Castle.Windsor or Unity frameworks.

0
source

Source: https://habr.com/ru/post/1481744/


All Articles