7

Ninject v2.2.1.4 を使用した ASP.NET MVC 3 アプリケーションがあります。すべてがうまく機能していましたが、突然、Ninject がパラメーターなしのコンストラクターに対してパラメーターを持つコンストラクターを使用して DbContext を作成しようとしているのが見え始めました。バインディングは次のとおりです。

kernel.Bind<MyContext>().ToSelf().InRequestScope();

kernel.Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<MyContext>());
kernel.Bind<DbContext>().ToMethod(ctx => ctx.Kernel.Get<MyContext>());

MyContext は、IUnitOfWork インターフェイスも実装する DbContext オブジェクトです。このように設定したので、1 つのリクエストで使用される複数のリポジトリに同じコンテキストが挿入されます。MyContext コンストラクターは次のようになります。

public MyContext() { }
public MyContext(string connectionString) { }
public MyContext (long accountID) { }
public MyContext (Connection connection) { }

すべて同じ MyContext クラスを使用するため、アプリケーションごとに異なるコンストラクターがあります。バインディングを見ると、MyContext クラスが要求されたときにパラメーターなしのコンストラクターが呼び出されると思いますが、何らかの理由でそうではありません。accountID が指定されていなくても、長い accountID パラメータを持つものが呼び出されます。これは明らかにスローされ、「一致するバインディングが利用できず、タイプは自己バインド可能ではありません」という例外ステートメントがスローされます。実際には、IUnitOfWork を生成しようとすると例外がスローされます。

最後の 3 つのコンストラクターをコメント アウトすると、すべて正常に機能し、パラメーターなしのコンストラクターが使用されます。パラメーター化されたコンストラクターのいずれか 2 つをコメントアウトすると、パラメーターなしのコンストラクターではなく、もう一方を使用しようとします。

Ninject が提供する提案は次のとおりです。

Suggestions:
  1) Ensure that you have defined a binding for long.
  2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
  3) Ensure you have not accidentally created more than one kernel.
  4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
  5) If you are using automatic module loading, ensure the search path and filters are correct.

したくないので、1には何もありません。2と5の意味がわかりません。私は、私たちが 3 を実行したとは思いませんし、4 も実行していません。

このシナリオでパラメーターなしのコンストラクターを使用しない理由についての考え。

4

2 に答える 2

5

@Xanderの答えは一般的に正しいですが、NinjectにはV3で非常に具体的なソリューションがいくつかあります。Ninject は、この wiki 記事[実際には 3.0 のバッジが付けられた V2.4 用であると主張している] に 記載されているように、解決方法を知っているパラメーターが最も多いものを見つける特定のアルゴリズムによってコンストラクターにスコアを付けます。コードを参照してください。これもウィキにあると思います。そうでない場合は、誰かがそこに置く必要があります。

あなたが見た動作の変化について言えば、潜在的な自己バインディングがゴールポストを変更している (解決中に新しい登録が追加されている) か、他のコンストラクターの 1 つをより魅力的にするバインディングを追加した可能性があります。

[Inject]属性は、あなたが求めている他のすべての基準よりも優先されます (ただし、実際にはコードにコンテナー固有の属性を含める必要はありません)。

提案されたWithConstructorArgument手法は、実際に使用することによってToConstructor影響を受けます.WCAを実行しても選択には影響しません(冗長な仕様について苦情を受けることはないと思います.

肝心なのは、この関連する質問に対する @Mark Seemann のコメントで示唆されているように、これほど大きな混乱に陥ってはならないということです。


悲しいことに、上記はすべて嘘です。v2.2から移行すると、この答えは正しくなります。できない、またはできない場合は、同等のソースとテストを見て、その前のルールを見つける必要があります (メモリから (および私の調査で検索結果に表示されたいくつかの Google コードから)、それはに基づいていました)。コンストラクターはカウントされますが、等しいスコアがどのように明確化されるかはわかりません。

2.2 では、 an を追加するの[Inject]が手っ取り早い方法です。

于 2012-10-02T00:37:53.037 に答える
4

デフォルトでは、Ninject は他の同様の IoC フレームワークとともに、最も多くのパラメーターを持つコンストラクターを選択します。WithConstructorArgument拡張メソッドによる初期化中に使用するコンストラクターを指定します。

kernel.Bind<DbContext>()
      .WithConstructorArgument("connectionString",
             ConfigurationManager.ConnectionStrings["connection"]
                  .ConnectionString)
      .ToMethod(ctx => ctx.Kernel.Get<MyContext>());

Ninject にデフォルトのコンストラクター[Inject]を強制的に使用させるには、コンストラクターに属性を配置します。

[Inject]
public MyContext() { }
于 2012-10-01T23:19:25.683 に答える