We Do Tech, stuff.

Small business web and system solutions.

Free programs, software reviews, and tech, stuff.

Generic Dependency Injection in .Net Core

by: Dan Orlovsky
Posted On: 11/12/2018 6:13:17 PM

With a generic interface, you can create new App Services and Managers without having to add each dependency manually!


I find dependency injection to be quite a useful pattern.  It also happens to be a pattern utilized in many of the code bases I've found myself using the most often.  Asp.Net Boilerplate and nopCommerce to name a couple, which use Castle Windsor and AutoFac respectively.

It wasn't until I started digging into .Net Core 2.1's native dependency injection that I realized, with a relatively small amount of work, you can write powerful applications that do a great deal of the heavy lifting for you!

The Problem Space

My goal is to get a better handle in .Net Core and Angular.  One way I enjoy familiarizing myself with new technology is to try and create a workable Content Management System.  I created a User, and Blog entity.  My IRepository interface and Repository object.  A UserService and a BlogService.  I've barely gotten off the ground and now have 4 separate objects to register in the IoC controller!

My startup.cs class (which of course, this stuff can and should be moved to a configuration object) is already starting to become a mess, and I've barely created any functionality!

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddDbContext<ngCmsDbContext>(options => 
              options.UseSqlServer(Configuration.GetConnectionString("ngCmsConnectionString"), c => c.MigrationsAssembly("ngCmsBase.Web")));
            
    services.AddScoped(typeof(IRepository<Blog, long>), typeof(Repository<Blog, long>));
    services.AddScoped(typeof(IRepository<User, long>), typeof(Repository<User, long>));

    services.AddTransient(BlogService);
    services.AddTransient(UserService);
}

It's becoming apparent this is going to get out of hand and I am going to miss something - soon.  But, there's an easy fix!

The scoping of the repository was really easy.  I just removed the two lines for:

services.AddScoped(typeof(IRepository<,>), typeof(Repository<,>));

Registering the services, however, took a little more work and the magic of reflection.

First, I created an empty interface, and made my Services implement it.  I then use reflection to track down all the objects that implement that interface, and simply register them on the fly, like so:

My interface is named: IngServiceBase 

var type = typeof(IngServiceBase);
var types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(s => s.GetTypes())
                .Where(p => type.IsAssignableFrom(p) && !p.IsInterface);
foreach(var t in types)
{
    services.AddTransient(t);
}

Now, no matter how many Entites I make, they will all immediately be able to make use of the Repository.  And no matter how many services I write, so long as they implement the IngServiceBase interface, they are ready to be injected!


Dan Orlovsky

Self-taught full-stack developer and Visual Studio junkie specializing in C#, ASP.NET (WebForms and MVC), HTML5, and CSS3.  I design custom content management solutions for small-businesses looking to take control of their website.  Each project is built with the technical aptitude of the user in mind.

Currently a junior Software Design Engineer for a data company with a focus in Angular and C#.

 


Comments

Ad Space