In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
Editor to share with you the ASP.NET Core dependency injection service registration and provide sample analysis, I believe that most people do not know much about it, so share this article for your reference, I hope you will learn a lot after reading this article, let's go to know it!
Preface
In applications with dependency injection, we always directly use the DI container to obtain the required service instances. In other words, the DI container plays the role of a service provider, which can provide an available service object according to the service description information provided by us. The DI container in ASP.NET Core is represented as an object that implements the IServiceProvider interface.
ServiceProvider and ServiceDescriptor
Registration and provision of services
Using ServiceProvider to provide services
Provide a collection of service instances
Get ServiceProvider's own object
Support for generics
1. ServiceProvider and ServiceDescriptor
I have always thought that excellent design should first of all be simple design, at least seemingly simple design, this is what we call the road to simplicity. As a service provider, the DI container in ASP.NET Core is ultimately embodied as an IServiceProvider interface, and all types and their instances that implement this interface are collectively referred to as ServiceProvider. As the following code snippet shows, the interface is extremely simple, providing only a single GetService method that provides you with a corresponding service instance depending on the type of service provided.
Public interface IServiceProvider {object GetService (Type serviceType);}
What is really used inside ASP.NET Core is an internal type that implements the IServiceProvider interface (the name of the type is "ServiceProvider"), and we cannot create this object directly, we can only get it indirectly by calling the extension method BuildServiceProvider of the IServiceCollection interface. The IServiceCollection interface is defined under the "Microsoft.Extensions.DependencyInjection" namespace, which is used for all types related to ASP.NET Core dependency injection in this series of articles unless otherwise specified. As the following code snippet shows, the IServiceCollection interface actually represents a collection whose elements are ServiceDescriptor objects, which directly inherits another interface, IList, which is implemented by the ServiceCollection class.
Public static class ServiceCollectionExtensions {public static IServiceProvider BuildServiceProvider (this IServiceCollection services);} public interface IServiceCollection: IList {} Public class ServiceCollection: IServiceCollection {/ / omitted member}
The reason why ServiceProvider, which is embodied as a DI container, can provide a service instance that can be used out of the box according to our given service type (usually an interface type) is because we have registered the corresponding service description information in advance. These service descriptions that guide ServiceProvider to correctly implement service provision operations are embodied in the following ServiceDescriptor type.
Public class ServiceDescriptor {public ServiceDescriptor (Type serviceType, object instance); public ServiceDescriptor (Type serviceType, Func factory, ServiceLifetime lifetime); public ServiceDescriptor (Type serviceType, Type implementationType, ServiceLifetime lifetime); public Type ServiceType {get;} public ServiceLifetime Lifetime {get;} public Type ImplementationType {get;} public object ImplementationInstance {get;} public Func ImplementationFactory {get;}}
The ServiceType attribute of ServiceDescriptor represents the life type of the service provided, and because standardized services are generally defined as interfaces, they are represented as an interface type in most cases. The property Lifetime of type ServiceLifetime reflects how ServiceProvider controls the life cycle of the service instance. As shown in the following code snippet, ServiceLifetime is an American TV series type, and defining three options (Singleton, Scoped, and Transient) reflects three forms of control over the lifecycle of the service object, which we will cover specifically in the rest of this section.
Public enum ServiceLifetime {Singleton, Scoped, Transient}
3-10 for the other three attributes of ServiceDescriptor, they actually assist ServiceProvider in providing specific service instances. The ImplementationType attribute represents the real type of the provided service instance, the property ImplementationInstance directly represents the provided service instance, and the ImplementationFactory provides a delegate object to create the service instance. Several core types of ASP.NET Core related to dependency injection have the relationship shown in figure 10.
Because the ServiceProvider in ASP.NET Core is created from an IServiceCollection object that represents the ServiceDescriptor collection, when we call its GetService method, it finds the corresponding ServiceDecriptor object based on the type of service we provide. If the ImplementationInstance property of the ServiceDecriptor object returns a specific object, the object will be used directly as the provided service instance. If the ImplementationFactory of the ServiceDecriptor object returns a specific delegate, the delegate object will be used directly as a factory for creating a service instance.
If both properties are Null,ServiceProvider, the corresponding constructor will be called to create the provided service instance based on the type returned by the ImplementationType property. As for the three dependency injection methods we mentioned in the previous section, ServiceProvider only supports constructor injection, property injection and method injection.
II. Registration and provision of services
ASP.NET Core programming for dependency injection is mainly reflected in two aspects: first, create a ServiceCollection object and add service registration information to it in the form of a ServiceDescriptor object; second, create a corresponding ServiceProvider for the ServiceCollection object and use it to provide the service instances we need.
When registering the service, we can directly call the appropriate constructor to create the ServiceDescriptor object and add it to the ServiceCollection object. In addition, the IServiceCollection interface has the following three sets of extension methods to combine these two steps into one. From the code snippet given below, it is not difficult to see that these three groups of extension methods respectively aim at the three lifecycle control methods for service instances mentioned above. The generic parameter TService represents the declaration type of the service, that is, the ServiceType attribute of ServiceDescriptor, while the other attributes of ServiceDescriptor are provided through the corresponding parameters of the method.
Public static class ServiceCollectionExtensions {public static IServiceCollection AddScoped (this IServiceCollection services) where TService: class; / / other AddScoped overload public static IServiceCollection AddSingleton (this IServiceCollection services) where TService: class; / / other AddSingleton overload public static IServiceCollection AddTransient (this IServiceCollection services) where TService: class; / / other AddTransient overload}
For a ServiceProvider object used as a DI container, we can directly call its GetService method to get the desired service instance based on the specified service type. In addition, the provision of services can also be accomplished through the corresponding extension methods of the IServiceProvider interface. As shown in the following code snippet, the extension method GetService specifies the declaration type of the service in the form of generic parameters. As for the other two extension methods GetRequiredService and GetRequiredService, if ServiceProvider cannot provide a specific service instance, an InvalidOperationException exception will be thrown and indicate that the corresponding service registration information is insufficient.
Public static class ServiceProviderExtensions {public static T GetService (this IServiceProvider provider); public static object GetRequiredService (this IServiceProvider provider, Type serviceType); public static T GetRequiredService (this IServiceProvider provider);}
Using ServiceProvider to provide services
Next, we use the way of example demonstration to introduce how to use ServiceCollection for service registration, and how to use ServiceCollection to create the corresponding ServiceProvider to provide the service instance we need. We create an ASP.NET Core console program and add dependencies to the NuGet package "Microsoft.Extensions.DepedencyInjection" in project.json as follows.
{"dependencies": {"Microsoft.Extensions.DependencyInjection": "1.0.0-rc1-final"},...}
We next define four service interfaces (IFoo, IBar, IBaz, and IGux) and the four service classes that implement them (Foo, Bar, Baz, and Gux), as shown in the following code snippet, IGux has three read-only properties (Foo, Bar, and Baz) that are interface types and are initialized in the constructor.
Public interface IFoo {} public interface IBar {} public interface IBaz {} public interface IGux {IFoo Foo {get;} IBar Bar {get;} IBaz Baz {get;} public class Foo: IFoo {} public class Bar: IBar {} public class Baz: IBaz {} public class Gux: IGux {public IFoo Foo {get; private set;} public IBar Bar {get; private set;} public IBaz Baz {get; private set;} public Gux (IFoo foo, IBar bar, IBaz baz) {this.Foo = foo; this.Bar = bar This.Baz = baz;}}
Now we have created a ServiceCollection object in the Main method that serves as the entry to the program, and have completed registration for the four service interfaces in different ways. Specifically, for the ServiceDescriptor facing the service interfaces IFoo and IGux, we specify the ImplementationType attribute that represents the real type of the service, while for the ServiceDescriptor for the service interface IBar and IBaz, we initialize the ImplementationInstance ImplementationFactory attributes that represent the service instance and service factory, respectively. Since we are calling the AddSingleton method, the Lifetime property of the four ServiceDescriptor is Singleton.
Class Program {static void Main (string [] args) {IServiceCollection services = new ServiceCollection () .AddSingleton () .AddSingleton (new Bar ()) .AddSingleton (_ = > new Baz ()) .AddSingleton (); IServiceProvider serviceProvider = services.BuildServiceProvider (); Console.WriteLine ("serviceProvider.GetService (): {0}", serviceProvider.GetService ()); Console.WriteLine ("serviceProvider.GetService (): {0}", serviceProvider.GetService ()) Console.WriteLine ("serviceProvider.GetService (): {0}", serviceProvider.GetService ()); Console.WriteLine ("serviceProvider.GetService (): {0}", serviceProvider.GetService ());}}
Next, we call the extension method BuildServiceProvider of the ServiceCollection object to get the corresponding ServiceProvider object, and then call its extension method GetService to obtain the service instance objects for the four interfaces and output the type names to the console. After running the program, we will get the following output on the console, which confirms that ServiceProvider provides us with the desired service example.
ServiceProvider.GetService (): Foo serviceProvider.GetService (): Bar serviceProvider.GetService (): Baz serviceProvider.GetService (): Gux
Provide a collection of service instances
If we specify the service type as IEnumerable when we call the GetService method, the result returned will be a collection object. In addition, we can directly call IServiceProvider the following two extension methods, GetServeces, to achieve the same purpose. In this case, ServiceProvider will use all the ServiceDescriptor that matches the specified service type to provide specific service instances, which will be used as elements of the returned collection object. If all ServiceDescriptor do not match the specified service type, the final return is an empty collection object.
Public static class ServiceProviderExtensions {public static IEnumerable GetServices (this IServiceProvider provider); public static IEnumerable GetServices (this IServiceProvider provider, Type serviceType);}
It is worth mentioning that if the ServiceCollection where the ServiceProvider resides contains multiple ServiceDescriptor with the same service type (corresponding to the ServiceType attribute), when we call the GetService method to obtain a single service instance, only the last ServiceDescriptor is valid. As for the other ServiceDescriptor, they are meaningful only in the scenario of getting the service set.
We use a simple example to demonstrate how to use ServiceProvider to get a collection of multiple service instances. We define the following service interface IFoobar in a console application, which is implemented by two service types, Foo and Bar. In the Main method that serves as the program entry, we add two ServiceDescriptor for the service type Foo and Bar to the created ServiceCollection object, both of which have a ServiceType property of IFoobar.
Class Program {static void Main (string [] args) {IServiceCollection serviceCollection = new ServiceCollection () .AddSingleton () .AddSingleton (); IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider (); Console.WriteLine ("serviceProvider.GetService (): {0}", serviceProvider.GetService ()); IEnumerable services = serviceProvider.GetServices (); int index = 1; Console.WriteLine ("serviceProvider.GetServices ():"); foreach (IFoobar foobar in services) {Console.WriteLine ("{0}: {1}", index++, foobar) } public interface IFoobar {} public class Foo: IFoobar {} public class Bar: IFoobar {}
After calling the extension method BuildServiceProvider of the ServiceCollection object to get the corresponding ServiceProvider object, we first call its GetService method to determine whether the real type of the service instance obtained for the service interface IFoobar is Foo or Bar. Next we call ServiceProvider's extension method GetServices to get a set of service instances for the service interface IFoobar and print their true types on the console. After running, the program will generate the following output on the console.
ServiceProvider.GetService (): Bar serviceProvider.GetServices (): 1: Foo 2: Bar
Get ServiceProvider's own object
Another small detail worth paying attention to for ServiceProvider's service provision mechanism is that when we call the GetService or GetRequiredService methods, if we set the service type to IServiceProvider, the resulting object is actually the ServiceProvider itself. In the same way, calling the GetServices method returns a collection that contains itself. The code snippet shown below reflects this feature of ServiceProvider.
Class Program {static void Main (string [] args) {IServiceProvider serviceProvider = new ServiceCollection (). BuildServiceProvider (); Debug.Assert (object.ReferenceEquals (serviceProvider, serviceProvider.GetService (); Debug.Assert (object.ReferenceEquals (serviceProvider, serviceProvider.GetServices (). Single ());}}
Support for generics
The service instances provided by ServiceProvider are not limited to ordinary types, but also support generic service types. When registering for a generic service, we can set the service type to a "off generic type" (such as IFoobar) that carries specific generic parameters, while the service type can also be an "open generic type" (such as IFoo) that contains specific generic parameters. The former actually treats it as a non-generic service, while the latter really embodies the essence of "generics".
For example, when we register the mapping between a certain generic service interface IFoobar and its implementation class Foobar, when we specify a service interface type IFoobar with specific generic parameters and call the GetService method of ServiceProvider to obtain the corresponding service instance, ServiceProvider will parse the matching implementation type (possibly Foo and Baz) and get the final implementation type (Foobar) according to the specified generic parameter type (IFoo and IBar).
We also use a simple console application to demonstrate generics-based service registration and delivery. As shown in the following code snippet, we define three service interfaces (IFoo, IBar, and IFoobar) and three service classes that implement them (Foo, Bar Foobar). The generic interface has two properties of generic parameter types (Foo and Bar), which are initialized in the implementation class by constructor injection.
Class Program {static void Main (string [] args) {IServiceProvider serviceProvider = new ServiceCollection () .Addtransient () .AddTransient () .AddTransient (typeof (IFoobar), typeof (Foobar)) .BuildServiceProvider (); Console.WriteLine ("serviceProvider.GetService (). Foo: {0}", serviceProvider.GetService () .Foo); 12: Console.WriteLine ("serviceProvider.GetService (). Bar: {0}", serviceProvider.GetService (). Bar) } public interface IFoobar {T1 Foo {get;} T2 Bar {get;} public interface IFoo {} public interface IBar {} public class Foobar: IFoobar {public T1 Foo {get; private set;} public T2 Bar {get; private set;} public Foobar (T1 foo, T2 bar) {this.Foo = foo; this.Bar = bar;} public class Foo: IFoo {} public class Bar: IBar {}
In the Main method as the entry program, we create a ServiceCollection object and register the mapping between the above three service interfaces and the corresponding implementation types using the Transient schema. For the generic service IFoobar/Foobar, we specify the open generic type IFoobar/Foobar that does not carry specific generic parameters. After creating the corresponding ServiceProvider with this ServiceCollection, we call the GetService method of the latter and specify IFoobar as the service type. The resulting service object will be a Foobar object, and we output its Foo and Bar attribute types to the console for verification. After the program is executed, the output shown below will be produced on the console.
ServiceProvider.GetService (). Foo: Foo serviceProvider.GetService (). Bar: Bar above is all the content of the article "Service Registration and sample Analysis of ASP.NET Core dependency injection". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
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.