1

我们使用的是 StructureMap,容器的默认生命周期是在每次请求该类型时创建一个新对象。最近,我们开始研究为 Web 应用程序中的每个 HTTP 请求创建一个嵌套容器。它工作得很好,除了嵌套容器的生命周期与常规容器完全不同,因为所有对象在嵌套容器内都变成了单例。

由于我们在大部分对象创建中都使用 StructureMap,因此我们的代码在嵌套容器的生命周期中以神秘的方式中断。有人可能会争辩说这是我们的错误,我想这是正确的,因为GetInstance()即使我们真的希望创建一个新实例,我们也会调用。但是我找不到任何方法让我们绕过 StructureMap 中的生命周期管理并强制创建(类似于 aCreateInstance()而不是GetInstance())。我们可以着手实现我们自己的CreateInstance()方法,但那种感觉就像是在重新发明 StructureMap。我们也可以改变我们的工厂来显式地创建对象,但是当我们需要通用地获取一个实例时这并不真正起作用(container.GetInstance<IMyType>())。

因此,任何关于强制 StructureMap 创建对象,或如何更改嵌套容器中的生命周期,或如何更改我们的工厂代码以更明确地创建实例的建议都会很棒。

4

2 回答 2

1

我们处于类似情况,在您的问题下谈论您评论的这一部分:

...我们有一个 Web 应用程序的网站/实例,根据您的身份,我们会连接到您所属的数据库。所以我们希望每个请求都有一个隔离的容器,以避免状态溢出到不同的系统(用户 A 从用户 B 的系统中获取一个对象)......

我正在寻找相同的功能,它应该是多线程安全的。然后我找到了这个链接: StructureMap:多线程环境。没有为 PluginFamily 定义默认实例

结果可以这样描述:

1)要求:您的解决方案中有一个抽象。而不是StructureMap.ObjectFactory.GetInstance......所有部分都应该调用你的

Factory.GetInstance(type)

(及其提供者,将调用StructureMap (SM) 或以后的任何其他IoC提供者)

2) 如果是这种情况(或者您可以为您的 引入例如 Manager 模式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(). 如果在整个请求处理过程中此值是constIContainer ,则正确的将提供正确的对象。

6)每一个都IContainer可以有不同的Conventions,不同的LiefCycle设置......即使在PluginType注册了数千个 s 的情况下,这个解决方案也提供了非常好的性能并且是多线程安全的(例如,没有配置文件切换)

于 2013-02-15T09:26:17.433 回答
0

我们也可以改变我们的工厂来显式地创建对象,但是当我们需要通用地获取一个实例时这并不真正起作用(container.GetInstance<IMyType>())。

假设您需要的地方数量有限,这实际上是可行的:

For<IMyType>().Use(s => new MyType());

当然,这些也可能是潜在设计问题的症状,例如需要定义租户特定的上下文,因此请花一些时间仔细重新考虑您的设计。

于 2013-02-11T09:18:03.010 回答