简体   繁体   中英

Autofac how to use Scoped dependencies in Singletons

Resolving the SingletonClass gives me a new instance of LifetimeClass. Is there a way to resolve a scope dependency from Singleton within the same scope? This is a simple example I created to reproduce the unexpected behavior at my asp net core project.

public class LifetimeClass
{
    public string Value { get; set; }

}
public class Middle
{
    public Middle(LifetimeClass myLifetimeClass)
    {
        myLifetimeClass.Value = "OK";
    }
}

public class SingletonClass
{
    public SingletonClass(LifetimeClass myLifetimeClass)
    {

    }
}


class Program
{
    static void Main(string[] args)
    {
        ContainerBuilder containerBuilder = new ContainerBuilder();
        containerBuilder.RegisterType<LifetimeClass>().InstancePerLifetimeScope();
        containerBuilder.RegisterType<Middle>();
        containerBuilder.RegisterType<SingletonClass>().SingleInstance();
        var container = containerBuilder.Build();

        using (var scope = container.BeginLifetimeScope())
        {
            var a = scope.Resolve<Middle>();
            var b = scope.Resolve<SingletonClass>();
        }
    }
}

I think the answer to this is a no. You can't expect the Lifetime class to be the same instance in both the singleton and middle. I don't believe the behaviour you're getting is unexpected.

You have the LifetimeClass registered as instance per lifetime scope. You have created a scope using BeginLifetimeScope and resolved the Middle instance through it resulting in it having it's instance of LifetimeClass being that of the containing scope.

However, the SingletonClass is registered as a singleton, so it is instantiated from the container directly as would be expected because singletons are not scoped. Therefore its instance of LifetimeClass is also instantiated in the singleton's scope, which is the container, not your scope.

So it would be expected that each of these classes will be resolved with different instances of LifetimeClass.

If you need to deal with a specific LifetimeClass in both, you will either need to change your 'singleton' class to be registered per lifetime scope, or have whatever methods act on the LifetimeClass in the singleton accept the instance as a parameter.

Captive dependency (your LifetimeClass ) depend upon the lifetime of its parent, therefor it will create again a new instance of LifetimeClass , so I can suggest not to inject it to Middle by the constructor but by method injection:

public class SingletonClass
{
    public LifetimeClass LifetimeClass { get; set; }
    public SingletonClass(LifetimeClass lifetimeClass)
    {
        this.LifetimeClass = lifetimeClass;
    }
}

public class Middle
{
    private LifetimeClass _lifetimeClass;
    public void SetLifetimeClass(LifetimeClass lifetimeClass)
    {
        this._lifetimeClass = lifetimeClass;
    }
}


containerBuilder.Register(c =>
{
    var middle = new Middle();
    middle.SetLifetimeClass(c.Resolve<SingletonClass>().LifetimeClass);
    return middle;
});

The scope stays intact:

using (var scope = container.BeginLifetimeScope())
{
    var a = scope.Resolve<Middle>();
    var b = scope.Resolve<SingletonClass>();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM