Efficient Way of Writing Controlled Global Exceptions in .NET Core🕵
Tags: cleancode, architecture, netcoremiddleware, bestprectices
Published: 2023-07-17 14:02:15

**Introduction 📢**
**Hey folks!!!**
How are you all!!! Here I am with the new blog “Efficient Way of Writing Controlled Global Exceptions in.NET Core”.

In this **exciting** blog titled “Efficient Way of Writing Controlled Global Exceptions in.NET Core” I’ll share valuable insights on effectively managing exceptions in a **controlled** manner, resulting in a positive impact on your application. This article offers unique perspectives that you won’t find elsewhere. So, get ready to dive into some interesting learnings!

Make sure to pay attention to the specific use case I’ll discuss later in the article below.


**Why you need custom loggings**🤔
There are numerous reasons why you may desire these features, but for the sake of this article’s focus and objective, I won’t delve into all of them here. However, I will provide a list of some common reasons:

 1. Customizing logging **behavior**.
 2. Tracking **additional** contextual information.
 3. Logging to **multiple destinations** (_e.g., displaying informational logs in the console while storing only failed requests in the LoggingDB_).
 4. Improving logging **readability** for future analysis.
 5. **Integrating** and customizing behavior for multiple destinations (_e.g., storing informational logs in different databases and error logs in separate databases_).
 6. Presenting a **well-formatted** error structure to API users or consumers.


**Any other way to write global level logs other than Middleware way?**
**Yes**, you can implement `IExceptionFilter`. However, it's essential to understand the **fundamental** difference between `IExceptionFilter` and `CustomExceptionHandlerMiddleware `in terms of their execution within the request pipeline. Perhaps I will write another article that provides a detailed comparison and helps you choose between the two.

For now, the diagram below will give you a general understanding of when each component comes into play:
![CustomExceptionMiddleware Vs ExceptionFilter](https://cdn-images-1.medium.com/max/2000/1*lUI8-4LM9GCThQzC85jvEA.png)


**‘UseCase’ for the approach that I use✍:**
I have multiple microservices as a part of my big codebase. These multiple web API services will have almost same code for `GlobalExceptionHandlerMiddleware`, which basically handles unhandled exceptions at the request level.

However, I need to be **consistent** in terms of standard **HTTP response codes** so that I don’t violate **DRY** principles.

For the most commonly encountered exceptions, the best practices follow the following HTTP codes.
![](https://cdn-images-1.medium.com/max/2000/1*6ChdeV79fzgJCbBhxx4jXA.png)


**Let's architect this scenario into code 🏹:**
Yah! so, the idea is **to abstract** the most used exceptions along with their http code in a separate shared library.
Below, we have Three exception types in our **shared library** `DomainException `,`ApplicationException `and `InfrastructureException `.

And the consumers will inherit from below **Three** base exceptions.
![High level idea](https://cdn-images-1.medium.com/max/2000/1*KNY6mdUu-Rid5dy1cN62zw.png)

Write `DomainException` base
```csharp
[Serializable]
public abstract class DomainException: Exception {
    protected DomainException() {}
    
    protected DomainException(string message)
        : base(message) {}
    
    protected DomainException(string message, Exception exception)
        : base(message, exception) {}
}
```

Write `ApplicationException` base
```csharp
[Serializable]
public class ApplicationException: Exception {
    protected ApplicationException() {}

    protected ApplicationException(string message)
        : base(message) {}

    protected ApplicationException(string message, Exception exception)
        : base(message, exception) {}
}
```

Write `InfrastructureException `base
```csharp
    [Serializable]
    public class InfrastructureException: Exception {
        protected InfrastructureException() {}

        protected InfrastructureException(string message)
            : base(message) {}

        protected InfrastructureException(
            string message, Exception exception)
                : base(message, exception) {}
    }
```

    
Write Middleware implementation
```csharp
// GlobalExceptionHandlerMiddleware.cs

public class GlobalExceptionHandlerMiddleware {
    public async Task InvokeAsync(HttpContext context) {
        try {
            await _next(context).ConfigureAwait(false);
        } catch (DomainException ex) {
            await HandleException(context, ex, HttpStatusCode.BadRequest);
        } catch (ApplicationException ex) {
            await HandleException(context, ex, HttpStatusCode.InternalServerError);
        } catch (InfrastructureException ex) {
            await HandleException(context, ex, HttpStatusCode.ServiceUnavailable);
        } catch (ArgumentException ex) {
            await HandleException(context, ex, HttpStatusCode.BadRequest);
        } catch (Exception ex) {
            await HandleException(context, ex, HttpStatusCode.InternalServerError);
        }
    }

    private async Task HandleException(HttpContext httpContext, Exception exception, HttpStatusCode statusCode, bool logRequestBody = true) {
        // Log into Infra/Console/File etc
        WriteResponse(httpContext, statusCode);
    }

    //Modify and return request context
    private async Task WriteResponse(HttpContext httpContext, HttpStatusCode statusCode) {
        httpContext.Response.ContentType = "application/json";
        httpContext.Response.StatusCode = (int) statusCode;

        var responseModel = new {
            ..........
        };
        await httpContext.Response.WriteAsync(
            JsonSerializer.Serialize(responseModel, _seralizeSetting),
            Encoding.UTF8);
    }
}
```

        

```csharp
    //Expose an extension method from your shared library
    public static IApplicationBuilder UseGlobalExceptionHandling(
        this IApplicationBuilder app) {
        app.UseMiddleware<GlobalExceptionHandlerMiddleware>();
        return app;
    }
```

*Finally, Make sure your code line `app.UseGlobalExceptionHandeling()` as your first middleware in request pipeline.

**Enjoy using Exceptions from consumer code:**
![This is your Client/Consumer code](https://cdn-images-1.medium.com/max/2000/1*YmNPceUK65bRh_87pg0UQw.png)


**Summary**📚
I’m excited to share this blog titled “Efficient Way of Writing Controlled Global Exceptions in .NET Core”! In this article, I’ll provide valuable insights on how you can effectively manage exceptions in a controlled manner, ensuring a positive impact on your application.

We saw below points:
1. We were onto mission on: valuable **insights** on how you can effectively manage exceptions in a controlled manner.
2. We saw the ‘***why***’ part of ‘***need of custom logging***’.
3. Then we saw the **UseCase** of above approach I had written.
4. We saw the **HTTP codes** for general types of exceptions.
5. Then we also went through the **implementation** idea and the actual **hands-on code** by making our hands dirty.
6. **Above is just example in my perticular use case. You can have your own/different *ExceptionsTypes* that most suits in your context.🙌**