Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在多线程Windows服务中使用Ninject在每个刻度上获取依赖项(DbContext)的新实例?_C#_Multithreading_Entity Framework_Ninject - Fatal编程技术网

C# 如何在多线程Windows服务中使用Ninject在每个刻度上获取依赖项(DbContext)的新实例?

C# 如何在多线程Windows服务中使用Ninject在每个刻度上获取依赖项(DbContext)的新实例?,c#,multithreading,entity-framework,ninject,C#,Multithreading,Entity Framework,Ninject,我继承了一个Windows服务,其中所有依赖项都是在服务启动时创建的,并注入到临时作用域中 我们在这个服务中遇到了很多问题,尤其是我们有一个DbContext,它在服务运行的整个过程中都存在,并且每次都注入不同的实例 我想进行重构,以便每个工作线程都能被注入自己的DbContext,它将只在每个周期内有效 我已经看过了。对于单线程应用程序来说,它看起来不错,但对于多线程应用程序来说,它就不合适了。我也考虑过。虽然这会给每个线程提供它自己的实例,但就线程而言,它们是单线程,因此它不满足每勾号的要求

我继承了一个Windows服务,其中所有依赖项都是在服务启动时创建的,并注入到临时作用域中

我们在这个服务中遇到了很多问题,尤其是我们有一个DbContext,它在服务运行的整个过程中都存在,并且每次都注入不同的实例

我想进行重构,以便每个工作线程都能被注入自己的DbContext,它将只在每个周期内有效

我已经看过了。对于单线程应用程序来说,它看起来不错,但对于多线程应用程序来说,它就不合适了。我也考虑过。虽然这会给每个线程提供它自己的实例,但就线程而言,它们是单线程,因此它不满足每勾号的要求

我目前的想法是使用and注入一个范围工厂,我可以使用它在每个刻度上创建一个新的范围

这是路吗?如有任何建议、提示或替代方案,将不胜感激

更新


由于时间限制,我们最终使用了命名的作用域,但它没有@BatteryBackupUnit的解决方案那么干净。在图的后面还有一些依赖项,它们需要DbContext,我们必须再次注入范围工厂才能获得它。使用@ BATTYBACKUPUnE的解决方案,我们可以从<代码> THeLealDistaby/Cux>存储中重用同一个实例。要么因为没有作用域而失败,要么因为存在不同的作用域而注入另一个DbContext实例。 如果您不这样做,那么像命名范围或调用范围这样的范围可以为您工作

我们正在做以下工作:

当请求DbContext时,我们检查
ThreadLocal
()是否已经有了。如果有,我们就用那个。否则,我们将创建一个新的线程并将其分配给
ThreadLocal.Value
。 完成所有操作后,我们释放DbContext并重置
ThreadLocal.Value

有关示例,请参见此(简化的,不完美的)代码:

public interface IUnitOfWork
{
    IUnitOfWorkScope Start();
}

internal class UnitOfWork : IUnitOfWork
{
    public static readonly ThreadLocal<IUnitOfWorkScope> LocalUnitOfWork = new ThreadLocal<IUnitOfWorkScope>();

    private readonly IResolutionRoot resolutionRoot;

    public UnitOfWork(IResolutionRoot resolutionRoot)
    {
        this.resolutionRoot = resolutionRoot;
    }

    public IUnitOfWorkScope Start()
    {
        if (LocalUnitOfWork.Value == null)
        {
            LocalUnitOfWork.Value = this.resolutionRoot.Get<IUnitOfWorkScope>();
        }

        return LocalUnitOfWork.Value;
    }
}

public interface IUnitOfWorkScope : IDisposable
{
    Guid Id { get; }
}

public class UnitOfWorkScope : IUnitOfWorkScope
{
    public UnitOfWorkScope()
    {
        this.Id = Guid.NewGuid();
    }

    public Guid Id { get; private set; }

    public void Dispose()
    {
        UnitOfWork.LocalUnitOfWork.Value = null;
    }
}

public class UnitOfWorkIntegrationTest : IDisposable
{
    private readonly IKernel kernel;

    public UnitOfWorkIntegrationTest()
    {
        this.kernel = new StandardKernel();
        this.kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
        this.kernel.Bind<IUnitOfWorkScope>().To<UnitOfWorkScope>();
    }

    [Fact]
    public void MustCreateNewScopeWhenOldOneWasDisposed()
    {
        Guid scopeId1;
        using (IUnitOfWorkScope scope = this.kernel.Get<IUnitOfWork>().Start())
        {
            scopeId1 = scope.Id;
        }

        Guid scopeId2;
        using (IUnitOfWorkScope scope = this.kernel.Get<IUnitOfWork>().Start())
        {
            scopeId2 = scope.Id;
        }

        scopeId1.Should().NotBe(scopeId2);
    }

