强制在StructureMap中创建对象

本文关键字:创建对象 StructureMap | 更新日期: 2023-09-27 17:58:48

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

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

因此,任何关于强制StructureMap创建对象,或者如何更改嵌套容器中的生命周期,或者如何将我们的工厂代码更改为更明确地创建实例的建议都是非常好的。

强制在StructureMap中创建对象

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

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

我正在搜索相同的功能,它应该是多线程安全的。然后我找到了这个链接:StructureMap:多线程环境。没有为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()。如果在整个请求处理过程中此值是常量,则正确的IContainer将为正确的对象提供服务。

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

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

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

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

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