4

これが私の問題です。次のツールを使用してデスクトップアプリケーションを構築しています。

  • カリバーン
  • 注入する
  • NHibernate

私のすべてのビューモデルとリポジトリはNinjectでインスタンス化されています。私のリポジトリはすべて、コンストラクターにISessionが必要です。

ViewModelsに関するayendeのアドバイスに従いたいと思います。各ViewModelは新しいセッションを開きます。

ViewModelの作成時に新しいセッションを開き、このビューモデルで使用されるリポジトリ内でこのセッションを使用するようにNinjectを構成することは可能ですか?

NinjectのInScope関数とNHibernateのICurrentSessionContextインターフェイスを調べましたが、それらすべてをモデル化して必要なものを取得する方法がわかりません...

誰かが以前にそのようなものを作ったことがありますか?

前もって感謝します

マイク

4

5 に答える 5

0

さて、ninject グループのおかげで解決策を見つけました。

ここでの解決策は、ISession をバインドするときに関数 InScope を使用し、IContext 変数を参照してサービスを検査することです。リクエスト階層内の 1 つのサービスがビュー モデルの基本クラスに割り当て可能な場合、コンテキストをスコープとして使用します。

そのため、ViewModel のコンストラクターに ISession が初めて挿入されるときに、新しいスコープが使用されます。そして、ViewModel のコンストラクター内の ISession への後続のすべての呼び出しは、同じスコープで解決されます。そして、ViewModel に対して作成されるセッションは 1 つだけです。

コードは次のとおりです。

Bind<ISession>().ToMethod(ctx =>
    {
        var session = ctx.Kernel.Get<INHibernateSessionFactoryBuilder>()
            .GetSessionFactory()
            .OpenSession();

        session.FlushMode = FlushMode.Commit;

        return session;
    })
    .InScope(ctx =>
    {
        var request = ctx.Request;

        if (request.Service is IScreen)
            return request;

        while ((request = request.ParentRequest) != null)
            if (typeof(IScreen).IsAssignableFrom(request.Service))
                return request;

        return new object();
    });

ビューモデルのコンストラクターには、ISession に依存するすべての注入された依存関係が含まれている必要があります。

[Inject]
public PlayersManagementViewModel(ISession session, IPlayersRepository playersRepository)
{
}

それが役立つことを願っています

于 2010-06-28T13:03:27.957 に答える
0

ViewModel ライフサイクルを利用して同様のシナリオを解決しました。リポジトリによって実装される ISessionAware インターフェイス (SetSession メソッドを使用) を作成し、ViewModel の OnInitialize メソッドで ISessionAware を介してリポジトリを初期化しました (VM がScreenConductor によって管理されます)。

リフレクションを使用してリポジトリを保持するプロパティを調べると、すべてのインフラストラクチャを BaseDataVM クラスに配置できました。

コンテナでスコープを使用するとよりエレガントになると思いますが、Ninjectはわかりません。

于 2010-06-25T12:43:18.720 に答える
0

私は非常によく似たプロジェクトを持っており(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;
    }
于 2010-06-25T13:00:57.077 に答える
0

ここにあります ;) http://groups.google.com/group/unhaddins/browse_thread/thread/29eca74a83df5faf/d9fab4062d4cb4c4?lnk=gst&q=ninject#d9fab4062d4cb4c4

于 2010-06-25T21:01:11.693 に答える
0

unhaddin の AOP でこれを実現しています。「商談ごとの取引」と呼ばれます。

グーグルで検索

于 2010-06-25T20:43:20.393 に答える