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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions