[ASP.NET Core 3 frame Disclosure] DI [10]: third-party dependency injection adapter frame

.NET Core has a bearing (Hosting) system bearer services need to run in the background for a long time, a ASP.NET Core Services is just one application of the system of carrying it. Carrier injection system is always dependent manner employed to consume it in the required bearer service during service. For carrying system, the original registration service is always embodied in a IServiceCollection collection, the ultimate dependency injection container is embodied as a IServiceProvider object, if you want to integrate third-party dependency injection frameworks come in, you need to use them to solve the set from IServiceCollection adaptation problems between the IServiceProvider objects.

一、IServiceCollection =>ContainerBuilder=>IServiceProvider

Specifically, we can set a dependency injection framework for a third party between IServiceCollection collection and IServiceProvider objects ContainerBuilder object. Let's use IServiceCollection collection contains the original registration service to create a ContainerBuilder objects, and then to build IServiceProvider objects into the container as dependent on the use of the object.

4-15

二、 IServiceProviderFactory<TContainerBuilder>

Conversion shown above using a Two IServiceProviderFactory <TContainerBuilder> objects completed. The following code fragment, IServiceProviderFactory <TContainerBuilder> interface defines two methods, wherein CreateBuilder method using the designated collection IServiceCollection ContainerBuilder create corresponding object, and CreateServiceProvider method is further the object using the ContainerBuilder create a dependency of the container IServiceProvider object.

public interface IServiceProviderFactory<TContainerBuilder>
{
    TContainerBuilder CreateBuilder(IServiceCollection services);
    IServiceProvider CreateServiceProvider(TContainerBuilder containerBuilder);
}

.NET Core carrier systems always use the registered IServiceProviderFactory <TContainerBuilder> IServiceProvider service to create an object into the container as the final dependency. The default bearer is registered as the DefaultServiceProviderFactory type. As shown in the following code fragment, DefaultServiceProviderFactory object calls directly BuildServiceProvider IServiceCollection specified method to create a set of objects corresponding IServiceProvider.

public class DefaultServiceProviderFactory :  IServiceProviderFactory<IServiceCollection>
{   
    public DefaultServiceProviderFactory()  : this(ServiceProviderOptions.Default){}
    public DefaultServiceProviderFactory(ServiceProviderOptions options) =>_options = options;

    public IServiceCollection CreateBuilder(IServiceCollection services)  => services;

    public IServiceProvider CreateServiceProvider( IServiceCollection containerBuilder) =>  containerBuilder.BuildServiceProvider(_options);
}

Third, integrate third-party dependency injection framework

In order to allow readers to IServiceProviderFactory <TContainerBuilder> registered service integration use third-party dependency injection framework with a more profound understanding, we have to demonstrate a specific example. We are " a Mini version of dependency injection framework " created a directory named Cat "mini-version of" dependency injection framework, then we will provide a specific IServiceProviderFactory <TContainerBuilder> to complete the integration of its implementation type.

We first create a named CatBuilder type as the corresponding ContainerBuilder. Because of the need to involve a range of services for the creation, we set the following two types of proprietary embedded in CatBuilder class, which represents a range of services ServiceScope objects is actually a package of IServiceProvider object type represents another ServiceScopeFactory create the object plant, it is an object encapsulation of a Cat.

public class CatBuilder
{    
    private class ServiceScope : IServiceScope
    {
        public ServiceScope(IServiceProvider serviceProvider) => ServiceProvider = serviceProvider;
        public IServiceProvider ServiceProvider { get; }
        public void Dispose()=> (ServiceProvider as IDisposable)?.Dispose();
}

    private class ServiceScopeFactory : IServiceScopeFactory
    {
        private readonly Cat _cat;
        public ServiceScopeFactory(Cat cat) => _cat = cat;
        public IServiceScope CreateScope() => new ServiceScope(_cat);
    }
}

The object is a package for a CatBuilder Cat object, it returns to the direct method BuildServiceProvider Cat this object, and as ultimately dependent provided into the container. CatBuilder added services Register for IServiceScopeFactory interface during initialization, specific registration is ServiceScopeFactory objects created from the Cat object as the current child. In order to achieve wholesale services registered within the scope of the assembly, we define a method for the Register CatBuilder.

public class CatBuilder
{
    private readonly Cat _cat;
    public CatBuilder(Cat cat)
    {
        _cat = cat;
        _cat.Register<IServiceScopeFactory>( c => new ServiceScopeFactory(c.CreateChild()), Lifetime.Transient);
    }
    public IServiceProvider BuildServiceProvider() => _cat;
    public CatBuilder Register(Assembly assembly)
    {
        _cat.Register(assembly);
        return this;
    }
    ...
}

The following types of CatServiceProviderFactory achieved IServiceProviderFactory <CatBuilder> interface. In CreateBuilder method of implementation, we create a Cat object and specify the service registry (ServiceDescriptor objects) IServiceCollection collection contains the Cat into a compatible service registration (ServiceRegistry objects) and applied to the Cat objects created. We finally take advantage of this Cat object creates a CatBuilder object returned. Another way to achieve CreateServiceProvider returns IServiceProvider object calls CatBuilder object CreateServiceProvider obtained by the method.

