Dependent Injection in.NET: Life Cycle

The sample code for this article uses. NET 6, specific code can be in this repository Articles.DI Get in.

In the previous article, services were used uniformly when registering services. AddSingleton <TService, TImplementation>() to register services, what is the specific meaning of this method? Are there any other similar approaches? And we also have a question, what is the life cycle of a service when a container constructs it? Is the service constructed once when it is applied for? Or the entire program cycle, constructed only once? What if we want to customize that each service has a different life cycle? Next, we'll explore the life cycle of a service together.

life cycle

When registered with a container, there are three life cycles of a service

life cycle When to create Call Method
Instantaneous / Transient Each request creates a new instance AddTransient()
Scoped / Scoped Within the specified range, an instance is created on the first request
When a request is repeated, the same instance is returned
AddScoped()
Singleton Only once is created throughout the program life cycle
All subsequent requests will return the same instance
AddSingleton()

Referring to the actual code, we can have a more intuitive understanding of the three life cycles in Dependent Injection, which can be found in Microsoft. Find the corresponding article in the NET document: Tutorial: In. Use Dependent Injection in NET . Or you can do it here Warehouse View Get Source Directly in

// https://github.com/alva-lin/Articles.DI/tree/master/ConsoleApp1
// 01. Declare interfaces and implementation classes
public interface IOperation
{
    string OperationId { get; }
}

public interface ITransientOperation : IOperation {}

public interface IScopedOperation : IOperation {}

public interface ISingletonOperation : IOperation {}

public class DefaultOperation
    : ITransientOperation, IScopedOperation, ISingletonOperation
{
    // Create a Guid and take the last four characters
    public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
// 02.Create a service that relies on the operations above
public class OperationLogger
{
    private readonly ITransientOperation _transientOperation;
    private readonly IScopedOperation    _scopedOperation;
    private readonly ISingletonOperation _singletonOperation;

    public OperationLogger(ITransientOperation transientOperation,
                           IScopedOperation    scopedOperation,
                           ISingletonOperation singletonOperation)
    {
        _transientOperation = transientOperation;
        _scopedOperation    = scopedOperation;
        _singletonOperation = singletonOperation;
    }

    public void LogOperations(string scope)
    {
        LogOperation(_transientOperation, scope, "Always different");
        LogOperation(_scopedOperation, scope, "Changes only with scope");
        LogOperation(_singletonOperation, scope, "Always the same");
    }

    private static void LogOperation<T>(T operation, string scope, string message)
        where T : IOperation
    {
        Console.WriteLine($"{scope}: {typeof(T).Name,-19} [{operation.OperationId} {message,-23}]");
    }
}
// 03. Register the service and start the program
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateDefaultBuilder(args)
   .ConfigureServices(services =>
    {
        // Register the three Operation s as three declaration cycles
        services.AddTransient<OperationLogger>()
           .AddTransient<ITransientOperation, DefaultOperation>()
           .AddScoped<IScopedOperation, DefaultOperation>()
           .AddSingleton<ISingletonOperation, DefaultOperation>();
    })
   .Build();

ExemplifyScoping(host.Services, "Scope 1");
ExemplifyScoping(host.Services, "Scope 2");

await host.RunAsync();


static void ExemplifyScoping(IServiceProvider services, string scope)
{
    using IServiceScope serviceScope = services.CreateScope();
    IServiceProvider    provider     = serviceScope.ServiceProvider;

    var logger = provider.GetRequiredService<OperationLogger>();
    logger.LogOperations($"{scope}: Call 1 ...");
    Console.WriteLine();

    logger = provider.GetRequiredService<OperationLogger>();
    logger.LogOperations($"{scope}: Call 2 ...");
    Console.WriteLine();
}

Run the above code to get the following results

Scope 1: Call 1 ...: ITransientOperation [b672 Always different       ]
Scope 1: Call 1 ...: IScopedOperation    [afd8 Changes only with scope]
Scope 1: Call 1 ...: ISingletonOperation [21b3 Always the same        ]

Scope 1: Call 2 ...: ITransientOperation [b6fc Always different       ]
Scope 1: Call 2 ...: IScopedOperation    [afd8 Changes only with scope]
Scope 1: Call 2 ...: ISingletonOperation [21b3 Always the same        ]

Scope 2: Call 1 ...: ITransientOperation [ef31 Always different       ]
Scope 2: Call 1 ...: IScopedOperation    [46d1 Changes only with scope]
Scope 2: Call 1 ...: ISingletonOperation [21b3 Always the same        ]
 
Scope 2: Call 2 ...: ITransientOperation [9864 Always different       ]
Scope 2: Call 2 ...: IScopedOperation    [46d1 Changes only with scope]
Scope 2: Call 2 ...: ISingletonOperation [21b3 Always the same        ]

Comparing the log output of the program, you can see that the output of each ITransientOperation will be different. IScopedOperation outputs the same content in the same scope and different contents in different scopes. The last ISingletonOperation, the output is the same each time. This output also corresponds to what we have shown in the previous table.

Reference Links

Dependency Injection in.NET

Tutorial: In. Use Dependent Injection in NET

Keywords: .NET

Added by EOS on Mon, 17 Jan 2022 13:49:55 +0200