seesharper / LightInject

An ultra lightweight IoC container
http://www.lightinject.net
MIT License
618 stars 122 forks source link

I think there is a problem with PerLogicalCallContextScopeManagerProvider #269

Open factorx22 opened 8 years ago

factorx22 commented 8 years ago

The problem is when I use a scope in the main thread, and then use individual scopes in sub threads, the sub threads seem to share the same scope, the scope are not nested and they are defined in different threads. The current sub thread can finalize de scope in the other sub threads and the other sub threads result in 'Attempt to end a scope before all child scopes are completed' exception. I am concerned that this can affect a scenario where using autostart feature of wcf service, which use a scope for preload task in main thread and after on every wcf service request, creating an scope in the wcf context sub thread.

`using System; using System.ComponentModel; using System.ServiceProcess; using System.Threading;

namespace IoCTest { partial class Service : ServiceBase {

    BackgroundWorker _proc1 = new BackgroundWorker { WorkerSupportsCancellation = true };
    BackgroundWorker _proc2 = new BackgroundWorker { WorkerSupportsCancellation = true };
    BackgroundWorker _proc3 = new BackgroundWorker { WorkerSupportsCancellation = true };

    public Service()
    {
        InitializeComponent();

        _proc1.DoWork += DoJob;
        _proc2.DoWork += DoJob;
        _proc3.DoWork += DoJob;

        new Log().LogDebug("Initializing IoC");
        IoC.Initialize();
    }

    public void Run()
    {
        OnStart(null);
    }

    public void End()
    {
        OnStop();
    }

    protected override void OnStart(string[] args)
    {
        new Log().LogDebug("Start Service.");

        //I think there is a problem with PerLogicalCallContextScopeManagerProvider
        //The problem is when I use a scope in the main thread, and then use individual scopes in sub threads, 
        //the sub threads seem to share the same scope, but the scope are not nested and they are defined in different threads.
        //This is not the expected behavior, i expect each thread use own scope.
        ///////////////////////////////////////////////////////////////////////////////////////
        new Log().LogDebug("Begin scope in main thread.");
        using (IoC.Current.BeginScope())
        {
            var _instance = IoC.Current.GetInstance<ClassA>();
            _instance.DoSomething();
            _instance = IoC.Current.GetInstance<ClassA>(); //here same prev instance is ok  
            _instance.DoSomething();
            new Log().LogDebug("End scope in main thread");
        }
        ///////////////////////////////////////////////////////////////////////////////////////

        //the scope in sub threads have unexpected behavior. if i comment de scope in main thread all works fine
        _proc1.RunWorkerAsync(100);
        _proc2.RunWorkerAsync(300);
        _proc3.RunWorkerAsync(150);

    }

    protected override void OnStop()
    {
        _proc1.CancelAsync();
        _proc2.CancelAsync();
        _proc3.CancelAsync();
        new Log().LogDebug("End Service.");
    }

    private void DoJob(object sender, DoWorkEventArgs e)
    {
        var _sleepTime = (int)e.Argument;
        var _worker = sender as BackgroundWorker;
        while (true)
        {

            try
            {
                new Log().LogDebug("Begin scope sub thread");

                using (IoC.Current.BeginScope())
                {

                    var _instance = IoC.Current.GetInstance<ClassA>(); //in many case get instances created in scope of the other subthread.
                    _instance.DoSomething();
                    _instance = IoC.Current.GetInstance<ClassA>(); 
                    _instance.DoSomething();
                    new Log().LogDebug("End scope sub thread");

                } //the current thread dispose de scope in the other sub threads and the other sub threads have 
                //Attempt to end a scope before all child scopes are completed exception
                //I am concerned that this may affect 

            }
            catch (Exception err)
            {
                new Log().LogError(err.Message);
            }
            Thread.Sleep(_sleepTime);

        }
    }
}

}

using LightInject; using System;

namespace IoCTest { public static class IoC {

    static IServiceContainer _currentContainer;

    static IoC()
    {
        _currentContainer = new ServiceContainer();
        _currentContainer.ScopeManagerProvider = new PerLogicalCallContextScopeManagerProvider();
        _currentContainer.Register<ClassA>(new PerScopeLifetime());
        _currentContainer.Register<ClassB>(new PerScopeLifetime());

    }

    public static void Initialize()
    {

    }
    public static IServiceContainer Current
    {
        get
        {
            return _currentContainer;
        }
    }

} }`

factorx22 commented 8 years ago

ligthinject is an amazing job.

sorry my english is terrible but you can look my test and see better the problem.

IoCTest.zip