public class CatServiceProviderFactory : IServiceProviderFactory<CatBuilder>
{
    public CatBuilder CreateBuilder(IServiceCollection services)
    {
        var cat = new Cat();
        foreach (var service in services)
        {
            if (service.ImplementationFactory != null)
            {
                cat.Register(service.ServiceType, provider ) => service.ImplementationFactory(provider),   service.Lifetime.AsCatLifetime());
            }
            else if (service.ImplementationInstance != null)
            {
                cat.Register(service.ServiceType, service.ImplementationInstance);
            }
            else
            {
                cat.Register(service.ServiceType, service.ImplementationType,    service.Lifetime.AsCatLifetime());
            }
        }
        return new CatBuilder(cat);
    }
    public IServiceProvider CreateServiceProvider(CatBuilder containerBuilder) => containerBuilder.BuildServiceProvider();
}

Cat having expression lifecycle service .NET Core DI framework consistent, so we will transition from the registration service type into ServiceDescriptor ServiceRegistry type, direct conversion to complete the life cycle of two kinds of modes, particularly the conversion implemented in a AsCatLifetime extension method.

internal static class Extensions
{
    public static Lifetime AsCatLifetime(this ServiceLifetime lifetime)
    {
        return lifetime switch
        {
            ServiceLifetime.Scoped => Lifetime.Self,
            ServiceLifetime.Singleton => Lifetime.Root,
            _ => Lifetime.Transient,
        };
    }
}

Next, we demonstrate how to create CatServiceProviderFactory IServiceProvider objects into the container as a dependency. We define the interfaces and the corresponding implementation types as follows, wherein Foo, Bar, Baz and Qux type were realized corresponding interface IFoo, IBar, IBaz and IQux, which marked a MapToAttribute characteristics registered IQux corresponding interface Qux type between mapping. In order to reflect Cat control of the service instance lifecycle, we let them derive from the same base class Base. Base implements IDisposable, we output the corresponding text in its constructor and Dispose implemented method to determine when the corresponding instance is created and released.

public interface IFoo {}
public interface IBar {}
public interface IBaz {} 
public interface IQux {}
public interface IFoobar<T1, T2> {}
public class Base : IDisposable
{
    public Base()  => Console.WriteLine($"Instance of {GetType().Name} is created.");
    public void Dispose()  => Console.WriteLine($"Instance of {GetType().Name} is disposed.");
}

public class Foo : Base, IFoo{ }
public class Bar : Base, IBar{ }
public class Baz : Base, IBaz{ } 
[MapTo(typeof(IQux), Lifetime.Root)]
public class Qux : Base, IQux { }
public class Foobar<T1, T2>: IFoobar<T1,T2>
{
    public IFoo Foo { get; }
    public IBar Bar { get; }
    public Foobar(IFoo foo, IBar bar)
    {
        Foo = foo;
        Bar = bar;
    }
}

In the demonstration program below, we created a ServiceCollection collection, and three different lifecycle models were added to the service registry for IFoo, IBar and IBaz interface. According to this we are going to create a collection of ServiceCollection CatServiceProviderFactory object and call its CreateBuilder method to create a corresponding CatBuilder object. We then call the object's Register method CatBuilder completed the bulk service registry entry for the current assembly, which aims to add service for registered IQux / Qux of.

class Program
{
    static void Main()
    {
        var services = new ServiceCollection()
            .AddTransient<IFoo, Foo>()
            .AddScoped<IBar>(_ => new Bar())
            .AddSingleton<IBaz>(new Baz());

        var factory = new CatServiceProviderFactory();
        var builder = factory.CreateBuilder(services)
            .Register(Assembly.GetEntryAssembly());
        var container = factory.CreateServiceProvider(builder);

        GetServices();
        GetServices();
        Console.WriteLine("\nRoot container is disposed.");
        (container as IDisposable)?.Dispose();

        void GetServices()
        {
            using (var scope = container.CreateScope())
            {
                Console.WriteLine("\nService scope is created.");
                var child = scope.ServiceProvider;

                child.GetService<IFoo>();
                child.GetService<IBar>();
                child.GetService<IBaz>();
                child.GetService<IQux>();

                child.GetService<IFoo>();
                child.GetService<IBar>();
                child.GetService<IBaz>();
                child.GetService<IQux>();                     
                Console.WriteLine("\nService scope is disposed.");
            }
        }
    }
}

After creating the IServiceProvider objects into the container as a dependent in CreateServiceProvider CatServiceProviderFactory object method call, we have two calls to the native method GetServices method. GetServices will use this method IServiceProvider object to create a range of services and use IServiceProvider within this range provides two sets of services service instance. IServiceProvider objects created by CatServiceProviderFactory be in the final release by calling its Dispose method. After running the program will output on the console results shown in Figure 4-16, the output reflects the service lifecycle and demonstration program embodies exactly the same.

image

[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-10.html