我正在寻找帮助创建IScopeAccessor的实现,或寻找新的解决方案,这将允许我为每个ViewModel提供NHibernate会话。
我知道Windsor现在支持scoped生活方式(here)。但是,该示例使用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的实现,根据KrzysztofKoźmic(here)允许我
“......提供你喜欢的任何范围。范围是一个抽象的术语,它可以是任何东西。”
不幸的是,我发现IScopeAccessor的实现不是特定于基于Web的场景,我很难理解我需要做什么才能将“任何东西”变成有效的范围。
我找到了一个使用Ninject确切想要做的事情的例子(http://www.emidee.net/index.php/2010/08/23/ninject-use-one-database-session-per-视图模型/):
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做同样的事情或获得相同结果的任何想法?
答案 0 :(得分:1)
问题似乎是创造的地方。 如果所有关于正在构建的视图模型的依赖关系,你可以使用boud生活方式,如What's new...中所述 或者您也可以使用自己的范围访问器,它对视图模型很敏感。例如:
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();
}
}
用于以下viewmodel接口:
public interface IViewModel
{
string DisplayName { get; }
Guid UID { get; }
}
你当然可以用其他方式比较视图模型,这只是一个例子。
绑定生活方式和范围访问器这两者的缺点是,如果在viewmodel中使用类型化工厂,它将无法工作,懒惰地构造对象,因为范围访问者不知道,从中对象/方法调用其工厂方法。但我认为这是一个普遍的.NET问题,因为一个方法确实从来不知道它从哪里被调用。
因此,您可以使用自己的工厂,每个工厂实例只生成一个实例,并将它们作为视图模型的范围。
希望这有帮助。