Asp.NetCore起動プロセス説明(四)

12029 ワード

Asp.NetCore内DI(DependencyInjection)はプロジェクトの終始を貫き、Aspを学ぶ.NetCoreはDIを越えられない.以下、DIはAspで説明する.Net Core内のプロセス

asp.Netcore 3.0以下


Asp.Net core 3.0以下には、IServiceProviderFactoryのデフォルト実装と、IStartupの2つのカスタム置換DIコンテナがある.Configure関数戻り値の変更

1、IServiceProviderFactory


WebHostBuilderを表示Build
        public IWebHost Build()
        {
            var hostingServices = BuildCommonServices(out var hostingStartupErrors);
            var applicationServices = hostingServices.Clone();
            var hostingServiceProvider = GetProviderFromFactory(hostingServices);

            AddApplicationServices(applicationServices, hostingServiceProvider);

            var host = new WebHost(
                applicationServices,
                hostingServiceProvider,
                _options,
                _config,
                hostingStartupErrors);
            try
            {
                host.Initialize();
                
                //         

                return host;
            }
            catch
            {
                host.Dispose();
                throw;
            }

            IServiceProvider GetProviderFromFactory(IServiceCollection collection)
            {
                var provider = collection.BuildServiceProvider();
                var factory = provider.GetService>();

                if (factory != null && !(factory is DefaultServiceProviderFactory))
                {
                    using (provider)
                    {
                        return factory.CreateServiceProvider(factory.CreateBuilder(collection));
                    }
                }

                return provider;
            }
        }

BuildCommonServices関数の再フォロー
        private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)
        {
            var services = new ServiceCollection();

            //         

            services.AddTransient, DefaultServiceProviderFactory>();

            _configureServices?.Invoke(_context, services);

            return services;
        }

考え方が簡単で、DIを登録し、IServiceProviderに戻ってHostコンテナに渡し、IServiceProviderFactoryを見つけ、タイプがD e f a ultServiceProviderFactoryではないと判断すると、DIを変換し、最後に新しいIServiceProviderに戻る.
       public interface IServiceProviderFactory
       {

              TContainerBuilder CreateBuilder(IServiceCollection services);

              IServiceProvider CreateServiceProvider(TContainerBuilder 
containerBuilder);
       }

WebHostBuilder.ConfigureServices内のDI登録がデフォルトで実装されているIServiceProviderFactory IServiceProviderFactoryのプロセスはIServiceProviderFactoryである.CreateBuilder->IServiceProviderFactory.CreateServiceProviderは、まずDIコンテナIServiceCollectionをカスタムコンテナに変換し、カスタムコンテナをIServiceProviderに変換し、最後にルートノードのIServiceProviderに依存すればよい
IServiceProviderFactoryの登録には論理WebHostBuilderがあります.UseDefaultServiceProviderからソースへ
        public static IWebHostBuilder UseDefaultServiceProvider(this IWebHostBuilder hostBuilder, Action configure)
        {
            return hostBuilder.ConfigureServices((context, services) =>
            {
                var options = new ServiceProviderOptions();
                configure(context, options);
                //     IServiceProviderFactory
                services.Replace(ServiceDescriptor.Singleton>(new DefaultServiceProviderFactory(options)));
            });
        }

異曲同工の妙は,これ以上くどくど述べない.

2、IStartup.Configure


おなじみのWebHostBuilderを開くかBuildCommonServices
        private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)
        {
            var services = new ServiceCollection();

            //      

            if (!string.IsNullOrEmpty(_options.StartupAssembly))
            {
                try
                {
                    var startupType = StartupLoader.FindStartupType(_options.StartupAssembly, _hostingEnvironment.EnvironmentName);

                    if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo()))
                    {
                        services.AddSingleton(typeof(IStartup), startupType);
                    }
                    else
                    {
                        services.AddSingleton(typeof(IStartup), sp =>
                        {
                            var hostingEnvironment = sp.GetRequiredService();
                            var methods = StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName);
                            return new ConventionBasedStartup(methods);
                        });
                    }
                }
                catch (Exception ex)
                {
                    var capture = ExceptionDispatchInfo.Capture(ex);
                    services.AddSingleton(_ =>
                    {
                        capture.Throw();
                        return null;
                    });
                }
            }

            _configureServices?.Invoke(_context, services);

            return services;
        }

