我有一个使用多个数据库分片的API应用程序,使用StructureMap进行依赖注入。每个API调用中所需的标题之一是ShardKey
,它告诉我此调用正在寻址哪个数据库。为了实现这一点,我有一个OwinMiddleware
类称为ShardingMiddleware
,其中包含下面的代码(剪断为清楚起见):StructureMap中的跨线程冲突
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中触发,事情开始变成梨形。 Ferinstance:
System.ObjectDisposedException:无法访问处置的对象。造成这种错误的一个常见原因是处理从依赖注入解决的上下文,然后尝试在应用程序的其他地方使用相同的上下文实例。这可能发生在你正在上下文中调用Dispose()或将上下文包装在using语句中。如果您正在使用依赖注入,则应该让依赖注入容器负责处理上下文实例。
或其他异常指示StructureMap没有可用的MyDbContext
的有效实例。
对我来说,似乎多线程在某种程度上搞乱了彼此的配置,但对于我的生活我无法理解,因为我使用嵌套容器来存储每个API的数据库上下文呼叫。
任何想法可能会在这里出错?
更新:我也尝试将我的Db上下文抽象为接口。没有真正的区别;我仍然收到错误
System.InvalidOperationException:尝试创建类型为'SomeController'的控制器时发生错误。确保控制器有一个无参数的公共构造函数。 ---> StructureMap.StructureMapConfigurationException:没有默认实例被注册,并且不能为类型“MyNamespace.IMyDbContext”
更新2自动确定:我解决了这个问题,但奖金仍然是开放的。请参阅下面的答案。
您的'DbContext'可能会作为[Captive Dependency]保留下来(http://blog.ploeh.dk/2014/06/02/captive-dependency/)。确保此依赖项的使用者的生命周期的寿命不超过'DbContext'的寿命,或者 - 甚至更好 - 防止将DbContext直接注入到消费者中。 'DbContext'是运行时数据,运行时数据[不应该注入到组件中](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99)。而是在抽象背后隐藏DbContext。 – Steven