1

StructureMap を使用しており、コンテナのデフォルトのライフサイクルは、そのタイプが要求されるたびに新しいオブジェクトを作成することです。最近、Web アプリケーションの各 HTTP リクエストに対してネストされたコンテナを作成する調査を開始しました。ネストされたコンテナのライフサイクルは、ネストされたコンテナ内ですべてのオブジェクトがシングルトンになるという点で、通常のコンテナとはまったく異なります。

ほとんどのオブジェクト作成に StructureMap を使用しているため、入れ子になったコンテナのライフサイクルでコードが不可解な方法で壊れます。これは私たちの側のエラーであると主張する人もいるかもしれませんが、それは正しいと思います。なぜならGetInstance()、新しいインスタンスが作成されることを本当に期待している場合でも呼び出すからです。しかし、StructureMap のライフサイクル管理をバイパスして作成を強制する方法が見つかりません ( のCreateInstance()代わりにa のようなものGetInstance())。独自のメソッドを実装することもできますCreateInstance()が、それは StructureMap を再発明するようなものです。ファクトリを変更してオブジェクトを明示的に作成することもできますが、一般的にインスタンスを取得する必要がある場合は実際には機能しません ( container.GetInstance<IMyType>())。

したがって、StructureMap に強制的にオブジェクトを作成させる方法、ネストされたコンテナーでライフサイクルを変更する方法、またはファクトリ コードをより明示的にインスタンスを作成するように変更する方法についてのアドバイスは素晴らしいものです。

4

2 に答える 2

1

私たちは同様の状況にあり、あなたの質問の下であなたのコメントのこの部分について話しました:

...Web アプリケーションの 1 つの Web サイト/インスタンスがあり、あなたが誰であるかに応じて、あなたが所属するデータベースに接続します。したがって、状態が異なるシステムに流れ込むのを避けるために、要求ごとに分離されたコンテナーが必要です (ユーザー A はユーザー B のシステムからオブジェクトを取得します)...

マルチスレッドセーフである必要がある同じ機能を探していました。次に、このリンクを見つけました: StructureMap: Multithreaded env. PluginFamily のデフォルト インスタンスが定義されていません

結果は次のように説明できます。

1) 要件: ソリューションには抽象化があります。StructureMap.ObjectFactory.GetInstance... の代わりに、すべての部分があなたを呼び出す必要があります

Factory.GetInstance(type)

(およびそのプロバイダー。StructureMap (SM) または後で他のIoCプロバイダーを呼び出します)

2) この場合 (または、たとえば Manager パターンを導入してFactory、すべてのコードをSMにインデントさせることができる場合)、2 つ (またはそれ以上) のコンテナーを作成できます。

まずデフォルトのもの

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
   }

さて、私たちが持っているもの: Two Registry. 1つはデフォルトで、2つ目は特別で、それから利益を得て一部を調整するか、まったく異なるものにすることができます...

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) これらのそれぞれは、異なるConventions、異なるLiefCycleIContainer設定を持つことができます...数千の が登録されている場合でも、このソリューションは非常に優れたパフォーマンスを提供し、マルチスレッドセーフです (たとえば、プロファイルの切り替えはありません)。PluginType

于 2013-02-15T09:26:17.433 に答える
0

ファクトリを変更してオブジェクトを明示的に作成することもできますが、一般的にインスタンスを取得する必要がある場合は実際には機能しません ( container.GetInstance<IMyType>())。

必要な場所が限られている場合、これは実際に実行可能です。

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

もちろん、これらは、テナント固有のコンテキストを定義する必要があるなど、根本的な設計上の問題の症状である可能性もあります。そのため、設計を慎重に再検討してください。

于 2013-02-11T09:18:03.010 に答える