ipjohnson / Grace

Grace is a feature rich dependency injection container library
MIT License
336 stars 33 forks source link

Resolving delegate factories for multiple services of the same interface with metadata #267

Open daveraine opened 4 years ago

daveraine commented 4 years ago

I'm trying to resolve multiple services with metadata using a delegate factory but seems this is not supported. I've modified the LazyMetadata_StronglyTyped test to illustrate what I'm trying to achieve.

Is this something that could be supported?

public delegate IMultipleService MultipleServiceDelegate();

[Fact]
public void LazyMetadata_StronglyTyped_Delegate()
{
    var container = new DependencyInjectionContainer();

    container.Configure(c =>
    {
        c.Export<MultipleService1>().As<IMultipleService>().WithMetadata("IntValue", 1);
        c.Export<MultipleService2>().As<IMultipleService>().WithMetadata("IntValue", 2);
        c.Export<MultipleService3>().As<IMultipleService>().WithMetadata("IntValue", 3);
        c.Export<MultipleService4>().As<IMultipleService>().WithMetadata("IntValue", 4);
        c.Export<MultipleService5>().As<IMultipleService>().WithMetadata("IntValue", 5);
    });

    var array = container.Locate<Lazy<MultipleServiceDelegate, MetadataValue>[]>();

    Assert.NotNull(array);
    Assert.Equal(5, array.Length);

    Assert.Equal(1, array[0].Metadata.IntValue);
    Assert.Equal(2, array[1].Metadata.IntValue);
    Assert.Equal(3, array[2].Metadata.IntValue);
    Assert.Equal(4, array[3].Metadata.IntValue);
    Assert.Equal(5, array[4].Metadata.IntValue);

    Assert.IsType<MultipleService1>(array[0].Value());
    Assert.IsType<MultipleService2>(array[1].Value());
    Assert.IsType<MultipleService3>(array[2].Value());
    Assert.IsType<MultipleService4>(array[3].Value());
    Assert.IsType<MultipleService5>(array[4].Value());
}
ipjohnson commented 3 years ago

Hi @daveraine

I apologize I usually get back to people quicker but some how I missed this issue. This should work and does for Func<IMultipleService> but apparently fails for a custom delegate.

What's failing is the auto registration of the MultipleServiceDelegate delegate. You can get around this by explicitly registering it.

            container.Configure(c =>
            {
                c.Export<MultipleService1>().As<IMultipleService>().WithMetadata("IntValue", 1);
                c.Export<MultipleService2>().As<IMultipleService>().WithMetadata("IntValue", 2);
                c.Export<MultipleService3>().As<IMultipleService>().WithMetadata("IntValue", 3);
                c.Export<MultipleService4>().As<IMultipleService>().WithMetadata("IntValue", 4);
                c.Export<MultipleService5>().As<IMultipleService>().WithMetadata("IntValue", 5);

                c.AddActivationStrategy(new DelegateNoArgWrapperStrategy(typeof(MultipleServiceDelegate), c.OwningScope));
            });
daveraine commented 3 years ago

Awesome, thanks for the info. No worries about the late reply. I actually refactored my code to use keyed registrations and extra data to achieve what I wanted and I think that is a better solution for me in the end, but good to hear there is a workaround currently if I do need this behaviour.