Dependency injection in .NET Core console applications

ASP.NET Core uses built-in dependency injection mechanism provided by Microsoft. This blog post intorduces how to use same mechanism in .NET Core console applications. For those who like other DI/IoC frameworks this writing provides demo about how to use Autofac with .NET Core framework-level dependency injection.

Framework-level dependency injection in ASP.NET Core

I don’t describe here details of dependency injection in ASP.NET Core. Those who want to find out more about it can skim through these writings:

Dependency injection in .NET Core console applications

We can use same dependecy injection mechanism also in .NET Core command line applications. Although we don’t have there anything prepared for us it’s very easy to put up something similar to web applications. Actually I prefer to use more lightweight approach for console applications.

Before writing any code we need Nuget package for dependency injection components:

  • Microsoft.Extensions.DependencyInjection

At very basic level we can create dependency injection service provider using the following code.

static void Main(string[] args)
{
     var collection = new ServiceCollection();
     collection.AddScoped<IDemoService, DemoService>();
     // ...
     // Add other services
     // ...
     var serviceProvider = collection.BuildServiceProvider();      var service = serviceProvider.GetService<IDemoService>();
     service.DoSomething();      serviceProvider.Dispose();
}

NB! Calling Dispose() on service provider is mandatory as otherwise registered instances will not get disposed. Keep this in mind.

Preparing for disposables and third-party dependency injection frameworks

Solution above works but it has one problem – it doesn’t consider possible use of third-party service providers. As ServiceProvider class is sealed and third-parties cannot extend it they must use IServiceProvider interface.

public interface IServiceProvider
{
     object GetService(Type serviceType);
}

Convenience methods like GetService<T>() are defined in ServiceProviderServiceExtensions class.

public static class ServiceProviderServiceExtensions
{
     public static IServiceScope CreateScope(this IServiceProvider provider);
     public static object GetRequiredService(this IServiceProvider provider, Type serviceType);
     public static T GetRequiredService<T>(this IServiceProvider provider);
     public static T GetService<T>(this IServiceProvider provider);
     public static IEnumerable<T> GetServices<T>(this IServiceProvider provider);
     public static IEnumerable<object> GetServices(this IServiceProvider provider, Type serviceType);
}

IServiceProvider doesn’t use IDisposable and therefore it doesn’t have Dispose() method. Still classes that extend this interface may also extend IDisposable but we don’t know it. To consider this possibility we have to implement disposing of service provider a little different way.

static void Main(string[] args)
{
     var collection = new ServiceCollection();
     collection.AddScoped<IDemoService, DemoService>();
     // ...
     // Add other services
     // ...
     IServiceProvider serviceProvider = collection.BuildServiceProvider();      var service = serviceProvider.GetService<IDemoService>();
     service.DoSomething();      if (serviceProvider is IDisposable)
     {
         ((IDisposable)serviceProvider).Dispose();
     } }

Now our code supports disposing of disposable service providers but we have still room to make things better.

Getting code cleaner

Main() method is currently messed up with all details of dependency injection. In real projects we have probably many services in service collection and filling this collection is worth separate method. Also I don’t like to have service provider disposing logic in Main() method.

class Program
{
     private static IServiceProvider _serviceProvider;

     static void Main(string[] args)
     {
         RegisterServices();

         var service = _serviceProvider.GetService<IDemoService>();
         service.DoSomething();          DisposeServices();
     }      private static void RegisterServices()
     {
         var collection = new ServiceCollection();
         collection.AddScoped<IDemoService, DemoService>();
         // ...
         // Add other services
         // ...
         _serviceProvider = collection.BuildServiceProvider();      }      private static void DisposeServices()      {          if(_serviceProvider == null)          {              return;          }          if (_serviceProvider is IDisposable)          {              ((IDisposable)_serviceProvider).Dispose();          }      } }

Things are better now as Main() method is cleaner.

Using Autofac

Back in time I wrote about how to use Structuremap and Autofac with ASP.NET Core. Using Autofac is simple and we need only small changes in our code to make it work.

First thing is to add Autofac NuGet packages to .NET Core console application project.

  • Autofac
  • Autofac.Extensions.DependencyInjection

With Autofac packages in place we can change RegisterServices method to use Autofac.

private static void RegisterServices()
{
     var collection = new ServiceCollection();
     var builder = new ContainerBuilder();

     builder.RegisterType<DemoService>().As<IDemoService>();
     //
     // Add other services ...
     //
     builder.Populate(collection);

     var appContainer = builder.Build();

     _serviceProvider = new AutofacServiceProvider(appContainer);
}

We don’t need modifications to any other part of code. With these changes done and compiled our application uses Autofac now.

Wrapping up

Dependency injection mechanism provided by Microsoft with .NET Core is popular in ASP.NET but it can be used also in other types of .NET Core projects. It’s actually very easy to get dependency injection work as we need only small amount of code. In real applications biggest part of related code is about registering types. We were also able to use Autofac as third-party dependency injection framework. It was easy and we made only minor changes to our existing code.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    2 thoughts on “Dependency injection in .NET Core console applications

    • July 29, 2019 at 5:51 pm
      Permalink

      Thank you Gunnar!

      Excelent Explanation! Now im improving my windows services applications with D.I.

      You helped me a lot too.

    Leave a Reply

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