Refactoring exception handling - c#

In one of my classes I have a call to a repository which has some error handling on it. I would like to refactor 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 those lines in my catch block with a call to another method which takes an error message value and a logger message value. However I suppose I could also do this using an Action<> parameter but I am very inexperienced at using Func<> and Action<> and don't really see what benefit I would have using one of those over a method.
My question is really what is the best way to refactor this code and why does one way benefit over the other (as per my example above).
Thanks for any help.

You can use lambdas to help with this.
If you define your general-purpose error handler to accept a parameter of type Action then you can call that action in the error handler.
You don't need to worry about return values because the lambda you write at the point of call can take care of that.
For example, your general handler could 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 could use it like this:
public IList<User> GetUser()
{
IList<User> result = null;
AttemptAction(() => result = _repository.GetUsers());
return result;
}

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 a function and return its value. The function will be inside the same try-catch block. The messages are provides via parameters. Now, somewhere else in your code, you could call this like:
var users = Try("My web message.", "My soap message.", () => _repository.GetUsers());
Or, in your case even shorter (when not using parameters):
var users = Try("My web message.", "My soap message.", _repository.GetUsers);
Of course you can modify and arrange the parameters of Try to your own liking.
In case you are mixing method with and without return types, it is better not to use the Func but the Action. This will be able to comply to 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 tiny bit more difficult to read / maintain:
IList<User> users;
Try("My web message.", "My soap message.", () => users = _repository.GetUsers());

You can use Aspect-Oriented Programming http://en.wikipedia.org/wiki/Aspect-oriented_programming.
The idea to place all repetitive code to special classes that are called aspect.
Your code will look like 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 ccan use PostSharp, Castle.Windsor or Unity frameworks.

Related

Execution order problem when using Action

I have the following C# code running in a console app for .NET Core 2.2 on Debian 9 x64:
DbCall(Action action) {
try {
lock(thisLock) {
action();
}
}
catch (Exception ex) {
//exception handling
}
}
private T DbCall<T>(Func<T> func) {
try {
lock(thisLock) {
return func();
}
} catch (Exception ex) {
//exception handling
}
}
public void RemoveClassAEntity(ClassA classAentity) {
DbCall(() => {
DbContext.ClassAEntities.Remove(classAentity);
DbContext.SaveChanges();
});
}
public List<ClassA> GetClassAEntities(Func<ClassA, bool> condition) {
return DbCall(() => {
return DbContext.ClassAEntities
.Where(condition)
.ToList();
});
}
public void RemoveClassAEntitiesWithCondition() {
var entities = GetClassAEntities(e => SatisfiesCondition(e));
entities.Sort();
entities.ForEach(e => RemoveClassAEntity(e));
}
There are multiple methods similar to RemoveClassAEntity, that's why I introduced the DbCall methods, so that I wouldn't need to repeat the lock and exception handling.
The method RemoveClassAEntity is public and can be called from multiple threads. However, it cannot be called from different threads at the same time for the same entity (SatisfiesCondition cannot return true at the same time in different threads)
My problem is that "Value cannot be null. Parameter name: entity" error occurs sometimes, originating from the line "action();". I am fairly certain that RemoveClassAEntity is never called with null argument. I couldn't reproduce the issue with a debugger, only by checking error logs in production environment.
I expected the delegate passed to DbCall to be executed synchronously with the calling method, but I get the impression that the delegate is executed after the calling method exits, that's why the exception occurs. If that could be the case, how do I force it to run before the RemoveClassAEntity method exits?
If that's not the case, what could be?

Where to use exception handling

I have an MVC controller that uses a payment service class. Where should I do the exception handling? What is best practice?
Do I use try/catch blocks in both my controller and service class?
Is the exception just thrown again in the service class so it can be handled in the controller? Or should all the exception handling be done in the controller?
I can catch Stripe specific exceptions, should that be done in the service class or controller? Confused...
public async Task<IActionResult> DoSomething(MyViewModel model)
{
try
{
await _paymentService.UpdateSomethingAsync(id, token);
}
catch (Exception ex)
{
//handle
}
enter code here
}
public class PaymentService : IPaymentService
{
public async Task UpdateSomethingAsync(string id, string token)
{
try
{
//update using Stripe...
}
catch (Exception ex)
{
//TODO: Implement error handling
throw;
}
}
}
I guess exception handling must be at service level as it should be self capable of catching and handling all the exceptions(also, to log it at service level for later analysis) occurred at service level and throwing it in its original form (or as per the need it can be customized at service level) to the receiver.
Receiver (controller in this case) should have it's own error handling mechanism as it is a different layer of application and may require some manipulation over exceptions or it's logging at UI level. Here, note that if there is no manipulation or logging of exception or error is required you can directly show service level exception and remove catch from controller.
Hope it make sense.
just write the same code in catch which is in try{ } because catch never pass back or return the value .
try
{
cust_id = txtID.Text;
submit changes();
lblmessage.Text = "Data Save";
}
catch (Exception ex)
{
lblmessage.Text = "Saving error";
cust_id = txtID.Text;
submit changes();
}

