Exemplo n.º 1
0
    private void UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, HostBuilderContext context, IServiceCollection services, object?instance = null)
    {
        var webHostBuilderContext = GetWebHostBuilderContext(context);
        var webHostOptions        = (WebHostOptions)context.Properties[typeof(WebHostOptions)];

        ExceptionDispatchInfo?startupError     = null;
        ConfigureBuilder?     configureBuilder = null;

        try
        {
            // We cannot support methods that return IServiceProvider as that is terminal and we need ConfigureServices to compose
            if (typeof(IStartup).IsAssignableFrom(startupType))
            {
                throw new NotSupportedException($"{typeof(IStartup)} isn't supported");
            }
            if (StartupLoader.HasConfigureServicesIServiceProviderDelegate(startupType, context.HostingEnvironment.EnvironmentName))
            {
                throw new NotSupportedException($"ConfigureServices returning an {typeof(IServiceProvider)} isn't supported.");
            }

            instance ??= ActivatorUtilities.CreateInstance(new HostServiceProvider(webHostBuilderContext), startupType);
            context.Properties[_startupKey] = instance;

            // Startup.ConfigureServices
            var configureServicesBuilder = StartupLoader.FindConfigureServicesDelegate(startupType, context.HostingEnvironment.EnvironmentName);
            var configureServices        = configureServicesBuilder.Build(instance);

            configureServices(services);

            // REVIEW: We're doing this in the callback so that we have access to the hosting environment
            // Startup.ConfigureContainer
            var configureContainerBuilder = StartupLoader.FindConfigureContainerDelegate(startupType, context.HostingEnvironment.EnvironmentName);
            if (configureContainerBuilder.MethodInfo != null)
            {
                var containerType = configureContainerBuilder.GetContainerType();
                // Store the builder in the property bag
                _builder.Properties[typeof(ConfigureContainerBuilder)] = configureContainerBuilder;

                var actionType = typeof(Action <,>).MakeGenericType(typeof(HostBuilderContext), containerType);

                // Get the private ConfigureContainer method on this type then close over the container type
                var configureCallback = typeof(GenericWebHostBuilder).GetMethod(nameof(ConfigureContainerImpl), BindingFlags.NonPublic | BindingFlags.Instance) !
                                        .MakeGenericMethod(containerType)
                                        .CreateDelegate(actionType, this);

                // _builder.ConfigureContainer<T>(ConfigureContainer);
                typeof(IHostBuilder).GetMethod(nameof(IHostBuilder.ConfigureContainer)) !
                .MakeGenericMethod(containerType)
                .InvokeWithoutWrappingExceptions(_builder, new object[] { configureCallback });
            }

            // Resolve Configure after calling ConfigureServices and ConfigureContainer
            configureBuilder = StartupLoader.FindConfigureDelegate(startupType, context.HostingEnvironment.EnvironmentName);
        }
        catch (Exception ex) when(webHostOptions.CaptureStartupErrors)
        {
            startupError = ExceptionDispatchInfo.Capture(ex);
        }

        // Startup.Configure
        services.Configure <GenericWebHostServiceOptions>(options =>
        {
            options.ConfigureApplication = app =>
            {
                // Throw if there was any errors initializing startup
                startupError?.Throw();

                // Execute Startup.Configure
                if (instance != null && configureBuilder != null)
                {
                    configureBuilder.Build(instance)(app);
                }
            };
        });
    }