ipjohnson / Grace

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

Problem with keyed service using SingletonPerScope and IsRequired = false #186

Closed eglauko closed 5 years ago

eglauko commented 5 years ago

When I need different implementations of the same interface, I use qualifiers, AsKeyed, when I configure the services. If I have a class with a property to be injected with a key, and not required, no error occurs and the property value will be null. Is this right.

Take a look in my test, there is no service for 'gama' key.

public void Container_TestOptionalQualifiedServiceLocate()
{
    var container = new DependencyInjectionContainer(GraceDynamicMethod.Configuration());

    container.Configure(c =>
    {
        c.Export<AlphaNameService>().AsKeyed<INameService>("Alpha");
        c.Export<BethaNameService>().AsKeyed<INameService>("Betha");

        c.Export<MultiNameService>()
            .ImportProperty(s => s.Alpha).LocateWithKey("Alpha").IsRequired(false)
            .ImportProperty(s => s.Betha).LocateWithKey("Betha").IsRequired(false)
            .ImportProperty(s => s.Gamma).LocateWithKey("Gamma").IsRequired(false);
    });

    var multiNameService = container.Locate<MultiNameService>();
    Assert.IsNotNull(multiNameService);

    Assert.IsNotNull(multiNameService.Alpha);
    Assert.AreEqual("Alpha", multiNameService.Alpha.Name);

    Assert.IsNotNull(multiNameService.Betha);
    Assert.AreEqual("Betha", multiNameService.Betha.Name);

    Assert.IsNull(multiNameService.Gamma);
}

This test passes. But if I change the lifestyle of one of the services to SingletonPerScope, the test fails. The Gamma property will be assigned with the class that is configured with SingletonPerScope.

c.Export<AlphaNameService>().AsKeyed<INameService>("Alpha").Lifestyle.SingletonPerScope();

take a try


    public interface INameService
    {
        string Name { get; }
    }

    public class AlphaNameService : INameService
    {
        public string Name => "Alpha";
    }

    public class BethaNameService : INameService
    {
        public string Name => "Betha";
    }

    public class MultiNameService
    {
        public INameService Alpha { get; set; }

        public INameService Betha { get; set; }

        public INameService Gamma { get; set; }
    }
ipjohnson commented 5 years ago

@eglauko That's not correct but I believe I know why it happens. There is a short cut when it comes to SingletonPerScope which must not be taking into account keyed resolution. I'll look at fixing it this weekend.

ipjohnson commented 5 years ago

OK I've addressed this issue. It turned out to be the dependency was being pulled accidentally from the injection scope as a last ditch effort to find something that matched. I've since tightened up the code a little bit and the test now passes.