In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-08 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly explains the "detailed introduction of ASP.NET Core dependency injection", the content of the article is simple and clear, easy to learn and understand, now please follow the editor's ideas slowly in depth, together to study and learn "detailed introduction to ASP.NET Core dependency injection"!
Catalogue
Dependency injection
What is dependency injection?
What are the benefits of dependency injection
ASP.NET Core built-in dependency injection
Service life cycle
Service release
TryAdd {Lifetime} extension method
Parsing multiple different implementations of the same service
Replace & & Remove extension method
Autofac
Service parsing and injection
Constructor injection
Method injection
Attribute injection
Some points for attention
Services provided by default in the framework
Dependency injection what is dependency injection
To put it simply, the creation and destruction of the object is left to the DI container, and the caller only needs to receive the injected object instance.
Microsoft official document-DI
What are the benefits of dependency injection
Dependency injection is a "first-class citizen" in .NET, and you can't do without it everywhere, so what are the benefits of it?
Suppose you have a log class FileLogger, which is used to log to a local file.
Public class FileLogger {public void LogInfo (string message) {}}
Logging is very common, and almost all services need to log. If dependency injection is not used, then we must manually new FileLogger in each service to create a FileLogger instance.
Public class MyService {private readonly FileLogger _ logger = new FileLogger (); public void Get () {_ logger.LogInfo ("MyService.Get");}}
If one day we want to replace FileLogger and use ElkLogger to process logs through ELK, then we need to change the code in all services to new ElkLogger.
Public class MyService {private readonly ElkLogger _ logger = new ElkLogger (); public void Get () {_ logger.LogInfo ("MyService.Get");}}
In a large project, such code is scattered throughout the project, and the services involved need to be modified, which is obviously unrealistic and violates the "opening and closing principle".
If other dependencies are needed in Logger, the services that use Logger also provide dependencies for them, and if the dependencies are modified, other services must also be changed, making it more difficult to maintain.
It is difficult to unit test because it cannot do mock
Because of this, dependency injection solves these thorny problems:
Abstract dependencies through interfaces or base classes (including abstract or virtual methods, etc.)
Store dependencies in a service container
The framework is responsible for creating and releasing instances of dependencies and injecting them into constructors, properties, or methods
ASP.NET Core's built-in dependency injection service life cycle
Transient
Instantly, that is, each time it is acquired, it is a brand new service instance.
Scoped
Scope (or scope), that is, within a certain scope (or scope), the same service instance is always obtained, while different service instances are obtained between different scope (or scope). For Web applications, each request is a scope (or scope).
Singleton
Singleton, that is, in a single application, the same service instance is always obtained. In addition, in order to ensure the normal operation of the program, the singleton service must be thread-safe.
Service release
If the service implements the IDisposable interface and the service is created by the DI container, then you should not go to the Dispose,DI container to automatically release the service.
For example, there are four services: Service1, Service2, Service3 and Service4, and all of them implement IDisposable interfaces, such as:
Public class Service1: IDisposable {public void Dispose () {Console.WriteLine ("Service1.Dispose");}} public class Service2: IDisposable {public void Dispose () {Console.WriteLine ("Service2.Dispose");}} public class Service3: IDisposable {public void Dispose () {Console.WriteLine ("Service3.Dispose") }} public class Service4: IDisposable {public void Dispose () {Console.WriteLine ("Service4.Dispose");}}
And register as:
Public void ConfigureServices (IServiceCollection services) {/ / release services.AddTransient () every time you finish using (end of request); / / release services.AddScoped () when out of range (end of request); / / release services.AddSingleton () when the program stops; / / release services.AddSingleton when the program stops (sp = > new Service4 ());}
Inject the constructor
Public ValuesController (Service1 service1, Service2 service2, Service3 service3, Service4 service4) {}
Request to get the output:
Service2.Dispose
Service1.Dispose
These service instances are created by the DI container, so the DI container is also responsible for releasing and destroying the service instances. Note that it is not time to release the singleton at this time.
But if registered as:
Public void ConfigureServices (IServiceCollection services) {/ / Note the difference from the above. This is directly new, while the above is services.AddSingleton (new Service1 ()) via sp = > new; services.AddSingleton (new Service2 ()); services.AddSingleton (new Service3 ()); services.AddSingleton (new Service4 ());}
At this point, the instances are created by ourselves, and the DI container will not be responsible for releasing and destroying them, which need to be done by our developers.
For more information on registration, please refer to the official document-Service registration methods
TryAdd {Lifetime} extension method
When you register the same service multiple times, such as:
Services.AddSingleton (); services.AddSingleton ()
Then when you use IEnumerable (described below) to parse the service, multiple copies of MyService instances are produced.
To do this, the framework provides TryAdd {Lifetime} extension methods, which are located under the namespace Microsoft.Extensions.DependencyInjection.Extensions. When a service of the specified type already exists in the DI container, nothing is done; otherwise, the service is injected into the DI container.
Services.AddTransient (); / / since the service type IMyService has been registered above, the following code does not do anything (independent of the life cycle) services.TryAddTransient (); services.TryAddTransient ()
TryAdd: pass in the service type, implementation type, life cycle and other information through the parameter ServiceDescriptor.
TryAddTransient: corresponding to AddTransient
TryAddScoped: corresponding to AddScoped
TryAddSingleton: corresponding to AddSingleton
TryAddEnumerable: the difference between this and TryAdd is that TryAdd determines whether to register only based on the service type, while TryAddEnumerable determines whether to register together based on the service type and the implementation type, and is often used to register multiple different implementations of the same service type. For example:
/ / registered IMyService-MyService1services.TryAddEnumerable (ServiceDescriptor.Singleton ()); / registered IMyService-MyService2services.TryAddEnumerable (ServiceDescriptor.Singleton ()); / / did nothing because IMyService-MyService1 has registered services.TryAddEnumerable (ServiceDescriptor.Singleton ()) on it; parsed multiple different implementations of the same service
By default, if multiple different implementations of the same service are injected, the last injected will prevail when the service is parsed.
If you want to resolve all service instances of the same service type, you can resolve it through IEnumerable (in the same order as the registration order):
Public interface IAnimalService {} public class DogService: IAnimalService {} public class PigService: IAnimalService {} public class CatService: IAnimalService {} public void ConfigureServices (IServiceCollection services) {/ / Life cycle unrestricted services.AddTransient (); services.AddScoped (); services.AddSingleton ();} public ValuesController (/ / CatService IAnimalService animalService, / / DogService, PigService, CatService IEnumerable animalServices) {} Replace & & Remove extension method
What we have mentioned above is to register new services into the DI container, but sometimes we need to use Replace and Remove when we want to replace or remove certain services.
/ / replace the implementation of IMyService with MyService1services.Replace (ServiceDescriptor.Singleton ()); / / remove the implementation of IMyService registration MyServiceservices.Remove (ServiceDescriptor.Singleton ()); / / remove all registered services.RemoveAll of IMyService (); / / clear all service registrations services.Clear (); Autofac
Autofac is an old DI component, so let's replace the DI container that comes with ASP.NET Core with Autofac.
1. Install the nuget package:
Install-Package AutofacInstall-Package Autofac.Extensions.DependencyInjection
two。 Replace service provider factory
Public static IHostBuilder CreateHostBuilder (string [] args) = > Host.CreateDefaultBuilder (args) .ConfigureWebHostDefaults (webBuilder = > {webBuilder.UseStartup ();}) / / replace the default provider factory here with autofac .UseServiceProviderFactory (new AutofacServiceProviderFactory ())
3. Add a ConfigureContainer method to the Startup class
Public class Startup {public Startup (IConfiguration configuration) {Configuration = configuration;} public IConfiguration Configuration {get;} public ILifetimeScope AutofacContainer {get; private set;} public void ConfigureServices (IServiceCollection services) {/ / 1. Do not build or return any IServiceProvider, otherwise the ConfigureContainer method will not be called. / / 2. Do not create ContainerBuilder, and do not call builder.Populate (), AutofacServiceProviderFactory has done this work / / 3. You can still register the service here by services.AddOptions (); services.AddControllers (); services.AddSwaggerGen (c = > {c.SwaggerDoc ("v1", new OpenApiInfo {Title = "WebApplication.Ex", Version = "v1"});} / 1. ConfigureContainer is used for service registration using Autofac / / 2. This method runs after ConfigureServices, so the registration here will overwrite the previous registration / / 3. No build container, do not call builder.Populate (), AutofacServiceProviderFactory has done this work public void ConfigureContainer (ContainerBuilder builder) {/ / divide the service registration into modules, register builder.RegisterModule (new AutofacModule ()) } public class AutofacModule: Autofac.Module {protected override void Load (ContainerBuilder builder) {/ / register the service here builder.RegisterType (). As ();}} public void Configure (IApplicationBuilder app, ILoggerFactory loggerFactory) {/ / get autofac's DI container AutofacContainer = app.ApplicationServices.GetAutofacRoot () by this method }} Service parsing and injection
Above we mainly talk about the injection method of the service, and then look at the parsing method of the service. There are two ways to parse:
1.IServiceProvider
2.ActivatorUtilities
Used to create service instances that are not registered in the DI container
Features for some framework levels
Constructor injection
Many of the examples we have given above use constructor injection-- receiving parameters through the constructor. Constructor injection is a very common and preferred method of service injection, which requires:
The constructor can accept non-dependency injection parameters, but must provide a default value
When the service is parsed through IServiceProvider, the constructor must be public
When the service is parsed through ActivatorUtilities, the constructor must be public. Although constructor overloading is supported, only one of the parameters must be valid, that is, all parameters can be obtained through dependency injection.
Method injection
As the name implies, method injection is to receive service instances through method parameters.
[HttpGet] public string Get ([FromServices] IMyService myService) {return "Ok";} attribute injection
ASP.NET Core's built-in dependency injection does not support attribute injection. But Autofac supports it, and the usage is as follows:
The old rule is to define services and implementations first
Public interface IUserService {string Get ();} public class UserService: IUserService {public string Get () {return "User";}}
Then register for the service
By default, are the constructor parameters of the controller managed by the DI container, while the controller instance itself is managed by the ASP.NET Core framework, so this "property injection" cannot take effect?
Through the AddControllersAsServices method, the controller is handed over to the autofac container for processing, so that the attribute injection can take effect.
Public void ConfigureServices (IServiceCollection services) {services.AddControllers (). AddControllersAsServices ();} public void ConfigureContainer (ContainerBuilder builder) {builder.RegisterModule ();} public class AutofacModule: Autofac.Module {protected override void Load (ContainerBuilder builder) {builder.RegisterType (). As (); var controllerTypes = Assembly.GetExecutingAssembly (). GetExportedTypes () .Where (type = > typeof (ControllerBase) .IsAssignableFrom (type)) .ToArray () / / configure all controllers to support attribute injection builder.RegisterTypes (controllerTypes) .PropertiesAutowired ();}}
Finally, we receive the service instance through properties in the controller
Public class ValuesController: ControllerBase {public IUserService UserService {get; set;} [HttpGet] public string Get () {return UserService.Get ();}}
By calling the Get interface, we can get an instance of IUserService and get a response.
User
Some points for attention
Avoid using service location mode. Try to avoid using GetService to get service instances, and instead use DI.
Using Microsoft.Extensions.DependencyInjection;public class ValuesController: ControllerBase {private readonly IServiceProvider _ serviceProvider; / / the service instance public ValuesController (IServiceProvider serviceProvider) {_ serviceProvider = serviceProvider;} [HttpGet] public string Get () {/ / avoid obtaining the service instance var myService = _ serviceProvider.GetService (); return "Ok";}} through dependency injection as far as possible
Avoid calling BuildServiceProvider in ConfigureServices. Because this results in the creation of a second copy of the DI container, resulting in multiple copies of the registered singleton service.
Public void ConfigureServices (IServiceCollection services) {/ / do not call this method in this method var serviceProvider = services.BuildServiceProvider ();}
Be sure to pay attention to the scope of service resolution, and do not parse Transient or Scoped services in Singleton, which can lead to service state errors (such as escalating the service instance lifecycle to singletons). The ways that are allowed are:
1. Parsing Singleton services in Scoped or Transient services
two。 Parsing a Scoped service in a Scoped or Transient service (cannot be the same as the previous Scoped service)
When running in a Development environment and generating a host through CreateDefaultBuilder, the default service provider checks as follows:
1. The Scoped service cannot be resolved at the root service provider, which causes the lifecycle of the Scoped service to be elevated to Singleton because the root container is not released until the application is closed.
two。 Cannot inject Scoped service into Singleton service
As the business grows, more and more services need dependency injection. It is recommended to use an extension method to encapsulate service injection, named Add {Group_Name}, such as encapsulating all AppService service registrations.
Namespace Microsoft.Extensions.DependencyInjection {public static class ApplicationServiceCollectionExtensions {public static IServiceCollection AddApplicationService (this IServiceCollection services) {services.AddTransient (); services.AddScoped (); services.AddSingleton (); services.AddSingleton (sp = > new Service4 ()); return services;}
Then call it in ConfigureServices.
Public void ConfigureServices (IServiceCollection services) {services.AddApplicationService ();} default services provided by the framework
The following is a list of some commonly used frameworks that have registered by default:
Service type life cycle Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactoryTransientIHostApplicationLifetimeSingletonIHostLifetimeSingletonIWebHostEnvironmentSingletonIHostEnvironmentSingletonMicrosoft.AspNetCore.Hosting.IStartupSingletonMicrosoft.AspNetCore.Hosting.IStartupFilterTransientMicrosoft.AspNetCore.Hosting.Server.IServerSingletonMicrosoft.AspNetCore.Http.IHttpContextFactoryTransientMicrosoft.Extensions.Logging.ILoggerSingletonMicrosoft.Extensions.Logging.ILoggerFactorySingletonMicrosoft.Extensions.ObjectPool.ObjectPoolProviderSingletonMicrosoft.Extensions.Options.IConfigureOptionsTransientMicrosoft.Extensions.Options.IOptionsSingletonSystem.Diagnostics.DiagnosticSourceSingletonSystem.Diagnostics.DiagnosticListenerSingleton Thank you for your reading. This is the content of "A detailed introduction to ASP.NET Core dependency injection". After the study of this article, I believe you have a deeper understanding of the detailed introduction of ASP.NET Core dependency injection, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.