Back to all posts

Managing Dependency Injection in .NET Core

Posted on May 02, 2018

Posted in category:
Development
.NET

.NET Core's support for Dependency Injection is quite amazing. However, I still see projects that implement some bizarre solutions for things that are not that complicated. One of these items is how you configure dependency injection for assemblies that make up a project but might not be part of the main project.

What I've Seen

Many times, developers will not think about how/when things might get wired up. Due to this, I have seen some situations where a web project has a startup method that is hundreds, if not thousands, of lines long filled with "services.AddTransient..." calls for every single sub-library within the project. Other solutions have been more creative. However, they all share the limitation that the web project must know about the architecture of every referenced assembly.

Why This is Bad?

My primary concern with this approach is that we create a hard-dependency between the web, and other projects, inside of a solution. This isn't always a horrible thing if you have optional implementations that are truly configurable by an application. However, if you have a situation where there is a single implementation, it would be far better for the referenced assembly to expose a method for the web project to simply say "Hey assembly B, register your services!" This is easy and makes for a smooth approach.

The Setup

Within your referenced project it is necessary to ensure that you have the Options.ConfigurationExtensions package installed. You can install this using the following command.

Package Install
Install-Package Microsoft.Extensions.Options.ConfigurationExtensions

Exposing a Configuration Source

Assuming you have a project with a WebProject (ProjectWeb) and a class library project (ProjectB), we can add the following code to the ProjectB solution.

New Configuration Method
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class StartupExtensions
    {
        public static void RegisterProjectBBServices(this IServiceCollection services,
            IConfiguration configuration)
        {
            //Do your setup here
            services.AddTransient<IMobileDataService, MobileDataService>();
        }
    }
}

Looking at this example, first of all, we are placing this inside of the Microsoft.Extensions.DependencyInjection namespace, this makes discoverability in ProjectWeb much easier. In this class, we create an extension method that allows us to configure our application. In here, you can register all of your services. The above example registers an IMobileDataService; you can add any more needed.

Once this is done, inside of your Startup.cs file in your ProjectWeb you can use a single line of code to register all needed services.

services.RegisterProjectBServices(Configuration);

Given the namespace that you added your extension method in, everything will just work.

In Summary

Although still not a perfect solution, we can separate concerns allowing our referenced assemblies to configure themselves. By doing this, we can better achieve portability for libraries that might be used on both a Web and Console or another context. Avoiding duplicate code, and the dreaded "no binding found" messages. I hope this helps!