强制在StructureMap中创建对象

时间:2013-02-11 07:41:02

标签: c# structuremap

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

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

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

2 个答案:

答案 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());

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