z4kn4fein / stashbox-extensions-dependencyinjection

Stashbox Integration for ASP.NET Core, .NET Generic Host and ServiceCollection based applications.
https://z4kn4fein.github.io/stashbox
MIT License
17 stars 2 forks source link

Question: using ServiceProvider as limited parent container #8

Closed michaelplavnik closed 1 year ago

michaelplavnik commented 1 year ago

Could you please suggest what can be done to use existing ServiceProvider for missing dependency resolution? I can assume that ServiceCollection used to build ServiceProvider is available. The approach to copy descriptors into container works, except for singletons.

I came up with below POC, but may be there is a better way to do it....

static void RegisterServiceDescriptors(IStashboxContainer container, IEnumerable<ServiceDescriptor> services, IServiceProvider sp)
{
    foreach (var descriptor in services)
    {
        var lifetime = ChooseLifetime(descriptor.Lifetime);

        if (descriptor.ImplementationInstance != null)
        {
            container.RegisterInstance(descriptor.ImplementationInstance, descriptor.ServiceType);
        }
        else if (descriptor.ImplementationType != null)
        {
            if (descriptor.Lifetime != ServiceLifetime.Singleton)
                container.Register(descriptor.ServiceType, descriptor.ImplementationType, ctx => ctx.WithLifetime(lifetime));
            else
                RegisterDelegate(container, descriptor, sp, lifetime);
        }
        else if (descriptor.ImplementationFactory != null)
        {
            if (descriptor.Lifetime != ServiceLifetime.Singleton)
                container.Register(descriptor.ServiceType, ctx => ctx.WithFactory(descriptor.ImplementationFactory).WithLifetime(lifetime));
            else
                RegisterDelegate(container, descriptor, sp, lifetime);
        }
    }

    void RegisterDelegate(IStashboxContainer container, ServiceDescriptor descriptor, IServiceProvider sp, LifetimeDescriptor lifetime)
    {
        container.Register(descriptor.ServiceType, ctx => ctx
            .WithFactory(dr => sp.GetRequiredService(descriptor.ServiceType))
            .WithoutDisposalTracking()
            .WithLifetime(lifetime));
    }
}
z4kn4fein commented 1 year ago

Hi @michaelplavnik, thank you for reaching out! Could you please explain a bit more what exactly you want to achieve? My apologies, but I'm not sure I clearly understand based on your post above.

michaelplavnik commented 1 year ago

@z4kn4fein Thank you for responding. In rational world one will replace Microsoft DI with Stashbox and then child container will become natural pattern. However at my work, presently, I cannot replace top level container, but I have a need to isolate processing components, and thus a need for child container pattern. The top level service provider and it's related service collection are available. I tried to use Stasbox extension package, and it's behavior is to create a second instance of top level singleton. My goal is to share this instance with serviceprovider. The code in original post is trying to implement singleton sharing. But may be you have a deeper insight on how to achieve singleton sharing and even scope sharing.

z4kn4fein commented 1 year ago

Hi @michaelplavnik, thanks for the clarification! I think I get it now. As the top-level service provider is entirely independent of the Stashbox container, I couldn't tell you a better solution than yours.

Another way would be a custom resolver that would fall back to the top-level service provider whenever the Stashbox container couldn't find a specific type. But I'm unsure whether it would be worth playing around this way if your solution already works for you.

However, neither will allow the Stashbox container to act as a proper child container, as it would be a black box for the top-level service provider. So whenever a resolution request jumps up to the service provider, it won't jump back and use the dependencies in the Stashbox container. But it'll work as long as the services in the top-level service provider are isolated and they don't have to use dependencies from the "child", only the other way around.

michaelplavnik commented 1 year ago

Thank you