Returning BadRequest from WebApi Custom method

Using .net core web api here.
I have a endpoint in my api as:
[HttpPost("data")]
public async Task<IActionResult> PostData(List<string> udata)
{
JArray sets = new JArray();
try
{
sets = Helper.GetData(udata);
}
catch (Exception e)
{
return StatusCode(500, e.Message);
}
}
In the above I am calling an custom method in my helper "GetData" which does all the processing and calculations. To make the Api controller clean I moved all the processing to this helper method.
Below is my helper class:
public static class Helper
{
public static BadRequestObjectResult GetMessage(string message)
{
return new BadRequestObjectResult(message);
}
public static JArray GetData(List<string> udata)
{
if(udata == null)
return GetMessage("Data is null");
//do some processing and calclulations here
//return BadRequest if some issue
}
}
If there is some processing issue or some of the data is not as intended or some other issue I want to throw BadRequest. For this I made a custom method to do so "BadRequestObjectResult".
Now my issue is, if there is an issue in GetData it doesnt throws back to my api or exits from my loop. It just continues to next statement.
I know there is some issue by the way I am returning this but not able to find the issue.
Can anyone point out the correct way to handle this?
My suggestion is to throw an exception from your Helper class and and handle it from your PostData method. For example...
You could throw an ArgumentException and explicitly catch that from your API method.
public static class Helper
{
public static JArray GetData(List<string> udata)
{
if(udata == null)
throw new ArgumentException("Data is null");
//do some processing and calclulations here
//throw ArgumentException if there is an issue
}
}
[HttpPost("data")]
public async Task<IActionResult> PostData(List<string> udata)
{
JArray sets = new JArray();
try
{
sets = Helper.GetData(udata);
return Ok(sets);
}
catch (ArgumentException e)
{
return BadRequest(e.Message);
}
}
This way you can only worry about return codes from your controller while your Helper methods are only concerned with the input and aren't returning something specialized for a controller. It's a bit more flexible that way if you ever want to use your Helper class elsewhere.
This will also meet your requirement of stopping processing upon hitting a bad result, so as soon as a bad result is encountered the result set is thrown away and a BadRequest response is issued.

Unit Test for certain types of exceptions

Some background before I get into my question. I am currently working on a project that is migrating from an IBM DB2 to a SQL Server. Not to get into too much detail, but this DB2 linked server sometimes disconnects with the SQL server, which is normal for linked servers. I have this working in code and have a process setup for this to take care of it.
Anyway, I am trying to write a Test Method that throws a DbException (which is the exception that is thrown when the linked server is not connected) to test the process which I wrote when the linked server is disconnected. Is there a way to force throw a certain type of exception so I can test my code?
The try catch block looks something like this:
try
{
//Regular Processing and attempt to update to DB2
}
catch (DbException ex)
{
//Other processing to catch a linked server issue
}
catch (Exception ex)
{
//Even more processing for other exceptions
}
It's the same method as most unit testing, Inject your dependency via an interface, put your real db logic in one class based on that interface, and your
test stuff in another based on that interface.
interface IDBProcessor
{
void Process()
}
class ThrowyClass : IDBProcessor
{
public Exception ThrowThis {get; set;}
public void Process()
{
throw ThrowThis;
}
}
void MyMethod(IDBProcessor processor)
{
try
{
processor.Process()
}
catch (DbException ex)
{
//Other processing to catch a linked server issue
}
catch (Exception ex)
{
//Even more processing for other exceptions
}
}
Then in your unit test, Make a ThrowyClass with the exception you want and pass it in. ( There are mocking frameworks that will save you from making a Test class if you like).
[Test]
void MyThrowTest()
{
var throwy = new ThrowyClass() { ThrowThis = new SomeSpecificException() };
var myClass = new MyClass()
myClass.MyMethod(throwy);
// Assert what you expect
}
You will have to customize things to your specific application. You may wish to inject the IProcessor in the constructor of "MyClass"
You can simply throw it like this way :
throw new DbException();
You should take a look at IDbConnection and try the Moq framework
your code should like the following
var dbConnectionMock = new Mock<IDbConnection>();
dbConnectionMock.Setup(x => x.Open())
.Callback(() => {
throw new SqlException();
}).Verifiable();
https://github.com/Moq/moq4/wiki/Quickstart

code duplication in try catch block

Is there a better way to catch exceptions? I seem to be duplicating a lot of code. Basically in every controller I have a catch statement which does this:
try
{
Do something that might throw exceptions.
}
catch (exception ex)
{
Open database connection
Save exception details.
If connection cannot be made to the database save exception in a text file.
}
I have 4 controllers and around 5-6 actions methods in each controller which is a lot of code duplication. How can I trim down on the amount of line in the try catch statement above?
You could make use of Extension methods here.
Create an extension method in a new class.
public static class ExtensionMethods
{
public static void Log(this Exception obj)
{
// log your Exception here.
}
}
And use it like:
try
{
}
catch (Exception obj)
{
obj.Log();
}
You don't need to put try/catch blocks on every method. That's tedious and painful! Instead you can use the Application_Error event of Global.asax for logging the exceptions. The code below is the sample implementation which can be used to catch exceptions that occur in your web application.
protected void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();
if (!string.IsNullOrWhiteSpace(error.Message))
{
//do whatever you want if exception occurs
Context.ClearError();
}
}
I would like also to stress that "Handled exception" especially trying to put try/catch blocks on most methods is one of the "Top 3 silent performance killers for IIS / ASP.NET apps" as explained in this blog http://mvolo.com/fix-the-3-high-cpu-performance-problems-for-iis-aspnet-apps/
What you are trying to do is called a cross-cutting concern. You are trying to log any error that happens anywhere in your code.
In ASP.NET MVC cross-cutting concerns can be achieved by using Filters. Filters are attributes that can be applied globally, to a controller or to a method. They run before an action method executes or after it.
You have several types of filters:
Authorization filters, they run to check if the user is allowed to access a resource.
Action filters, these run before and after an action method executes.
Result filters, these can be used to change the result of an action method (for example, add some extra HTMl to the output)
Exception filters run whenever an exception is thrown.
In your case, you are looking for exception filters. Those filters only run when an exception happens in in an action method. You could apply the filter globally so it will automatically run for all exceptions in any controller. You can also use it specifically on certain controllers or methods.
Here in the MSDN documentation you can find how to implement your own filters.
Personally, since I greatly dislike try/catch blocks, I use a static Try class that contains methods that wrap actions in reusable try/catch blocks. Ex:
public static class Try {
bool TryAction(Action pAction) {
try {
pAction();
return true;
} catch (Exception exception) {
PostException(exception);
return false;
}
}
bool TryQuietly(Action pAction) {
try {
pAction();
return true;
} catch (Exception exception) {
PostExceptionQuietly(exception);
return false;
}
}
bool TrySilently(Action pAction) {
try {
pAction();
return true;
} catch { return false; }
}
// etc... (lots of possibilities depending on your needs)
}
I have used a special class in my applications that is called ExceptionHandler, in the class that is static I have some methods to handle application's exceptions. It gives me an opportunity to centralize exception handling.
public static class ExceptionHandler
{
public static void Handle(Exception ex, bool rethrow = false) {...}
....
}
In the method you can log the exception, rethrow it, replace it with another kind of exception, etc.
I use it in a try/catch like this
try
{
//Do something that might throw exceptions.
}
catch (exception ex)
{
ExceptionHandler.Handle(ex);
}
As Wouter de Kort has rightly stated in his answer, it is cross-cutting concern, so I've put the class in my Application Layer and have used it as a Service. If you defined the class as an interface you would be able to have different implementations of it in different scenarios.
Also you can use Singleton pattern:
sealed class Logger
{
public static readonly Logger Instance = new Logger();
some overloaded methods to log difference type of objects like exceptions
public void Log(Exception ex) {}
...
}
And
Try
{
}
Catch(Exception ex)
{
Logger.Instance.Log(ex);
}
Edit
Some peoples don't like Singleton for reasonable grounds.instead of singleton we can use some DI:
class Controller
{
private ILogger logger;
public Controller(ILogger logger)
{
this.logger = logger;
}
}
And use some DI library that will inject one instance of ILogger into your controllers.
I like the answers suggesting general solutions, however I would like to point out another one which works for MVC.
If you have a common controller base (wich you should anyways, it's a Best Practice IMO). You can simply override the OnException method:
public class MyControllerBase : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
DoSomeSmartStuffWithException(filterContext.Exception);
base.OnException(filterContext);
}
}
Then simply inherit your normal controllers from your common base instead of Controller
public class MyNormalController : MyControllerBase
{
...
If you like this you can check out the Controller class for other handy virtual methods, it has many.
In ASP .NET MVC you can implement your own HandleErrorAttribute to catch all the exceptions that occur in all controllers:
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var ex = filterContext.Exception;
// Open database connection
// Save exception details.
// If connection cannot be made to the database save exception in a text file.
}
}
Then register this filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
}
}
And of-course call the register method on application start-up:
public class MvcApplication : HttpApplication
{
protected override void OnApplicationStarted()
{
// ...
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// ...
}
}
Wouter de Kort has already explained the concept behind this in his answer.

Categories