gpt4 book ai didi

c# - StructureMap 中的跨线程冲突

转载 作者:太空狗 更新时间:2023-10-29 21:43:32 24 4
gpt4 key购买 nike

我有一个 API 应用程序,它使用多个数据库分片,并使用 StructureMap 进行依赖注入(inject)。每个 API 调用中的必需 header 之一是 ShardKey,它告诉我此调用针对的是哪个数据库。为实现这一点,我有一个名为 ShardingMiddlewareOwinMiddleware 类,其中包含以下代码(为清楚起见已截取):

var nestedContainer = container.GetNestedContainer();
using (var db = MyDbContext.ForShard(shardKey)) // creates a new MyDbContext with connection string appropriate to shardKey
{
nestedContainer.Configure(cfg => cfg.For<MyDbContext>().Use(db));
await Next.Invoke(context);
}

这在我的测试环境中运行良好,并通过了一系列集成测试。

但是集成测试实际上是单线程的。当我将它部署到 QA 环境中时,一个真正的应用程序正在通过多个同时调用攻击我的 API,事情开始变得糟糕。实例:

System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur is you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

或其他异常表明 StructureMap 没有可用的 MyDbContext 的有效实例。

在我看来,多个线程似乎以某种方式弄乱了彼此的配置,但对于我的生活我无法理解,因为我正在使用嵌套容器来存储每个 API 调用的数据库上下文.

知道这里可能出了什么问题吗?

更新:我还尝试将我的 Db 上下文抽象到一个接口(interface)中。没有真正的区别;我仍然收到错误

System.InvalidOperationException: An error occurred when trying to create a controller of type 'SomeController'. Make sure that the controller has a parameterless public constructor. ---> StructureMap.StructureMapConfigurationException: No default Instance is registered and cannot be automatically determined for type 'MyNamespace.IMyDbContext'

更新 2: 我解决了问题,但赏金仍然开放。请在下面查看我的回答。

最佳答案

好吧...我解决了这个问题,但我不明白为什么这会产生影响。

它归结为与我最初发布的内容有一些细微的差异,我忽略了这些差异,因为我认为细节无关紧要并且会分散对问题的注意力。事实上,我的容器并不是在本地定义的;相反,它是我的中间件的 protected 属性(它是出于集成测试目的而继承的):

protected IContainer Container { get; private set; }

然后在Invoke()方法内部有一个初始化调用:

Container = context.GetNestedContainer(); // gets the nested container created by a previous middleware class, using the context.Environment dictionary

在整个方法中使用日志记录语句,我得到了以下代码(如问题中所述,添加了日志记录):

_logger.Debug($"Line 1 Context={context.GetHashCode}, Container={Container.GetHashCode()}");
var db = MyDbContext.ForShard(shardKey.Value); // no need for "using", since DI will automatically dispose
_logger.Debug($"Line 2 Context={context.GetHashCode}, Container={Container.GetHashCode()}");
Container.Configure(cfg => cfg.For<MyDbContext>().Use(db));
await Next.Invoke(context);

令人惊讶的是,这是从日志中得出的结果:

Line 1 Context=56852305, Container=48376271

Line 1 Context=88275661, Container=85736099

Line 2 Context=56852305, Container=85736099

Line 2 Context=88275661, Container=85736099

太棒了!我的中间件的 Container 属性神奇地被替换了!这个,尽管它是用 private set 定义的,无论如何,为了安全起见,我检查了 MyDbContext.ForShard() 的代码并没有发现任何东西这可能会弄乱 Container 的引用。

那么解决方案是什么?我在初始化后立即声明了一个本地 container 变量,并使用了它。

它现在有效,但我不明白为什么或如何产生不同。

赏金将颁发给能够解释这一点的人。

关于c# - StructureMap 中的跨线程冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38775306/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com