Search code examples
c#dependency-injectionn-tier-architecture

Dependency Injection on an N-Tier solution - Remove Boilerplate


I am creating a solution that has an API (Microsoft.NET.Sdk.Web), domain (Microsoft.NET.Sdk), and MVC projects (Microsoft.NET.Sdk.Web) targeting .NET 8.

In my domain I have two classes that look like this:

public class ApplicationUserQuery
{

    private readonly string _connectionString;

    public ApplicationUserQuery(string connectionString)
    {
        _connectionString = connectionString;
    }

    // ...
}

public class ApplicationUserService
{

    private readonly ApplicationUserQuery _applicationUserQuery;

    public ApplicationUserService(ApplicationUserQuery applicationUserQuery)
    {
        _applicationUserQuery = applicationUserQuery;
    }

    // ...
}

To use the classes in my API project I am doing the following in my Program.cs:

var applicationDatabaseConnectionString = builder.Configuration.GetConnectionString("ApplicationDatabase");
if (applicationDatabaseConnectionString == null)
{
    throw new ArgumentNullException(nameof(applicationDatabaseConnectionString));
}
builder.Services.AddScoped(_ => new ApplicationUserQuery(applicationDatabaseConnectionString));
builder.Services.AddScoped<ApplicationUserService>();

This works, but it seems like a lot of boilerplate just for two classes and will continue to grow for every service/query class I create in my domain. Is there anyway to simplify this using the built-in .NET core stuff? I'm wanting to avoid using a 3rd party library like Ninject because of issues I have had with Ninject in particular on projects I do at work.


Solution

  • The .NET Extensions DI is intended to be used like the example you provided. It is a rudimentary tool that you can build upon if you like, it has very little opinions. Features like named (keyed) services was just introduced in .NET 8, years after initial release.

    If you want to auto-register the dependencies, use a different library or implement it yourself - e.g. take the domain Assembly, enumerate all types that end with "Query" and register them as scoped, it's not that much code and you have it under your control.