[ASP.NET Core 3 framework Secret] dependency injection [7]: Consumer Services

IServiceCollection collection contains service registration information is used to create the final IServiceProvider objects into the container as a dependency. When you need to consume a service instance, we only need to specify the type of service GetService method can call the IServiceProvider, IServiceProvider objects will provide the required service instance based on the corresponding service registry.

一、IServiceProvider

The following code fragment, IServiceProvider interface defines only GetService method for providing service instance corresponding to the specified type. When IServiceCollection objects using the service include registered create IServiceProvider object, we only need to service the registered service type (corresponding to ServiceDescriptor of ServiceType property) as a parameter called GetService method, which can provide us with a corresponding service according to the registration information service instance.

public interface IServiceProvider
{
    object GetService(Type serviceType);
}

Overload on for three BuildServiceProvider extension method to create an object in IServiceCollection reflect IServiceProvider interface. The following code fragment, according to the configuration of the object to create the three options provided is a method for providing extension type ServiceProvider object. Configuration options ServiceProviderOptions provides two types of attributes, ValidateScopes attribute indicates whether you need to verify range of services for open, while ValidateOnBuild attribute indicates the need for pre-service inspection as each object is registered ServiceDescriptor can provide the corresponding service instance. By default, these two types of test are closed.

public class ServiceProviderOptions
{
    public bool ValidateScopes { get; set; }
    public bool ValidateOnBuild { get; set; }
    internal static readonly ServiceProviderOptions Default  = new ServiceProviderOptions();
}

public static class ServiceCollectionContainerBuilderExtensions
{
    public static ServiceProvider BuildServiceProvider( this IServiceCollection services)
        => BuildServiceProvider(services, ServiceProviderOptions.Default);
    public static ServiceProvider BuildServiceProvider( this IServiceCollection services, bool validateScopes)
        => services.BuildServiceProvider(new ServiceProviderOptions {  ValidateScopes = validateScopes });

    public static ServiceProvider BuildServiceProvider( this IServiceCollection services, ServiceProviderOptions options)
        => new ServiceProvider(services, options);
}

While calling IServiceCollection of BuildServiceProvider extension method always returns a ServiceProvider object, but I do not intend to detail this type, it is because ServiceProvider involves a series of internal type and interface, and provide a mechanism for the realization of this type of service instance has been constantly changing, and this change of trend in future versions of the replacement process will likely continue.

In addition to defining GetService method IServiceProvider interface, the interface having a further extension of these methods to serve as examples. GetService <T> method specifies a type of service in the form of generic parameters, for the service instance will return the corresponding type conversion. If you specify a service type of service registration does not exist, GetService method returns Null, if the call GetRequiredService or GetRequiredService <T> method InvalidOperationException type of exception is thrown. If the required service instance is necessary, we usually call these two extension methods.

public static class ServiceProviderServiceExtensions
{
    public static T GetService<T>(this IServiceProvider provider);

    public static T GetRequiredService<T>(this IServiceProvider provider);
    public static object GetRequiredService(this IServiceProvider provider,  Type serviceType);
    
    public static IEnumerable<T> GetServices<T>(this IServiceProvider provider);
    public static IEnumerable<object> GetServices(this IServiceProvider provider,  Type serviceType);
}

As previously mentioned several times, if you add more than one service registered for a certain type, then GetService method will always be registered using the latest service added to provide a service instance. If you want to take advantage of all the services registered to create a set of service instances list, we can call GetServices or GetServices <T> method, you can also call GetService <IEnumerable <T >> method.

Second, create a service instance

For IServiceProvider objects created by BuildServiceProvider method call IServiceCollection collection, when we invoke its GetService method specified by type of service in order to obtain the corresponding service instance, it will always find the corresponding registration from the service list according to the type of services provided the ServiceDescriptor object, and according to it to provide the required service instance.

ServiceDescriptor having three different constructors , correspond to the first three services provided by way of example, we can provide a Func <IServiceProvider, object> object as a factory to create the corresponding service instance, may also provide good service to create a direct examples . If we offer is to achieve the type of service, then the service will ultimately provide an example to create a certain type by calling the constructor, then the constructor is selected by what kind of strategy?

If IServiceProvider object was attempting to create a service instance by calling the constructor of the way, all the parameters passed to the constructor must be initialized, so eventually selected constructor must have a basic condition, that is IServiceProvider to provide a constructor all parameters . To give readers a deeper understanding of strategies can be employed in the constructor IServiceProvider selection process, we will demonstrate by way of examples of this were about.