    [Fact]
    public void NestedScope_MustReuseSameScope()
    {
        Guid scopeId1;
        Guid scopeId2;
        using (IUnitOfWorkScope scope1 = this.kernel.Get<IUnitOfWork>().Start())
        {
            scopeId1 = scope1.Id;
            using (IUnitOfWorkScope scope2 = this.kernel.Get<IUnitOfWork>().Start())
            {
                scopeId2 = scope2.Id;
            }
        }

        scopeId1.Should().Be(scopeId2);
    }

    [Fact]
    public void MultipleThreads_MustCreateNewScopePerThread()
    {
        var unitOfWork = this.kernel.Get<IUnitOfWork>();
        Guid scopeId1;
        Guid scopeId2 = Guid.Empty;
        using (IUnitOfWorkScope scope1 = unitOfWork.Start())
        {
            scopeId1 = scope1.Id;
            Task otherThread = Task.Factory.StartNew(() =>
                {
                    using (IUnitOfWorkScope scope2 = unitOfWork.Start())
                    {
                        scopeId2 = scope2.Id;
                    }
                },
                TaskCreationOptions.LongRunning);
            if (!otherThread.Wait(TimeSpan.FromSeconds(5)))
            {
                throw new TimeoutException();
            }
        }

        scopeId2.Should().NotBeEmpty();
        scopeId1.Should().NotBe(scopeId2);
    }

    public void Dispose()
    {
        this.kernel.Dispose();
    }
}
公共接口IUnitOfWork
{
IUnitOfWorkScope开始();
}
内部类UnitOfWork:IUnitOfWork
{
public static readonly ThreadLocal LocalUnitOfWork=new ThreadLocal();
私有只读IResolutionRoot resolutionRoot;
公共工作单元(IResolutionRoot resolutionRoot)
{
this.resolutionRoot=resolutionRoot;
}
公共IUnitOfWorkScope启动()
{
if(LocalUnitOfWork.Value==null)
{
LocalUnitOfWork.Value=this.resolutionRoot.Get();
}
返回LocalUnitOfWork.Value;
}
}
公共接口IUnitOfWorkScope:IDisposable
{
Guid Id{get;}
}
公共类UnitOfWorkScope:IUnitOfWorkScope
{
公共单位工作范围()
{
this.Id=Guid.NewGuid();
}
公共Guid Id{get;private set;}
公共空间处置()
{
UnitOfWork.LocalUnitOfWork.Value=null;
}
}
公共类UnitOfWorkIntegrationTest:IDisposable
{
私有只读IKernel内核;
公共UnitOfWorkIntegrationTest()
{
this.kernel=新的标准内核();
this.kernel.Bind().To();
this.kernel.Bind().To();
}
[事实]
public void必须在未发布时创建新闻范围()
{
Guid范围ID1;
使用(IUnitOfWorkScope scope=this.kernel.Get().Start())
{
scopeId1=scope.Id;
}
Guid范围ID2;
使用(IUnitOfWorkScope scope=this.kernel.Get().Start())
{
scopeId2=scope.Id;
}
scopeId1.Should().NotBe(scopeId2);
}
[事实]
public void NestedScope_MustReuseSameScope()
{
Guid范围ID1;
Guid范围ID2;
使用(IUnitOfWorkScope scope1=this.kernel.Get().Start())
{
scopeId1=scope1.Id;
使用(IUnitOfWorkScope scope2=this.kernel.Get().Start())
{
scopeId2=scope2.Id;
}
}
scopeId1.Should().Be(scopeId2);
}
[事实]
public void MultipleThreads\u MustCreateNewScopePerThread()
{
var unitOfWork=this.kernel.Get();
Guid范围ID1;
Guid scopeId2=Guid.Empty;
使用(IUnitOfWorkScope scope1=unitOfWork.Start())
{
scopeId1=scope1.Id;
Task otherThread=Task.Factory.StartNew(()=>
{
使用(IUnitOfWorkScope scope2=unitOfWork.Start())
{
scopeId2=scope2.Id;
}
},
TaskCreationOptions.LongRunning);
如果(!otherThread.Wait(TimeSpan.FromSeconds(5)))
{
抛出新的TimeoutException();
}
}
scopeId2.Should().NotBeEmpty();
scopeId1.Should().NotBe(scopeId2);
}
公共空间处置()
{
this.kernel.Dispose();
}
}
注意:我使用的是nuget包:ninject、xUnit.Net和Fluent断言


还请注意,您可以替换IUnitOfWork。从
ToProvider()
绑定开始。当然,您需要在提供程序中实现相应的逻辑。

中实现的适当工作范围单元解决了此问题

设置:

_kernel.Bind<IService>().To<Service>().InUnitOfWorkScope();
using(UnitOfWorkScope.Create()){
    // resolves, async/await, manual TPL ops, etc    
}