3

我正在寻找一些帮助来创建 IScopeAccessor 的实现,或者寻找一个新的解决方案,这将允许我为每个 ViewModel 提供一个 NHibernate 会话。

我知道温莎现在支持所见的范围生活方式(这里)。但是,该示例使用 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 相关联,这将在需要时动态发生。

作为替代方案,看起来我可以创建 IScopeAccessor 的实现,根据 Krzysztof Koźmic (此处)将允许我

“......提供你喜欢的任何范围。范围在这里是一个抽象术语,它可以是任何东西。”

不幸的是,我找不到不特定于基于 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

问题似乎是创造的地方。如果这完全是关于正在构建的视图模型的依赖关系,您可以使用 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 问题,因为方法实际上永远不知道从哪里调用它。

因此,您可以使用自己的工厂,每个工厂实例只生成一个实例,并将它们的范围也限制在您的视图模型中。

希望这可以帮助。

于 2012-12-28T12:13:21.203 回答