私は非常によく似たプロジェクトを持っており(Caliburnを使用していないことを除いて)、これを行う方法も理解しようとしています。Ninject の InScope() メソッドを使用して、コンストラクター インジェクションに適した方法を 1 つ思いつきました。
Ninject のカーネルへのアクセスをラップする IoC という静的クラスがあります。依存関係はすべてコンストラクターに注入されるため、コンテキストはオブジェクトの作成時にのみ関連します。したがって、コンテキストに何が提供されるかは問題ではありませんが、Guid は安全な選択のように感じます。Program.OpenSession() は、新しい ISession を開くための静的メソッドです。
public static class Ioc
{
private static readonly IKernel _kernel;
static IoC()
{
_kernel = new StandardKernel();
_kernel.Load(new ContextModule());
}
private static object _context;
public static T ResolveInContext<T>(object context)
{
_context = context;
var result = _kernel.Get<T>();
_context = null;
return result;
}
private class ContextModule : NinjectModule
{
public override void Load()
{
Bind<ISession>().ToMethod(x => Program.OpenSession()).InScope(x => _context);
Bind<frmCompanyViewer>().ToSelf().InScope(x => _context);
}
}
}
使用法は次のとおりです。
var frm = IoC.ResolveInContext<frmCompanyViewer>(Guid.NewGuid());
フォームのコンストラクタ シグネチャは次のとおりです。
public frmCompanyViewer(ISession session, ICompanyRepository companyRepository)
バインディングに InScope を使用すると、frmCompanyViewer の構築に使用されるものと同じ ISession が companyRepository の構築にも使用されることを確認しました。InScope を削除すると、2 つの ISession が使用されます。
追加するために編集:これも機能します。コメントを参照してください。これは、実際のアプリケーションではスレッド セーフにする必要があります。ConstructInContext
オブジェクトの構築中にのみコンテキストが適用されることを明確にするために、メソッド名を に変更しました。
public static T ConstructInContext<T>()
{
_context = Guid.NewGuid();
var result = _kernel.Get<T>();
_context = null;
return result;
}