IStartupからDIへの登録
WebHostBuilderを確認してください.Build
        public IWebHost Build()
        {
            var hostingServices = BuildCommonServices(out var hostingStartupErrors);
            var applicationServices = hostingServices.Clone();
            var hostingServiceProvider = GetProviderFromFactory(hostingServices);

            var host = new WebHost(
                applicationServices,
                hostingServiceProvider,
                _options,
                _config,
                hostingStartupErrors);
            try
            {
                host.Initialize();  //     
                
                //         

                return host;
            }
            catch
            {
                host.Dispose();
                throw;
            }
        }

見てみろInitializeコード
        public void Initialize()
        {
            try
            {
                EnsureApplicationServices();
            }
            catch (Exception ex)
            {
                // EnsureApplicationServices may have failed due to a missing or throwing Startup class.
                if (_applicationServices == null)
                {
                    _applicationServices = _applicationServiceCollection.BuildServiceProvider();
                }

                if (!_options.CaptureStartupErrors)
                {
                    throw;
                }

                _applicationServicesException = ExceptionDispatchInfo.Capture(ex);
            }
        }

見てみろEnsureApplicationServicesコード
        private void EnsureApplicationServices()
        {
            if (_applicationServices == null)
            {
                EnsureStartup();
                _applicationServices = _startup.ConfigureServices(_applicationServiceCollection);
            }
        }

        private void EnsureStartup()
        {
            if (_startup != null)
            {
                return;
            }

            _startup = _hostingServiceProvider.GetService();

            if (_startup == null)
            {
                throw new InvalidOperationException($"No application configured. Please specify startup via IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, injecting {nameof(IStartup)} or specifying the startup assembly via {nameof(WebHostDefaults.StartupAssemblyKey)} in the web host configuration.");
            }
        }

IStartupインタフェースのインスタンスを取得し、IStartupを呼び出す.ConfigureServicesはIServiceProviderインスタンスを返します

Asp.Net Core 3.0以上


Asp.Net Core 3.0以下の設計コードは混乱しすぎてAsp.Net Core 3.0が始まり、DIに代わる流れが簡潔になりました
デフォルトのプログラムエントリ
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup();
                });
    }

ホストを表示します.CreateDefaultBuilder
        public static IHostBuilder CreateDefaultBuilder(string[] args)
        {
            var builder = new HostBuilder();

            //      

            return builder;
        }

HostBuilderに向かいます.Build
        public IHost Build()
        {
            //      
            CreateServiceProvider();

            return _appServices.GetRequiredService();
        }

HostBuilderを表示CreateServiceProvider
        private void CreateServiceProvider()
        {
            var services = new ServiceCollection();
            //      

            var containerBuilder = _serviceProviderFactory.CreateBuilder(services);

            foreach (var containerAction in _configureContainerActions)
            {
                containerAction.ConfigureContainer(_hostBuilderContext, containerBuilder);
            }

            _appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder);

            if (_appServices == null)
            {
                throw new InvalidOperationException($"The IServiceProviderFactory returned a null IServiceProvider.");
            }

            // resolve configuration explicitly once to mark it as resolved within the
            // service provider, ensuring it will be properly disposed with the provider
            _ = _appServices.GetService();
        }

ここには_ServiceProviderFactory、定義に移動
    public class HostBuilder : IHostBuilder
    {
        //      
        private IServiceFactoryAdapter _serviceProviderFactory = new ServiceFactoryAdapter(new DefaultServiceProviderFactory());
    }

対応するパラメータには、2つの関数が異なるリロードされたUseServiceProviderFactoryがあります.
        public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory)
        {
            _serviceProviderFactory = new ServiceFactoryAdapter(factory ?? throw new ArgumentNullException(nameof(factory)));
            return this;
        }
        
        public IHostBuilder UseServiceProviderFactory(Func> factory)
        {
            _serviceProviderFactory = new ServiceFactoryAdapter(() => _hostBuilderContext, factory ?? throw new ArgumentNullException(nameof(factory)));
            return this;
        }        

後記


レモンの大物はAspと言った.Net CoreはせめてDIに置き換えられるところが3箇所~もう1箇所ソースコードを見てみましたがIApplicationBuilderFactoryかな
    public interface IApplicationBuilderFactory
    {
        IApplicationBuilder CreateBuilder(IFeatureCollection serverFeatures);
    }

ここでCreateBuilderはIApplicationBuilder IApplicationBuilderのIocオブジェクトを返しますここで設定できます
もし内容に対して交流と学习のがあるならば、プラスすることができます.Netアプリケーションフレームワーク交流グループ、グループ番号386092459