Built-in Dependency Injection Support with .NET Core

Built-in Dependency Injection Support with .NET Core

With .NET Core, gone are the days of needing a 3rd party solution to implement Dependency Injection (DI).  DI support is built-in to the .NET Core framework, but getting this wired-up is a bit different depending on if you’re using ASP.NET Core or some other .NET Core project type.

Here’s an overview of the pieces we want to wire up:

class library for DI

The above shows a .NET Core (1.0 RTM) class library named SomeClassLibrary which is referenced by both a console app and a web app.  The class library contains an interface for a WidgetService that gets Widget object data from a WidgetRepository.

The Widget is an object with two properties, Id and Name:

namespace SomeClassLibrary.Domain
{
    public class Widget
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

The SomeConsoleApp and SomeWebApp projects will be loosely coupled to the WidgetService and WidgetRepository, therefore they’ll programs against their respective interfaces.

Here’s a look at the IWidgetService interface:

using System.Collections.Generic;
using SomeClassLibrary.Domain;

namespace SomeClassLibrary.Application
{
    public interface IWidgetService
    {
        List<Widget> GetAllWidgets();
    }
}

All this interface is doing is defining a method named GetAllWidgets that returns a list of Widget objects.  The concrete WidgetService class then gets the Widgets via the injected IWidgetRepository:

using System.Collections.Generic;
using System.Linq;
using SomeClassLibrary.Domain;

namespace SomeClassLibrary.Application
{
    public class WidgetService : IWidgetService
    {
        private readonly IWidgetRepository widgetRepository;

        public WidgetService(IWidgetRepository widgetRepository)
        {
            this.widgetRepository = widgetRepository;
        }

        public List<Widget> GetAllWidgets()
        {
            return this.widgetRepository.GetAll().ToList();
        }
    }
}

The IWidgetRepository interface exposes a method named GetAll() that returns an IEnumerable of Widget:

using System.Collections.Generic;

namespace SomeClassLibrary.Domain
{
    public interface IWidgetRepository
    {
        IEnumerable<Widget> GetAll();
    }
}

The concrete implementation of the WidgetRepository returns a hard-coded list of Widgets for the purposes of our demonstration:

using System.Collections.Generic;

namespace SomeClassLibrary.Domain
{
    public class WidgetRepository : IWidgetRepository
    {
        public IEnumerable<Widget> GetAll()
        {
            // send back some hard-coded data
            return new List<Widget>
            {
                new Widget { Id = 1, Name = "First Widget" },
                new Widget { Id = 2, Name = "Second Widget" }
            };
        }
    }
}

Let’s Use DI in the ASP.NET Core App

ASP.NET Core makes DI very easy.  By convention, the Startup.cs class will run at the beginning of the application lifecycle.  By default it has a ConfigureServices method that runs using a IServiceCollection parameter.  To implement DI, simply add the NuGet package Microsoft.Extensions.DependencyInjection and call the AddScoped extension to map an interface to a concrete class.

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SomeClassLibrary.Domain;
using SomeClassLibrary.Application;

namespace SomeWebApp
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // add descriptors for interfaces
            services.AddScoped<IWidgetRepository, WidgetRepository>();
            services.AddScoped<IWidgetService, WidgetService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IWidgetService widgetService)
        {
            loggerFactory.AddConsole();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.Run(async (context) =>
            {
                // use the resolved Widget service
                List<Widget> widgets = widgetService.GetAllWidgets();

                // if everything resolved, print out the Name property value of the first widget
                await context.Response.WriteAsync(widgets.FirstOrDefault().Name);
            });
        }
    }
}

The above code tells the ASP.NET Core app what concrete classes to use per interface used in the ConfigureServices method (lines 20-21).  Then when the app runs the IWidgetService (which in this case is passed in to the Configure method) resolves its concrete implementation and the service can be used (line 37).

Now Let’s Use DI in a .NET Core Console App

Using DI in a ASP.NET Core web app is fairly straight-forward because you’re provided the benefit of Startup.cs and its built-in service collection availability.  A console app starts with a static Main method that doesn’t take in an IServiceCollection, so where do you start?  I started by Googling around and ran in to this excellent Derp Turkey blog post.  Go ahead and give it a read, because it explains DI in a console app much more in depth than I do here.  The main reason that I’m re-explaining it is because that post was written for a beta of .NET Core and a few NuGet package names have slightly changed.

First install the NuGet package for Microsoft.Extensions.DependencyInjection.  In the Main method, start by defining a new ServiceCollection object and then add your interface descriptors just like you did for the web app (lines 18-19 below).

Next you’ll need an IServiceProvider instance to wire-up the service collection (line 22 below).  After that, you have access to your service and all its methods.

using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using SomeClassLibrary.Application;
using SomeClassLibrary.Domain;

namespace SomConsoleApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // create service collection
            IServiceCollection services = new ServiceCollection();

            // add descriptors for interfaces
            services.AddTransient<IWidgetRepository, WidgetRepository>();
            services.AddTransient<IWidgetService, WidgetService>();

            // create service provider
            IServiceProvider provider = services.BuildServiceProvider();

            // resolve the IWidgetService
            IWidgetService service = provider.GetService<IWidgetService>();

            // use the resolved Widget service
            List<Widget> widgets = service.GetAllWidgets();

            // if everything resolved, the list of hard-coded widgts will come back from the WidgetService
            foreach (var widget in widgets)
            {
                Console.WriteLine("Widget Details:");
                Console.WriteLine("  Id:" + widget.Id);
                Console.WriteLine("  Name: " + widget.Name);
                Console.WriteLine("\n");
            }

            Console.Read();
        }
    }
}

The above will use service’s wired-up DI implementation to resolve the concrete classes and return the fake data we have in the WidgetRepository.

All these code samples are in GitHub.

 

Tags: Filled Under: Programming Posted on: June 30, 2016

One Comment on “Built-in Dependency Injection Support with .NET Core”

  • erw

    June 2, 2017 at 3:43 am

    NET Core’s built-in support for constructor-based dependency injection extends to MVC controllers.

  • Leave a Reply

    Your email address will not be published. Required fields are marked *