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

Spike: An alternative ServiceCollectionExtensions for named services #240

Closed
petrsvihlik opened this issue Oct 1, 2020 · 1 comment · Fixed by #254
Closed

Spike: An alternative ServiceCollectionExtensions for named services #240

petrsvihlik opened this issue Oct 1, 2020 · 1 comment · Fixed by #254

Comments

@petrsvihlik
Copy link
Contributor

petrsvihlik commented Oct 1, 2020

Motivation

Although it's convenient for the consumers and tempting for authors to offer support for registering named services out of the box, e.g.:

  • public static IServiceCollection AddDeliveryClient(this IServiceCollection services, string name, IConfiguration configuration, string configurationSectionName = "DeliveryOptions")
  • public static IServiceCollection AddDeliveryClientCache(this IServiceCollection services, string name, DeliveryCacheOptions options)

it shouldn't really be the responsibility of this SDK to facilitate complex DI resolution scenarios.

Current problems that we see:

  • not to introduce another NuGet dependency, we are solving the problem with factories which is a workaround for the ASP.NET Core's default DI container
  • it doesn't solve the problem of nested dependencies completely (scenarios such as using different type providers, link and rich-text resolvers, etc.)
  • lots of code to maintain and scenarios to be covered with unit tests

Proposed solution

public class TestGrandChildResolutions
{
    public interface IA1 { IB B { get; set; } }
    public class A1 : IA1 { public IB B { get; set; } public A1(IB b) { this.B = b; } }

    public interface IA2 { IB B { get; set; } }
    public class A2 : IA2 { public IB B { get; set; } public A2(IB b) { this.B = b; } }

    public interface IB { IC C { get; set; } }
    public class B : IB { public IC C { get; set; } public B(IC c) { this.C = c; } }

    public interface IC { }
    public class C1 : IC { }
    public class C2 : IC { }

    [Test]
    public void Test()
    {
        ContainerBuilder builder = new ContainerBuilder();

        builder.RegisterType<C1>().AsImplementedInterfaces().Named<IC>("C1-Name");
        builder.RegisterType<C2>().AsImplementedInterfaces().Named<IC>("C2-Name");

        builder.RegisterType<B>().AsImplementedInterfaces().WithParameter(ResolvedParameter.ForNamed<IC>("C1-Name")).Named<IB>("B1-Name");
        builder.RegisterType<B>().AsImplementedInterfaces().WithParameter(ResolvedParameter.ForNamed<IC>("C2-Name")).Named<IB>("B2-Name");

        builder.RegisterType<A1>().AsImplementedInterfaces().WithParameter(ResolvedParameter.ForNamed<IB>("B1-Name"));
        builder.RegisterType<A2>().AsImplementedInterfaces().WithParameter(ResolvedParameter.ForNamed<IB>("B2-Name"));

        IContainer container = builder.Build();
        IA1 a1 = container.Resolve<IA1>();
        IA2 a2 = container.Resolve<IA2>();

        Assert.IsInstanceOf<C1>(a1.B.C, "C1 Check");
        Assert.IsInstanceOf<C2>(a2.B.C, "C2 Check");
    }
}
  • and finally, remove the existing implementation of named services

Additional context

  • We should then document the new library and offer best practices.
  • Once we validate that this approach works, we should get rid of the current named services support in the SDK.
  • A comment by @vletierce

I have been using the SDK over a year now and must say the fact that I can't assigned a custom type provider to a named HttpClient through the .NetCore dependency injection mechanisme represents a real problem on my side.
There is the possibility to create an instance of a SharedTypeProvider class however it only works if all your content types (accross projects) have different names, unfortunately in my case I have content types that share the same name accross projects.

Could we have quick exemple of what solution 4 would look like ? In my case it is very important that I can match a content type provider to a specific named client.

Thanks

@petrsvihlik
Copy link
Contributor Author

Other implementations of keyed services:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment