9

問題(要約)

依存関係Xを登録するモジュールがあるとします。依存関係Xの有効期間は、MVC3アプリ(HttpRequestごとの有効期間)とコンソールアプリケーション(名前付きの有効期間スコープごとの依存関係)で異なります。依存関係Xの存続期間をどこで、またはどのように指定しますか?

場合

すべてのリポジトリを登録するモジュールを含むアセンブリに、データベース関連のすべてのコードを配置しました。これで、ISession(Nhibernate)登録もモジュールに含まれます。

ISessionは依存関係Xです(特定の問題の場合)。ISessionのライフタイムは、MVC3アプリ(リクエストごとのライフタイム)と、名前付きライフタイムスコープを定義するコンソールアプリで異なります。

ISessionの登録はモジュールの外部にあるべきですか?実装の詳細なのでおかしいでしょう。

ここで行う最良のケースは何ですか?設計上の欠陥またはこれのためのスマートな構造がありますか:)?

4

2 に答える 2

7

ユースケースの説明を考えると、いくつかのオプションがあると思います。

まず、ライフタイムスコープを含む独自の依存関係のセットを各アプリケーションに登録させることができます。この点で1つまたは2つの「重複した」コードがあることは、アプリケーションと登録がかなり小さいように見えるという事実との違いを考えると、それほど大きな問題ではありません。

次に、共通部分(ライフタイムスコープを除く)を、各アプリケーションで使用できるContainerBuilder拡張メソッドにラップできます。それでも、各アプリには少し「重複したコード」があることを意味しますが、共通ロジックは単純な拡張機能でラップされます。

public static IRegistrationBuilder<TLimit, ScanningActivatorData, DynamicRegistrationStyle>
  RegisterConnection<TLimit, ScanningActivatorData, DynamicRegistrationStyle>(this ContainerBuilder builder)
{
  // Put the common logic here:
  builder.Register(...).AsImplementedInterfaces();
}

各アプリでこのような拡張機能を使用すると、次のようになります。

builder.RegisterConnection().InstancePerHttpRequest();
// or
builder.RegisterConnection().InstancePerLifetimeScope();

最後に、Webまたは非Webのいずれかであることがわかっている場合は、スイッチを処理するカスタムモジュールを作成できます

public class ConnectionModule : Autofac.Module
{
  bool _isWeb;
  public ConnectionModule(bool isWeb)
  {
    this._isWeb = isWeb;
  }

  protected override void Load(ContainerBuilder builder)
  {
    var reg = builder.Register(...).AsImplementedInterfaces();
    if(this._isWeb)
    {
      reg.InstancePerHttpRequest();
    }
    else
    {
      reg.InstancePerLifetimeScope();
    }
  }
}

次に、各アプリケーションで、モジュールを登録できます。

// Web application:
builder.RegisterModule(new ConnectionModule(true));

// Non-web application:
builder.RegisterModule(new ConnectionModule(false));

または、他のアプリのライフタイムスコープに名前があるとおっしゃいました。モジュールに名前を付けることができます

public class ConnectionModule : Autofac.Module
{
  object _scopeTag;
  public ConnectionModule(object scopeTag)
  {
    this._scopeTag = scopeTag;
  }

  protected override void Load(ContainerBuilder builder)
  {
    var reg = builder.Register(...)
                     .AsImplementedInterfaces()
                     .InstancePerMatchingLifetimeScope(this._scopeTag);
  }
}

消費量は似ています:

// Web application (using the standard tag normally provided):
builder.RegisterModule(new ConnectionModule("httpRequest"));

// Non-web application (using your custom scope name):
builder.RegisterModule(new ConnectionModule("yourOtherScopeName"));

InstancePerLifetimeScope実際に意図したものでない限り、単にWebアプリケーションで使用することはお勧めしません。他の回答/コメントに記載されてInstancePerHttpRequestいるように、子のライフタイムスコープを安全に作成できるように、特定の名前付きライフタイムスコープを使用します。usingInstancePerLifetimeScopeにはそのような制限がないため、リクエストに対して1つの接続ではなく、子スコープごとに1つの接続を実際に取得します。私は個人的に、他の開発者が子のライフタイムスコープを使用しないとは思いません(これは推奨される方法です)。そのため、私のアプリケーションでは非常に具体的です。アプリケーションを完全に制御していて、追加の子スコープを作成していないこと、またはスコープごとに1つの接続が実際に必要であることを確認できる場合は、InstancePerLifetimeScopeあなたの問題を解決します。

于 2012-06-05T16:53:25.613 に答える
0

httpリクエストごとに1つの接続を使用するのが一般的な方法です。その場合、接続は.InstansePerLifetimeScope()を使用して登録されます。たとえば、次のようなことを行うことができます。

builder
    .Register(c => {
                       var conn = new SqlConnection(GetConnectionString());
                       conn.Open();
                       return conn;
                   })
    .AsImplementedInterfaces()
    .InstancePerLifetimeScope();
于 2012-06-02T19:40:22.803 に答える