Sample code for the service lifecycle:
public class ServiceA : IServiceA.IDisposable
{
private readonly int _n;
public ServiceA(INumberService numberService)
{
_n = numberService.GetNumber();
Console.WriteLine($"ctor {nameof(ServiceA)}, {_n}");
}
public void A() => Console.WriteLine($"{nameof(A)}, {_n}");
public void Dispose() => Console.WriteLine($"disposing {nameof(ServiceA)}, {_n}");
}
public class ServiceB : IServiceB.IDisposable
{
private readonly int _n;
public ServiceB(INumberService numberService)
{
_n = numberService.GetNumber();
Console.WriteLine($"ctor {nameof(ServiceB)}, {_n}");
}
public void B() => Console.WriteLine($"{nameof(B)}, {_n}");
public void Dispose() => Console.WriteLine($"disposing {nameof(ServiceB)}, {_n}");
}
public class ServiceC : IServiceC.IDisposable
{
private bool _isDisposed = false;
private readonly int _n;
public ServiceC(INumberService numberService)
{
_n = numberService.GetNumber();
Console.WriteLine($"ctor {nameof(ServiceC)}, {_n}");
}
public void C()
{
if (_isDisposed)
throw new ObjectDisposedException("ServiceC");
Console.WriteLine($"{nameof(C)}, {_n}");
}
public void Dispose()
{
Console.WriteLine($"disposing {nameof(ServiceC)}, {_n}");
_isDisposed = true;
}
}
public class NumberService : INumberService
{
private int _number = 0;
public int GetNumber() => Interlocked.Increment(ref _number);
}
Copy the code
public class ControllerX : IDisposable
{
private readonly IServiceA _serviceA;
private readonly IServiceB _serviceB;
private readonly int _n;
private int _countm = 0;
public ControllerX(IServiceA serviceA, IServiceB serviceB, INumberService numberService)
{
_n = numberService.GetNumber();
Console.WriteLine($"ctor {nameof(ControllerX)}, {_n}");
_serviceA = serviceA;
_serviceB = serviceB;
}
public void M()
{
Console.WriteLine($"invoked {nameof(M)} for the {++_countm}. time");
_serviceA.A();
_serviceB.B();
}
public void Dispose() => Console.WriteLine($"disposing {nameof(ControllerX)}, {_n}");
}
Copy the code
public interface IServiceA
{
void A();
}
public interface IServiceB
{
void B();
}
public interface IServiceC
{
void C();
}
public interface INumberService
{
int GetNumber();
}
Copy the code
Call the output of SingletonAndTransient()
class Program
{
static void Main()
{
SingletonAndTransient();
}
private static void SingletonAndTransient()
{
Console.WriteLine(nameof(SingletonAndTransient));
ServiceProvider RegisterServices()
{
IServiceCollection services = new ServiceCollection();
services.AddSingleton<IServiceA, ServiceA>();
services.AddTransient<IServiceB, ServiceB>();
// services.AddSingleton<ControllerX>();
services.Add(new ServiceDescriptor(typeof(ControllerX), typeof(ControllerX), ServiceLifetime.Transient));
services.AddSingleton<INumberService, NumberService>();
return services.BuildServiceProvider();
}
using (ServiceProvider container = RegisterServices())
{
Console.WriteLine($"requesting {nameof(ControllerX)}");
ControllerX x = container.GetRequiredService<ControllerX>();
x.M();
x.M();
Console.WriteLine($"requesting {nameof(ControllerX)}"); ControllerX x2 = container.GetRequiredService<ControllerX>(); x2.M(); Console.WriteLine(); }}}Copy the code
SingletonAndTransient
requesting ControllerX
ctor ServiceA, 1
ctor ServiceB, 2
ctor ControllerX, 3
invoked M for the 1. time
A, 1
B, 2
invoked M for the 2. time
A, 1
B, 2
requesting ControllerX
ctor ServiceB, 4
ctor ControllerX, 5
invoked M for the 1. time
A, 1
B, 4
disposing ControllerX, 5
disposing ServiceB, 4
disposing ControllerX, 3
disposing ServiceB, 2
disposing ServiceA, 1
Copy the code
The output of the UsingScoped ()
class Program
{
static void Main()
{
UsingScoped();
}
private static void UsingScoped()
{
Console.WriteLine(nameof(UsingScoped));
ServiceProvider RegisterServices()
{
var services = new ServiceCollection();
services.AddSingleton<INumberService, NumberService>();
services.AddScoped<IServiceA, ServiceA>();
services.AddSingleton<IServiceB, ServiceB>();
services.AddTransient<IServiceC, ServiceC>();
return services.BuildServiceProvider();
}
using (ServiceProvider container = RegisterServices())
{
using (IServiceScope scope1 = container.CreateScope())
{
IServiceA a1 = scope1.ServiceProvider.GetService<IServiceA>();
a1.A();
IServiceA a2 = scope1.ServiceProvider.GetService<IServiceA>();
a2.A();
IServiceB b1 = scope1.ServiceProvider.GetService<IServiceB>();
b1.B();
IServiceC c1 = scope1.ServiceProvider.GetService<IServiceC>();
c1.C();
IServiceC c2 = scope1.ServiceProvider.GetService<IServiceC>();
c2.C();
}
Console.WriteLine("end of scope1");
using (IServiceScope scope2 = container.CreateScope())
{
IServiceA a3 = scope2.ServiceProvider.GetService<IServiceA>();
a3.A();
IServiceB b2 = scope2.ServiceProvider.GetService<IServiceB>();
b2.B();
IServiceC c3 = scope2.ServiceProvider.GetService<IServiceC>();
c3.C();
}
Console.WriteLine("end of scope2"); Console.WriteLine(); }}}Copy the code
UsingScoped
ctor ServiceA, 1
A, 1
A, 1
ctor ServiceB, 2
B, 2
ctor ServiceC, 3
C, 3
ctor ServiceC, 4
C, 4
disposing ServiceC, 4
disposing ServiceC, 3
disposing ServiceA, 1
end of scope1
ctor ServiceA, 5
A, 5
B, 2
ctor ServiceC, 6
C, 6
disposing ServiceC, 6
disposing ServiceA, 5
end of scope2
disposing ServiceB, 2
Copy the code
The output of the CustomFactories ()
class Program
{
static void Main()
{
CustomFactories();
}
private static void CustomFactories()
{
Console.WriteLine(nameof(CustomFactories));
IServiceB CreateServiceBFactory(IServiceProvider provider) =>
new ServiceB(provider.GetService<INumberService>());
ServiceProvider RegisterServices()
{
var numberService = new NumberService();
var services = new ServiceCollection();
services.AddSingleton<INumberService>(numberService); // add existing
services.AddTransient<IServiceB>(CreateServiceBFactory); // use a factory
services.AddSingleton<IServiceA, ServiceA>();
returnservices.BuildServiceProvider(); } using (ServiceProvider container = RegisterServices()) { IServiceA a1 = container.GetService<IServiceA>(); IServiceA a2 = container.GetService<IServiceA>(); IServiceB b1 = container.GetService<IServiceB>(); IServiceB b2 = container.GetService<IServiceB>(); } Console.WriteLine(); }}Copy the code
CustomFactories
ctor ServiceA, 1
ctor ServiceB, 2
ctor ServiceB, 3
disposing ServiceB, 3
disposing ServiceB, 2
disposing ServiceA, 1
Copy the code
Service lifecycle:
- Singletons: Always return the same instance
- Transient: A new object is returned each time a service is injected. Each time a service is requested from the container, a new instance is created
- Scoped: Always return the same instance from the same scope, different instance from different scope
Registration Services:
- AddSingleton and AddTransient are both extensions to ServiceCollection to make it easier to register services. There is also a more primitive Add method, which is more difficult to use and can only be seen with IServiceCollection, but not with ServiceCollection
services.Add(new ServiceDescriptor(typeof(ControllerX), typeof(ControllerX), ServiceLifetime.Transient));
Copy the code
For the Scoped:
- In ASP.NET Core Web applications, the default scope is an HTTP Web Request. When a Scoped service is requested from the container, the same instance is returned if the request is from the same HTTP Web Request. Instead, return a different instance. This allows easy sharing of state in HTTP Web Requests
- For non-ASP.NET Core Web applications, you need to create your own scope
Release of services:
- At the end of the scope, the Transient and scoped services are released automatically, but the Singleton is not released
- When scoping is released, the Transient service and scoped service are released. The Singleton service is released when the root provider is released
- Dispose does not need to be called on the service to release them. Dispose method is automatically called as long as the IDisposable interface is implemented
- .NET Core 2.0 releases services in the reverse order of creation
Other instantiation methods:
- Create a custom factory
IServiceB CreateServiceBFactory(IServiceProvider provider) =>
new ServiceB(provider.GetService<INumberService>());
services.AddTransient<IServiceB>(CreateServiceBFactory);
Copy the code
- Pass the existing instance to the container
var numberService = new NumberService();
services.AddSingleton<INumberService>(numberService);
Copy the code