http://www.mamicode.com/info-detail-2200461.html
Related articles:
Deep understanding of dependency injection, Singleton, Scoped, Transient in net core (I)
Deep understanding of dependency injection, Singleton, Scoped, Transient in net core (II)
Deep understanding of dependency injection, Singleton, Scoped, Transient in net core (3)
Deep understanding of dependency injection, Singleton, Scoped, Transient in net core (4)1.1 Dependence
1.2 What is injection
private ILoginService<ApplicationUser> _loginService;
public AccountController()
{
_loginService = new EFLoginService()
}
The Master said, this is not good. You shouldn't create it yourself, but it should be given to you by your caller. So you let the outside world pass these two dependencies to you through the constructor.
public
AccountController(ILoginService<ApplicationUser> loginService)
{
_loginService = loginService;
}
The process of creating dependencies for others and using them for themselves is understood as injection.
1.3 Why reverse?
var controller = new AccountController(new EFLoginService());
controller.Login(userName, password);
// Replace the original EF login with Redis
var controller = new AccountController(new RedisLoginService());
controller.Login(userName, password);
1.4 What is a container?
- The relationship between binding services and instances
- Get instances and manage them (create and destroy)
2. NET Core DI
2.1 Instance registration
- IServiceCollection is responsible for registration
- IServiceProvider is responsible for providing examples
var serviceCollection = new ServiceCollection()
.AddTransient<ILoginService, EFLoginService>()
.AddSingleton<ILoginService, EFLoginService>()
.AddScoped<ILoginService, EFLoginService>();
public interface IServiceCollection : IList<ServiceDescriptor> { }
Our AddTransient, AddSignletone, and Coped methods above are extensions to IServiceCollection, all of which add Service Descriptor to this List.
private static IServiceCollection Add(
IServiceCollection collection,
Type serviceType,
Type implementationType,
ServiceLifetime lifetime)
{
var descriptor =
new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(descriptor);
return collection;
}
2.2 A single example of the life cycle of an instance
- Transient: Each GetService creates a new instance
- Scoped: Only one instance is initialized in the same Scope, which can be understood as (only one instance is created at each request level, and the same http request is in a scope)
- Singleton: Only one instance is created throughout the application lifecycle
public enum ServiceLifetime
{
Singleton,
Scoped,
Transient
}
public interface IOperation
{
Guid OperationId { get; }
}
public interface IOperationSingleton : IOperation { }
public interface IOperationTransient : IOperation{}
public interface IOperationScoped : IOperation{}
Our Operation implementation is simple. We can pass in a Guid in the constructor for assignment, and if not, we can use our own New Guid.
public class Operation :
IOperationSingleton,
IOperationTransient,
IOperationScoped
{
private Guid _guid;
public Operation() {
_guid = Guid.NewGuid();
}
public Operation(Guid guid)
{
_guid = guid;
}
public Guid OperationId => _guid;
}
In the program, we can call the GetService method of ServiceProvider many times, and get the same instance.
var services = new ServiceCollection();
// Default construction
services.AddSingleton<IOperationSingleton, Operation>();
// Customize null values of incoming Guid
services.AddSingleton<IOperationSingleton>(
new Operation(Guid.Empty));
// Customize to pass in a New Guid
services.AddSingleton <IOperationSingleton>(
new Operation(Guid.NewGuid()));
var provider = services.BuildServiceProvider();
// Guid for output singletone1
var singletone1 = provider.GetService<IOperationSingleton>();
Console.WriteLine($"signletone1: {singletone1.OperationId}");
// Guid for output singletone2
var singletone2 = provider.GetService<IOperationSingleton>();
Console.WriteLine($"signletone2: {singletone2.OperationId}");
Console.WriteLine($"singletone1 == singletone2 ? : { singletone1 == singletone2 }");
We registered IOperation Singleton three times, and finally got it two times. You should notice that we always got an instance of Guid from the last one we registered. The preceding one will be overwritten.
2.3 Tranisend for instance life cycle
The IOperation Transient we obtained this time is two different instances.
var services = new ServiceCollection();
services.AddTransient<IOperationTransient, Operation>();
var provider = services.BuildServiceProvider();
var transient1 = provider.GetService<IOperationTransient>();
Console.WriteLine($"transient1: {transient1.OperationId}");
var transient2 = provider.GetService<IOperationTransient>();
Console.WriteLine($"transient2: {transient2.OperationId}");
Console.WriteLine($"transient1 == transient2 ? :
{ transient1 == transient2 }");
2.4 Scoped for instance life cycle
var services = new ServiceCollection()
.AddScoped<IOperationScoped, Operation>()
.AddTransient<IOperationTransient, Operation>()
.AddSingleton<IOperationSingleton, Operation>();
Next we create a Scope using the ServiceProvider.CreateScope method
var provider = services.BuildServiceProvider();
using (var scope1 = provider.CreateScope())
{
var p = scope1.ServiceProvider;
var scopeobj1 = p.GetService<IOperationScoped>();
var transient1 = p.GetService<IOperationTransient>();
var singleton1 = p.GetService<IOperationSingleton>();
var scopeobj2 = p.GetService<IOperationScoped>();
var transient2 = p.GetService<IOperationTransient>();
var singleton2 = p.GetService<IOperationSingleton>();
Console.WriteLine(
$"scope1: { scopeobj1.OperationId }," +
$"transient1: {transient1.OperationId}, " +
$"singleton1: {singleton1.OperationId}");
Console.WriteLine($"scope2: { scopeobj2.OperationId }, " +
$"transient2: {transient2.OperationId}, " +
$"singleton2: {singleton2.OperationId}");
}
Next
scope1: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient1: fb35f570-713e-43fc-854c-972eed2fae52,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 200d1e63-d024-4cd3-88c9-35fdf5c00956,
transient2: 2766a1ee-766f-4116-8a48-3e569de54259,
singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
If a new Scope runs,
scope1: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient1: 035d8bfc-c516-44a7-94a5-3720bd39ce57,
singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225
scope2: 29f127a7-baf5-4ab0-b264-fcced11d0729,
transient2: 74c37151-6497-4223-b558-a4ffc1897d57,
singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
Application of DI in ASP.NET Core
3.1 Initialization in Startup Class
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ILoginService<ApplicationUser>,
EFLoginService>();
services.AddMvc();
)
Some components of ASP.NET Core have already provided some instance bindings, such as AddMvc, which is Mvc Middleware's extension method added to IServiceCollection.
public static IMvcBuilder AddMvc(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
var builder = services.AddMvcCore();
builder.AddApiExplorer();
builder.AddAuthorization();
AddDefaultFrameworkParts(builder.PartManager);
...
}
3.2 Use in Controller
private ILoginService<ApplicationUser> _loginService;
public AccountController(
ILoginService<ApplicationUser> loginService)
{
_loginService = loginService;
}
We just need to write this parameter in the controller's constructor, and Service Provider will inject it into the controller. This step is completed when the controller is initialized by Mvc, and we will go into details later when we introduce Mvc.
3.3 View
@using MilkStone.Services;
@model MilkStone.Models.AccountViewModel.LoginViewModel
@inject ILoginService<ApplicationUser> loginService
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
@loginService.GetUserName()
</body>
</html>
3.4 Get instances through HttpContext
HttpContext.RequestServices.GetService<ILoginService<ApplicationUser>>();
4. How to replace other Ioc containers
builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
This will bring some convenience to our initialization. Let's see how to replace Autofac to ASP.NET Core. We just need to change the return value of ConfigureService in the Startup class from void to IServiceProvider. The return is an AutoService Provider.
public IServiceProvider ConfigureServices(
IServiceCollection services){
services.AddMvc();
// Add other framework services
// Add Autofac
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
4.1 What's the change?
One of the big changes is that Instance PerRequest, the original life cycle of Autofac, will no longer be effective. As we said earlier, the entire request lifecycle is managed by ASP.NET Core, so this one of Autofac will no longer work. We can use Instance Per Lifetime Scope, which is also useful, corresponding to the Scoped in our ASP.NET Core DI.
Deep understanding of dependency injection, Singleton, Scoped, Transient in net core (4)
Label: function services return dcl null injection bfc addm sig
Original address: https://www.cnblogs.com/gdsblog/p/8465401.html