Coming soon!

Keep your ASP.NET Core startup project clean

  • aspnetcore
  • programming
  • net-core
  • entity-framework-core
  • inversion-of-control

By Benjamin Todts · 3/13/2018 8:37:28 PM (Original Post)

Avoid unnecessary dependencies using IServiceCollection extensions

From the start, ASP.NET Core was designed to leverage dependency-injection, providing a built-in container to hold your services.

ConfigureServices

Consider we have an ASP.NET Core Web API project, with the following projects:

  • Foo.API
    This Web API project is our application’s Startup project. It contains the outer API-layer that will be exposed publicly.
  • Foo.Domain
    This project is a class library, holding objects that belong to our domain. This includes any models as well as interfaces for e.g. services, repositories,…
  • Foo.Infrastructure
    Another class library, containing the infrastructure-layer of our project.
    Amongst others, this layer defines implementations for interfaces defined in our domain (not necessarily all of them).
  • Foo.Infrastructure.EntityFramework
    This project represents an extensions of the Infrastructure layer, containing Entity Framework-specific code.

The reason for this setup is, among others, inversion of control. Our domain works with interfaces, the actual implementation is inverted and defined in separate assemblies.

Inversion Of Control

Our API’s Startup class is as follows:

This ConfigureServices method is responsible for registering any services your app needs. Note that it has quite a few framework services registered by default.

Take a closer look at how we register our ApplicationDbContext: services.AddDbContext(options => options.UseSqlServer(…).

Remember that this method is part of our API project. While registering services, this project is fully aware that we are working with Entity Framework and using SqlServer. What’s more, for this to work, our API project actually needs to reference the Microsoft.EntityFrameworkCore assembly.

This breaks our carefully constructed inversion of control — why have a separate Foo.Infrastructure.EntityFramework project if our API has a dependency on Microsoft.EntityFrameworkCore anyway?

ServiceCollectionExtensions

Obviously, I wouldn’t be writing this blogpost if there was no elegant way around this.

Let’s inspect the ConfigureServices method signature: public void ConfigureServices(IServiceCollection services).
This services parameter is what provides access to ASP.NET Core’s underlying container. What’s better: we can easily write our own extensions for this IServiceCollection interface.

Let’s create such an extension in our Foo.Infrastructure.EntityFramework project:

Now let’s update our API’s startup class:

Great! Our API project no longer needs a dependency on Microsoft.EntityFrameworkCore, all it needs is a reference to our own Foo.Infrastructure.EntityFramework project. Notice that I purposefully named this method AddDataAccessServices as opposed to e.g. AddEntityFramework. Naming it the latter would feel like a leaky abstraction — if I were to switch to another ORM, say Nhibernate, I simply have to define a similar AddDataAccessServices method and create the reference to get this to work.

AddInfrastructureServices

I tend to create such extensions in every class library, even when said libraries don’t wrap a framework or third party dependency. In the example of our Foo API, I would also create an extension called AddInfrastructureServices to register the EmailSender.

That’s it! Using this elegant solution allows you to keep your container bootstrapping in your designated startup project, without violating pretty much every part of the SOLID acronym.

Since you’ve made it this far, I’m assuming you enjoyed reading this.
Thank you for taking your time, and don’t forget to 👏!


  • aspnetcore
  • programming
  • net-core
  • entity-framework-core
  • inversion-of-control

By Benjamin Todts · 3/13/2018 8:37:28 PM (Original Post)

Share this blogpost

Looking for talent?

Fill in the form below and we’ll get back to you as soon as possible.

Oops. You seem to have written your full name in invisible ink. Please enter it so we can read it. Oops. You seem to have written your company in invisible ink. Please enter it so we can read it. It seems your e-mail doesn’t exist. Please enter a real one so we can contact you. Oops. You seem to have written your telephone in invisible ink. Please enter it so we can read it.