We defined four service interface (IFoo, IBar, IBaz and IGux) and the realization of their four classes (Foo, Bar, Baz and Gux) in a console application. As shown in the code segment below, we define three Gux constructor, we define the parameters are the type of service interface. To determine which constructor IServiceProvider chose to create an instance of the target service, we output the corresponding indicative text on the console when the constructor executes.

public interface IFoo {}
public interface IBar {}
public interface IBaz {}
public interface IGux {}

public class Foo : IFoo {}
public class Bar : IBar {}
public class Baz : IBaz {}
public class Gux : IGux
{
    public Gux(IFoo foo)  => Console.WriteLine("Selected constructor: Gux(IFoo)");
    public Gux(IFoo foo, IBar bar)  => Console.WriteLine("Selected constructor: Gux(IFoo, IBar)");
    public Gux(IFoo foo, IBar bar, IBaz baz)  => Console.WriteLine("Selected constructor: Gux(IFoo, IBar, IBaz)");
}

In following this demonstration program, we have created a ServiceCollection objects and add for IFoo, IBar and IGux three service registry service interface, service interface IBaz for registration has not been added. We use IServiceProvider created by it to provide for instances of the service interface IGux, whether we can get a Gux object? If you can, it is through the implementation of which constructor to create it?

class Program
{
    static void Main()
    {       
        new ServiceCollection()
            .AddTransient<IFoo, Foo>()
            .AddTransient<IBar, Bar>()
            .AddTransient<IGux, Gux>()
            .BuildServiceProvider()
            .GetServices<IGux>();
    }
}

The definition in Gux in three constructors who, IServiceCollection collection due to the creation IServiceProvider provided contains an interface for IFoo IBar and services registered, so it can provide all the parameters of the previous two constructors. Since the third constructor IBaz having a type of parameter which can not be provided by IServiceProvider object. According to a first principle we described earlier (IServiceProvider objects can provide all constructor arguments), Gux first two constructors would become a legitimate candidate constructors, then IServiceProvider will eventually choose which one do?

A list of all valid candidates constructor, eventually selected constructor having such a characteristic: for each candidate set of parameter type constructor is the constructor subset of the set of parameter types. If such a constructor does not exist, an InvalidOperationException type of exception is thrown. According to this principle, Gux second parameter type constructor and comprises IFoo The IBar, the first constructor IFoo has only one type of parameter would eventually be selected Gux second constructor, so we run the program will produce the examples illustrated below output on the console.

4-6

Next, we slightly modified the program for instance. The following code fragment, we only define two constructors Gux, which has two parameters, parameter types are IFoo & IBar and IBar & IBaz. We will add to ServiceCollection collection created for IBaz / Baz service registration.

class Program
{
    static void Main()
    {       
        new ServiceCollection()
            .AddTransient<IFoo, Foo>()
            .AddTransient<IBar, Bar>()
            .AddTransient<IBaz, Baz>()
            .AddTransient<IGux, Gux>()
            .BuildServiceProvider()
            .GetServices<IGux>();
    }
}

public class Gux : IGux
{
    public Gux(IFoo foo, IBar bar) {}
    public Gux(IBar bar, IBaz baz) {}
}

For Gux two constructors, although they are able to be provided by the parameter IServiceProvider object, but not a constructor parameter types can be a superset of the set of all valid collection type constructor parameters, you can not select a most IServiceProvider Jia constructor. Shown below will be thrown after running the program InvalidOperationException exception, and can not be prompted to select an optimal service instance is created from two candidates in the constructor. (S409)

4-7

[ASP.NET Core 3 frame Disclosure] DI [1]: Inversion of Control
[ASP.NET Core 3 frame Disclosure] DI [2]: IoC mode
[ASP.NET Core 3 frame Disclosure] DI [3]: dependency injection mode
[ASP.NET Core 3 frame Disclosure] DI [4]: a mini-version of the DI frame
[ASP.NET Core 3 frame Disclosure] DI [5]: providing services using the container
[ASP.NET Core 3 framework Secret ] dependency injection [6]: service registration
[ASP.NET Core 3 framework Secret] dependency injection [7]: service consumption
[ASP.NET Core 3 framework Secret] dependency injection [8]: lifecycle services instance
[ASP.NET Core 3 frame Disclosure] DI [9]: Overview realize
[the ASP.NET framework Secret Core 3] DI [10]: third-party dependency injection adapter frame

Guess you like

Origin www.cnblogs.com/artech/p/inside-asp-net-core-03-07.html