我们正在使用StructureMap,容器的默认生命周期是每次要求该类型时创建一个新对象。最近,我们开始研究为Web应用程序中的每个HTTP请求创建嵌套容器。它很好用,除了嵌套容器的生命周期与常规容器完全不同,因为所有对象都成为嵌套容器内的单例。
由于我们在创建大部分对象时都使用了StructureMap,因此我们的代码以嵌套容器的生命周期以神秘的方式中断。有人可能会说这是我们的错误,我猜这是正确的,因为即使我们真的希望创建一个新实例,我们也会调用GetInstance()
。但我找不到任何方法可以绕过StructureMap中的生命周期管理并强制创建(类似于CreateInstance()
而不是GetInstance()
)。我们可以开始实现我们自己的CreateInstance()
方法,但这种感觉就像重新发明StructureMap一样。我们也可以更改我们的工厂以显式创建对象,但是当我们需要通常获取实例时,这并不真正起作用(container.GetInstance<IMyType>()
)。
因此,强制StructureMap创建对象,或如何更改嵌套容器中的生命周期,或者如何将工厂代码更改为更明确地创建实例的任何建议都会很棒。
答案 0 :(得分:1)
我们处于类似的情况,在你的问题下谈论你的评论的这一部分:
...我们的网络应用程序有一个网站/实例,具体取决于 你是谁,我们连接到你所属的数据库。所以我们想要 每个请求一个隔离的容器,以避免状态流血 不同的系统(用户A从用户B的系统获取对象)......
我正在搜索相同的功能,这应该是多线程安全的。然后我找到了这个链接: StructureMap: Multithreaded env. No default instance defined for PluginFamily
结果可以用这种方式描述:
1)要求:您的解决方案中有一个抽象。而不是StructureMap.ObjectFactory.GetInstance
...所有部分都应该调用你的
Factory.GetInstance(type)
(及其提供商,将调用 StructureMap (SM)或更高版本的任何其他 IoC 提供商)
2)如果是这种情况(或者您可以为Factory
引入例如管理模式,并让所有代码在 SM 上进行),我们可以创建两个(或更多)容器。
首先是默认值
public class DefaultProfileRegistry : Registry
{
public DefaultProfileRegistry()
{
// whatever calls needed to initialize this registry
SetScans(this); // scan
SetSetterInjection(this); // DI
Profile("DefaultProfile", SetDefaults); // even some common defaults
}
现在让我们创建一个不同的Registry
public class SpecialProfileRegistry : Registry
{
public SpecialProfileRegistry()
{
DefaultProfileRegistry.SetScans(this); // use part from default
...
Profile("Special", DefaultProfileRegistry.SetDefaults); // common defaults
}
嗯,我们有什么:两个Registry
。一个是默认,第二个是特殊可以从中获利并调整一部分,或完全不同......
3)在IFactoryProvider
实施者中注册它们,例如StructureMapFactoryProvider
(SMFP):
public partial class StructureMapFactoryProvider : IFactoryProvider
{
private static readonly IContainer Special;
static StructureMapFactoryProvider()
{
// 1) the default registry container
ObjectFactory.Initialize(x =>
{
x.UseDefaultStructureMapConfigFile = false;
// Defaults
x.IncludeRegistry<DefaultProfileRegistry>();
});
ObjectFactory.Container.SetDefaultsToProfile("DefaultProfile");
// 2) and now register the other(s)
Special = new StructureMap.Container(new SpecialProfileRegistry());
Special.SetDefaultsToProfile("Special");
}
好吧,现在,当我们首次触摸我们的SMFP时,所有容器都会被实例化......
4)最后在IFactoryProvider.GetInstance()
内,我们可以决定使用什么
object IFactoryProvider.GetInstance(Type type)
{
var useSpecial = ... // get the information to decide
if (useDefault)
{
return Special.GetInstance(type);
}
else
{
return ObjectFactory.GetInstance(type);
}
5)useSpecial
必须在这个地方以某种方式提供。 IFactoryProvider.GetInstance()
上的不得依赖。如果在完整请求处理期间此值为 const ,则正确的IContainer
将提供正确的对象。
6)这些IContainer
中的每一个都可以有不同的约定,不同的 LiefCycle 设置......即使在情况下,也有数千{{1}注册后,这个解决方案提供了非常好的性能,并且是多线程安全的(例如没有Profile切换)
答案 1 :(得分:0)
我们也可以改变我们的工厂来明确地创建对象,但是当我们需要一般地获取一个实例(
container.GetInstance<IMyType>()
)时,这并不能真正起作用。
这实际上是可行的,假设您需要的地方数量有限:
For<IMyType>().Use(s => new MyType());
这些当然也可能是潜在设计问题的症状,例如需要定义租户特定的背景,所以请花一些时间仔细重新考虑您的设计。