DEV Community

Michael Brennan
Michael Brennan

Posted on

Harnessing Extension Methods for DI in Clean Architecture with .NET

In the world of .NET development, maintaining clean, readable, and maintainable code is crucial—especially when working with a clean architecture approach. One powerful technique to achieve this is by leveraging extension methods for initializing the Dependency Injection (DI) container.

Here's why using extension methods to set up your DI container is so effective:

1. Keeps Program.cs Clean and Simple

When setting up DI in your .NET applications, the Program.cs file can quickly become cluttered with various service registrations. By moving these registrations into extension methods, you can significantly reduce the noise in Program.cs, making it easier to read and manage. This approach aligns with the principles of clean architecture by ensuring that each part of your application has a single responsibility.

2. Encapsulates DI Setup Code

Extension methods allow you to encapsulate your DI setup code, keeping it close to the actual code it relates to. For example, if you have a service layer, you can create an extension method that registers all the services within that layer. This keeps your DI configurations organized and ensures that the registration logic is easy to locate and update.

3. Enhances Reusability and Modularity

With extension methods, you can create reusable DI configurations that can be shared across multiple projects or applications. This modular approach is particularly beneficial in microservice architectures, where services often share common configurations like logging, caching, or database setups.

Example in Action:

Here’s how you might organize your Program.cs file using extension methods:

var builder = WebApplication.CreateBuilder(args);

// Clean and modular DI setup
builder.Services
    .AddDatabaseServices(builder.Configuration)
    .AddApplicationServices()
    .AddRepositoryServices()
    .AddThirdPartyServices();

var app = builder.Build();
// Remaining middleware configuration...
Enter fullscreen mode Exit fullscreen mode

And here’s how the extension methods might look:

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddDatabaseServices(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddDbContext<AppDbContext>(options =>
            options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));

        return services;
    }

    public static IServiceCollection AddApplicationServices(this IServiceCollection services)
    {
        services.AddTransient<IUserService, UserService>();
        services.AddTransient<IOrderService, OrderService>();

        return services;
    }

    public static IServiceCollection AddRepositoryServices(this IServiceCollection services)
    {
        services.AddScoped<IUserRepository, UserRepository>();
        services.AddScoped<IOrderRepository, OrderRepository>();

        return services;
    }

    public static IServiceCollection AddThirdPartyServices(this IServiceCollection services)
    {
        services.AddHttpClient("GitHub", client =>
        {
            client.BaseAddress = new Uri(configuration["GitHubApi:BaseAddress"]);
            client.DefaultRequestHeaders.UserAgent.ParseAdd(configuration["GitHubApi:UserAgent"]);
        });

        return services;
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Using extension methods for DI setup not only keeps your Program.cs clean and focused but also promotes better code organization, modularity, and reusability. By encapsulating your DI logic into extension methods, you ensure that your application’s architecture remains scalable and maintainable.

dotnet #cleanarchitecture #dependencyinjection #softwareengineering #csharp #codingtips #programming

Top comments (0)