Part 1 – ASP.NET Core Dependency Injection

In this article, I won’t explain what is dependency injection (DI). I will try to explain how DI in ASP.NET Core works what can we do with it and how we can use other DI containers (Autofac and Castle Windsor) with ASP.NET Core.ASP.NET Core provides a minimal feature set to use default services cotainer. But you want to use different DI containers, because DI in ASP.NET Core is vey primitive. For example, it dosn’t support property injection or advanced service registering methods.

Let’s go to the examples and try to understand basics of DI in ASP.NET Core.

class Program
{
    static void Main(string[] args)
    {
        IServiceCollection services = new ServiceCollection();
 
        services.AddTransient<MyService>();
 
        var serviceProvider = services.BuildServiceProvider();
        var myService = serviceProvider.GetService<MyService>();
 
        myService.DoIt();
    }
}
 
public class MyService
{
    public void DoIt()
    {
        Console.WriteLine("Hello MS DI!");
    }
}

IServiceCollection is the collection of the service descriptors. We can register our services in this collection with different lifestyles (Transient, scoped, singleton)

IServiceProvider is the simple built-in container that is included in ASP.NET Core that supports constructor injection by default. We are getting regisered services with using service provider.

Service Lifestyle/Lifetimes

We can configure services with different types of lifestyles like following.

Transient

This lifestyle services are created each time they are requested.

Scoped

Scoped lifestyle services are created once per request.

Singleton

A singleton service is created once at first time it is requested and this instance of service is used by every sub-requests.

Let’s try to understand better with doing some examples. First, I am creating service classes.

public class TransientDateOperation
{
    public TransientDateOperation()
    {
        Console.WriteLine("Transient service is created!");
    }
}
 
public class ScopedDateOperation
{
    public ScopedDateOperation()
    {
        Console.WriteLine("Scoped service is created!");
    }
}
 
public class SingletonDateOperation
{
    public SingletonDateOperation()
    {
        Console.WriteLine("Singleton service is created!");
    }
}

Then I will create a service provider, register services and get these services with different lifestyle.

static void Main(string[] args)
{
    Demo2();
}
 
private static void Demo2()
{
    IServiceCollection services = new ServiceCollection();
 
    services.AddTransient<TransientDateOperation>();
    services.AddScoped<ScopedDateOperation>();
    services.AddSingleton<SingletonDateOperation>();
 
    var serviceProvider = services.BuildServiceProvider();
 
    Console.WriteLine();
    Console.WriteLine("-------- 1st Request --------");
    Console.WriteLine();
 
    var transientService = serviceProvider.GetService<TransientDateOperation>();
    var scopedService = serviceProvider.GetService<ScopedDateOperation>();
    var singletonService = serviceProvider.GetService<SingletonDateOperation>();
 
    Console.WriteLine();
    Console.WriteLine("-------- 2nd Request --------");
    Console.WriteLine();
 
    var transientService2 = serviceProvider.GetService<TransientDateOperation>();
    var scopedService2 = serviceProvider.GetService<ScopedDateOperation>();
    var singletonService2 = serviceProvider.GetService<SingletonDateOperation>();
 
    Console.WriteLine();
    Console.WriteLine("-----------------------------");
    Console.WriteLine();
}

I created service instances two times to see which one is recreating. And the result is;

demo2

As you can see, when I try to create services second time, only transient service is recreated but scoped and singleton aren’t created again. But in this example, it isn’t clear scoped service life time. In this example, both first instance and second instance are in the same scope. Let’s do another example to understand better for scoped service instances. I am modify the demo like following;

private static void Demo3()
{
    IServiceCollection services = new ServiceCollection();
 
    services.AddTransient<TransientDateOperation>();
    services.AddScoped<ScopedDateOperation>();
    services.AddSingleton<SingletonDateOperation>();
 
    var serviceProvider = services.BuildServiceProvider();
 
    Console.WriteLine();
    Console.WriteLine("-------- 1st Request --------");
    Console.WriteLine();
 
    using (var scope = serviceProvider.CreateScope())
    {
        var transientService = scope.ServiceProvider.GetService<TransientDateOperation>();
        var scopedService = scope.ServiceProvider.GetService<ScopedDateOperation>();
        var singletonService = scope.ServiceProvider.GetService<SingletonDateOperation>();
    }
 
    Console.WriteLine();
    Console.WriteLine("-------- 2nd Request --------");
    Console.WriteLine();
 
    using (var scope = serviceProvider.CreateScope())
    {
        var transientService = scope.ServiceProvider.GetService<TransientDateOperation>();
        var scopedService = scope.ServiceProvider.GetService<ScopedDateOperation>();
        var singletonService = scope.ServiceProvider.GetService<SingletonDateOperation>();
    }
 
    Console.WriteLine();
    Console.WriteLine("-----------------------------");
    Console.WriteLine();
}

And result:

demo3

As you can see, scoped service instance is created more than one times in different scopes.

In this part, we tried to understand ASP.NET Core DI service provider, service collection and service registering lifestyle/lifetime.

In next part, I will do more examples about IServiceCollection and IServiceProvider to understand better how DI mechanism of ASP.NET Core is working.

Project source: ASP.NET Core Dependency Injection Training

#net-core, #asp-net-core, #dependency-injection, #service-collection, #service-provider