【问题标题】:Force the creation of an object in StructureMap强制在 StructureMap 中创建对象
【发布时间】:2013-02-11 07:41:01
【问题描述】:

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

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

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

【问题讨论】:

  • 我想您知道 Hybrid 或 HttpContext 范围。您想通过每个 HTTP 请求使用嵌套容器来实现什么目标?
  • 我们有一个 Web 应用程序的网站/实例,根据您的身份,我们会连接到您所属的数据库。因此,我们希望每个请求都有一个隔离的容器,以避免状态溢出到不同的系统中(用户 A 从用户 B 的系统中获取对象)。我们尝试为每个请求创建和初始化一个新容器,但这会使每个请求减慢大约一秒钟。

标签: c# structuremap


【解决方案1】:

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

...我们有一个 Web 应用程序的网站/实例,并且取决于 你是谁,我们连接到你所属的数据库。所以我们想要 每个请求一个隔离的容器,以避免状态溢出 不同的系统(用户 A 从用户 B 的系统中获取对象)...

我正在寻找相同的功能,它应该是多线程安全的。然后我找到了这个链接: StructureMap: Multithreaded env. No default instance defined for PluginFamily

结果可以这样描述:

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

Factory.GetInstance(type)

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

2) 如果是这种情况(或者您可以为您的Factory 引入例如 Manager 模式,并让您的所有代码缩进 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 设置...即使在某些情况下,也有成千上万的PluginTypes 注册,这个解决方案提供了非常好的性能并且是多线程安全的(例如没有配置文件切换)

【讨论】:

    【解决方案2】:

    我们还可以更改工厂以显式创建对象,但是当我们需要通用获取实例时,这实际上不起作用 (container.GetInstance&lt;IMyType&gt;())。

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

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

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

    【讨论】:

    • 这意味着我们必须为每种类型指定它,这是我们想要避免的。在很多地方,我们可以将:return container.GetInstance&lt;MyType&gt;() 替换为 return new MyType(container.GetInstance&lt;MyTypeDependency&gt;());,我认为这是解决简单情况的正确方法。
    • @Anders 哦,好吧,所以您有多种可能共享租户特定状态的类型。在这种情况下,除了等待"Child" Containers 实施之外,恐怕我无法为您的问题想出任何“罐头”解决方案。
    猜你喜欢
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 2013-10-31
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多