Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 6 - Get ServiceProvider Service from MS DI Extension before build() #644

Open
mannok opened this issue Jan 19, 2023 · 4 comments
Open

Comments

@mannok
Copy link

mannok commented Jan 19, 2023

internal class Program
    {
        public static void Main(string[] args)
        {
            var builder = Host.CreateDefaultBuilder(args);

            builder.ConfigureServices(services =>
                {
                    services.AddTransient<Startup>();

                    services.AddTransient<IPatchTarget>(serviceProvider =>
                    {
                        return new PatchTarget;
                    });
                });

            var windsorContainer = new WindsorContainer();
            builder.UseWindsorContainerServiceProvider(windsorContainer);
            windsorContainer.Install(new RepositoriesInstaller());

            var host = builder.Build();

            host.Services.GetRequiredService<Startup>().ExecuteAsync().Wait();
        }

        public class RepositoriesInstaller : IWindsorInstaller
        {
            public void Install(IWindsorContainer container, IConfigurationStore store)
            {
                container.Resolve<IPatchTarget>(); // PROBLEMATIC STATEMENT
            }
        }
    }

Please consider the above problematic statement, how could I resolve the imtermediate registered service in IWindsorInstaller? Since the HostBuilder has not yet built, I cannot resolve component. This may lead to the resolving problem for MS DI orginal registered components like IConfiguration

Any advise is much appreciated. Thanks

@ikkentim
Copy link
Contributor

ikkentim commented Apr 21, 2023

This is simply not possible. With MS DI you first build a collection of services (IServiceCollection) which will then be compiled into service provider (IServiceProvider). While the service provider has not yet been compiled, none of the services can be resolved. I think the underlying philosophy of MS DI is that DI containers are not configured during runtime.

The Windsor Container only receives the service collection when the service provider is built (during IHostBuilder.Build).

@TaviTruman
Copy link

You are correct that in Microsoft.Extensions.DependencyInjection (MS DI), dependency injection is primarily configured during the startup phase of the application, and not at runtime. It follows a two-step process:

Registering services in an IServiceCollection object during the startup/configuration phase. This is typically done in the ConfigureServices method of the Startup class.
Building an IServiceProvider from the IServiceCollection, which resolves the registered services and their dependencies.

Once the IServiceProvider is built, it is generally not recommended to modify it during runtime, as this could lead to unexpected behavior and threading issues. However, there might be some scenarios where you need to update the DI container at runtime. In such cases, you can utilize a factory pattern or other workarounds to achieve this.

For example, you can register a factory in the DI container that is responsible for creating and managing instances of a particular service. The factory can then be updated during runtime to change the way the service is created or to use a different implementation. This approach still adheres to the MS DI philosophy but provides some flexibility in managing service instances.

Remember, though, that runtime modifications should be used with caution and only when necessary, as they might lead to complications or unintended side effects.

@TaviTruman
Copy link

FYI - I am using MS DI and Castle Windsor container together; I simply register IServiceProvide with Windsor.

@TaviTruman
Copy link

TaviTruman commented Apr 23, 2023

Maybe something like this may work:

`using System;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Microsoft.Extensions.DependencyInjection;

internal class Program
{
public static void Main(string[] args)
{
var builder = Host.CreateDefaultBuilder(args);

    builder.ConfigureServices(services =>
    {
        services.AddTransient<Startup>();
    });

    var windsorContainer = new WindsorContainer();
    builder.UseWindsorContainerServiceProvider(windsorContainer);
    windsorContainer.Install(new RepositoriesInstaller());

    var host = builder.Build();

    host.Services.GetRequiredService<Startup>().ExecuteAsync().Wait();
}

public class RepositoriesInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<IPatchTarget>().ImplementedBy<PatchTarget>().LifestyleTransient()
        );
    }
}

}
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants