/// <summary>
        /// Запускаем приложение.
        /// </summary>
        /// <param name="buildContext">Провайдер сервисов.</param>
        /// <returns>Провайдер к коллекции зарегистрированных сервисов.</returns>
        public IBuildContext Start(IBuildContext buildContext)
        {
            _buildContext.Logger.LogInformation("Starting services");
            var measureSession = new MeasureSession("Starting services");

            measureSession.ExecuteWithTimer("StartRunnables", () =>
            {
                // Запуск сервисов.
                buildContext.ServiceProvider.StartRunnablesAsync(_buildContext.Logger).Wait();
            });

            measureSession.LogMeasures(_buildContext.Logger);

            return(buildContext);
        }
        /// <summary>
        /// Составляем приложение.
        /// </summary>
        /// <param name="startupConfiguration">Параметры запуска приложения.</param>
        /// <returns>Провайдер к коллекции зарегистрированных сервисов.</returns>
        public IBuildContext Build(StartupConfiguration startupConfiguration)
        {
            _buildContext = new BuildContext {
                StartupConfiguration = startupConfiguration,
            };
            var measureSession = new MeasureSession("Application startup");

            // Разбор параметров командной строки
            if (startupConfiguration.SetPropertiesFromCommandLineArgs)
            {
                startupConfiguration.BuildUpFromCommandLineArgs(startupConfiguration.CommandLineArgs.Args);
            }

            SetEnvVariables(startupConfiguration);

            // Can use defined service collection or create new
            _buildContext.ServiceCollection = startupConfiguration.ServiceCollection ?? new ServiceCollection();
            var serviceCollection = _buildContext.ServiceCollection;

            using (measureSession.StartTimer("ConfigureLogging"))
            {
                // Получение сконфигурированной фабрики логирования.
                var configureLogging = startupConfiguration.ConfigureLogging ?? DefaultLogging.ConfigureLogging;
                _buildContext.LoggerFactory = configureLogging();
                _buildContext.Logger        = _buildContext.LoggerFactory.CreateLogger("Bootstrap");
            }

            using (measureSession.StartTimer("LoadTypes"))
            {
                // Получение информации об окружении.
                _buildContext.StartupInfo = ReflectionUtils.GetStartupInfo();

                // Переключим текущую директорию на директорию запуска.
                Directory.SetCurrentDirectory(_buildContext.StartupInfo.BaseDirectory);
                _buildContext.StartupInfo.CurrentDirectory = _buildContext.StartupInfo.BaseDirectory;

                // Загрузка сборок в память
                _buildContext.Assemblies = ReflectionUtils
                                           .LoadAssemblies(_buildContext.StartupInfo.BaseDirectory, _buildContext.StartupConfiguration.AssemblyScanPatterns)
                                           .Concat(new[] { typeof(ApplicationBuilder).Assembly })
                                           .Distinct()
                                           .ToArray();

                _buildContext.Logger.LogDebug($"Loaded {_buildContext.Assemblies.Length} assemblies");

                if (_buildContext.Assemblies.Length > 20)
                {
                    var assemblyScanPatterns     = _buildContext.StartupConfiguration.AssemblyScanPatterns;
                    var assemblyScanPatternsText = string.Join(",", assemblyScanPatterns);
                    _buildContext.Logger.LogWarning($"Diagnostic: too many assemblies found. Specify AssemblyScanPatterns. Loaded: {_buildContext.Assemblies.Length} assemblies, AssemblyScanPatterns: {assemblyScanPatternsText}");
                }

                // Список типов
                _buildContext.ExportedTypes = _buildContext.Assemblies.SelectMany(assembly => assembly.GetDefinedTypesSafe()).ToArray();

                _buildContext.LogHeader();//todo: assemblies loaded? types loaded
            }

            using (measureSession.StartTimer("LoadConfiguration"))
            {
                // Загрузка конфигурации
                ConfigurationReader.LoadConfiguration(_buildContext);

                // Регистрируем конфигурацию в виде IConfiguration и IConfigurationRoot
                serviceCollection.Replace(ServiceDescriptor.Singleton <IConfiguration>(_buildContext.ConfigurationRoot));
                serviceCollection.Replace(ServiceDescriptor.Singleton <IConfigurationRoot>(_buildContext.ConfigurationRoot));
            }

            using (measureSession.StartTimer("ConfigureServices"))
            {
                try
                {
                    // Конфигурирование сервисов
                    ConfigureServices(_buildContext);

                    // Строим провайдер.
                    _buildContext.ServiceProvider = _buildContext.ServiceCollection.BuildServiceProvider();
                }
                catch (Exception exception)
                {
                    _buildContext.Logger.LogError(new EventId(0), exception, exception.Message);
                    throw;
                }
            }

            // Dump значений конфигурации в лог
            if (startupConfiguration.DumpConfigurationToLog)
            {
                _buildContext.ConfigurationRoot.DumpConfigurationToLog(_buildContext.LoggerFactory, startupConfiguration.IsSecretConfigurationKey, "Configuration");
            }

            measureSession.LogMeasures(_buildContext.Logger);

            return(_buildContext);
        }