Skip to content

Resolve aggregate services using keyed registrations #14

@rcdailey

Description

@rcdailey

I have an aggregate service containing interfaces that are only registered with keys (using Keyed<>()). Furthermore, each interface within the aggregate has the same number of concrete implementations, which are all mapped to the same key. Essentially it's a non-jagged 2D array of registrations.

I'd like the ability to resolve the aggregate service with IIndex, which would forward the key to the resolution of the services within it.

I have an example that demonstrates the behavior I'm looking for, which I'll provide below.

internal interface IMyService2
{
    void PrintInfo();
}

internal interface IMyService1
{
    void PrintInfo();
}

internal class MyService1Impl1 : IMyService1
{
    public void PrintInfo()
    {
        Console.WriteLine(" - MyService1Impl1");
    }
}

internal class MyService1Impl2 : IMyService1
{
    public void PrintInfo()
    {
        Console.WriteLine(" - MyService1Impl2");
    }
}

internal class MyService2Impl1 : IMyService2
{
    public void PrintInfo()
    {
        Console.WriteLine(" - MyService2Impl1");
    }
}

internal class MyService2Impl2 : IMyService2
{
    public void PrintInfo()
    {
        Console.WriteLine(" - MyService2Impl2");
    }
}

internal interface IMyAggregateServices
{
    public IMyService1 Service1 { get; init; }
    public IMyService2 Service2 { get; init; }
}

public static class Program
{
    public static void Main()
    {
        var builder = new ContainerBuilder();

        builder.RegisterType<MyService1Impl1>().Keyed<IMyService1>("one");
        builder.RegisterType<MyService1Impl2>().Keyed<IMyService1>("one");
        builder.RegisterType<MyService2Impl1>().Keyed<IMyService2>("two");
        builder.RegisterType<MyService2Impl2>().Keyed<IMyService2>("two");
        builder.RegisterAggregateService<IMyAggregateServices>();

        var container = builder.Build();

        var index = container.Resolve<IIndex<string, IMyAggregateServices>>();
        var aggregateServices = index["one"];

        Console.WriteLine("Print Service1:");
        aggregateServices.Service1.PrintInfo();

        Console.WriteLine("Print Service2:");
        aggregateServices.Service2.PrintInfo();
    }
}

Above, I expect the following output:

Print Service1:
 - MyService1Impl1
Print Service2:
 - MyService2Impl1

Obviously, the code above won't even execute. Instead, I get this exception:

Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'one (ConsoleApp1.IMyAggregateServices)' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.

If there's a reasonable workaround, I'm open to that as well. I'm sure I could implement my own concrete aggregate class to simulate this somehow, but I was hoping native support for this would be added.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions