Injection Dependency: Bring your own container in .NET Core console App, example with Simple Injector

Introduction of Simple Injector

Simple Injector is an easy-to-use Dependency Injection (DI) library for .NET that supports .NET Core, Xamarin, Mono and Universal apps. Simple Injector is easily integrated with frameworks such as Web API, MVC, WCF, ASP.NET Core and many others. It’s easy to implement the dependency injection pattern with loosely coupled components using Simple Injector.

Why Simple Injector? It’s simple to use, free, fast, support advanced generics types, and provide powerful diagnostics services.

If you want to know more about you can check the documentation here: https://simpleinjector.readthedocs.io/en/latest/quickstart.html

Installation of Simple Injector in a console app

Select and Install it from “Manage Nuget packages” panel

or type the following command in “Package manager console”:

PM> Install-Package SimpleInjector -Version 4.0.12

Configuration of Simple Injector in a console app

  • Import SimpleInjector and SimpleInjector.Lifestyles namespaces
  • Add a static Container property in your class Program
  • Register your service with its appropriate Interface, Simple Injector supports concrete injection (the class without its interface)
  • Optionnally add Verify method, it iterates registered service to check if something is not correct, will throw an exception before any execution of the progam
  • Then use GetInstance method to get your service

Example :

public interface IMyService
{
   string HelloWorld();
}
public class MyService: IMyService
{
   public string HelloWorld()
   {
      return "Hello world!";
   }
}
using SimpleInjector;
using System;

namespace ConsoleAppDemoWithSimpleInjector
{
   class Program
   {
      static readonly Container container;

      static Program()
      {
         container = new Container();

         container.Register<IMyService, MyService>();

         container.Verify();
      }

      static void Main(string[] args)
      {
         var service = container.GetInstance<IMyService>();
         Console.WriteLine(service.HelloWorld());
         Console.ReadLine();
      }
   }
}

Execution:

Configuration of Simple Injector in a console app thats runs undefinitely

In the absence of any framework code, you are yourself responsible to tell Simple Injector that certain code must run in isolation. This can be done with Scoping. There are two types of scoped lifestyles that can be used. ThreadScopedLifestyle allows wrapping code that runs on a single thread in a scope, where AsyncScopedLifestyle allows wrapping a block of code that flows asynchronously (using async await).

The following example demonstrates a simple Console application that runs indefinitely, and executes a request every second. The request is wrapped in a scope:

class Program
{
   static readonly Container container;

   static Program()
   {
      container = new Container();
      container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();

      container.Register<IMyService, MyService>();

      container.Verify();
   }

   static void Main(string[] args)
   {
      while (true)
      {
         using (ThreadScopedLifestyle.BeginScope(container))
         {
            var service = container.GetInstance<IMyService>();

            Console.WriteLine(service.HelloWorld());
         }

         Thread.Sleep(TimeSpan.FromSeconds(1));
      }
   }
}

By default the lifecycle of our service is Transient, it means that a new instance will be created each we ask an instance of our service, else you can set Singleton.

Transient lifestyle

container.Register<IMyService, MyService>(Lifestyle.Transient);

or

container.Register<IMyService, MyService>();

Singleton lifestyle

container.Register<IMyService, MyService>(Lifestyle.Singleton);

Example that display Guid of the instance:

public class MyService: IMyService
{
   private Guid _guid;

   public MyService()
   {
      _guid = Guid.NewGuid();
   }

   public string HelloWorld()
   {
      return $"Hello world! instance: {_guid}";
   }
}

Execution :

Transient lifestyle

Guid are not identicals

Singleton lifestyle

Guid are identicals

 

Simple isn’it ? 🙂