3

ViewModel ごとに NHibernate セッションを提供できるようにする、IScopeAccessor の実装を作成する、または新しいソリューションを見つけるための助けを探しています。

Windsor がスコープ付きのライフスタイルをサポートするようになったことは知っています (こちら)。ただし、この例では、using ブロックを使用して特別なスコープを作成し、using 内で container.resolve を呼び出しています。

    _container.Register(Component.For<A>().LifestyleScoped());

    using (_container.BeginScope())
    {
        var a1 = _container.Resolve<A>();
        var a2 = _container.Resolve<A>();
        Assert.AreSame(a1, a2);
    }

コンテナを渡したくないので、これを機能させる方法は考えられません。また、必要に応じて動的に発生する、作成される ViewModel にスコープを関連付けたいと考えています。

別の方法として、Krzysztof Koźmic (ここ)によると、IScopeAccessor の実装を作成できるようです。

「...好きなスコープを提供してください。スコープはここでは抽象的な用語であり、何でもかまいません。」

残念ながら、Web ベースのシナリオに固有ではない IScopeAccessor の実装を見つけることができず、「何か」を有効なスコープに変えるために何をする必要があるかを正確に理解するのに苦労しています。

Ninject (http://www.emidee.net/index.php/2010/08/23/ninject-use-one-database-session-per-view-model) を使用してやりたいことの正確な例を見つけました。 /):

Bind<ISession>().ToMethod(ctx =>
{
    var session = ctx.Kernel.Get<....>().BuildSessionFactory().OpenSession();
    return session;
})
.InScope(context =>
{ 
    var request = context.Request;

    if (typeof(IViewModel).IsAssignableFrom(request.Service))
        return request; 

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

    return new object(); 
});

Ninject では、InScope は、コールバックによって返されたオブジェクトが存続している限り、バインディングによって作成されたインスタンスを再利用する必要があることを示します。基本的に、このコールバックはルート レベルの ViewModel を返します (ViewModel はネストできるため)。

Windsor を使用して同じことを行う方法や同じ結果を得る方法について何か考えはありますか?

4

1 に答える 1

2

問題は作成場所にあるようです。構築されているビューモデルの依存関係がすべてである場合は、 What's new...で説明されているように、boud ライフスタイルを使用 できます。または、ビューモデルに敏感な独自のスコープ アクセサーを使用することもできます。たとえば、次のようにします。

public class ViewModelScopeAccessor : IScopeAccessor
{
    private IDictionary<Guid, ILifetimeScope> scopes = new Dictionary<Guid, ILifetimeScope>();
    private ILifetimeScope defaultScope;

    public ViewModelScopeAccessor()
        : this(new DefaultLifetimeScope())
    { }

    public ViewModelScopeAccessor(ILifetimeScope defaultScope)
    {
        this.defaultScope = defaultScope;
    }

    public ILifetimeScope GetScope(CreationContext context)
    {
        var creator = context.Handler.ComponentModel.Implementation;
        var viewModel = creator as IViewModel;
        if (viewModel != null)
        {
            ILifetimeScope scope;
            if (!scopes.TryGetValue(viewModel.UID, out scope))
            {
                scope = new DefaultLifetimeScope();
                scopes[viewModel.UID] = scope;
            }

            return scope;
        }
        else
        {
            return defaultScope;
        }
    }

    public void Dispose()
    {
        foreach (var scope in scopes)
        {
            scope.Value.Dispose();
        }

        defaultScope.Dispose();
        scopes.Clear();
    }
}

次のビューモデル インターフェイスの場合:

public interface IViewModel
{
    string DisplayName { get; }

    Guid UID { get; }
}

もちろん、他の方法でビューモデルを比較することもできますが、これは単なる例です。

バインドされたライフスタイルとそのスコープ アクセサーの両方の欠点は、ビューモデル内で型指定されたファクトリを使用すると、スコープ アクセサーがどのオブジェクト/メソッドからのものかわからないため、オブジェクトを遅延構築するために機能しないことです。そのファクトリ メソッドが呼び出されました。しかし、これは一般的な .NET の問題だと思います。なぜなら、メソッドは実際にはどこから呼び出されたのかを決して知らないからです。

そのため、ファクトリ インスタンスごとに 1 つのインスタンスのみを生成し、ビューモデルにもスコープを設定する独自のファクトリを使用できます。

お役に立てれば。

于 2012-12-28T12:13:21.203 に答える