【发布时间】:2018-01-26 19:31:09
【问题描述】:
我在我的应用程序中使用 autofac 并努力让这种情况正常工作。
我将我的类型注册为 PerLifetimeScope,但此规则也适用于根容器。
我有一个实例,它应该只为在子 LifetimeScope 内完成的请求共享,但应该总是为直接完成到根容器的请求返回一个新实例。
为了更好地描述:
我有一个使用 autofac 来解决依赖关系的移动应用程序。
我为应用程序构建了一个全局容器。当用户导航到新页面时,我会从该页面的容器中打开一个新范围。
页面可以使用 EntityFrameworkCore 访问内部 sqlite 数据库。用于访问数据库的 DbContext 实例对于页面范围内的所有依赖项应该是相同的。
我还有一个 ConfigurationsService 类,我像字典(键/值)一样使用它,但也存储在数据库中。 此类应在页面的任何范围之外在数据库中执行更新,而不是与页面所做的其他更改交互。
当单个配置发生更改时,它会请求 DbContext 的一个实例,进行更改并释放该实例。
这里的问题是,当 ConfigurationService 从容器(不是作用域)请求 DbContext 实例时,DbContext 现在将是一个共享实例,并且连接将保持活动状态,直到容器被释放。
我可以为此打开一个作用域,但它会为处于相同情况的每个类留下作用域生命周期的控制权。
更新 1:
下面的代码很好地代表了依赖层次和我上面描述的情况。
// CLASSES
public class Context
{
}
public class Repository
{
public Repository(Context context)
{
Context = context;
}
public Context Context { get; }
}
public class ViewModel
{
public ViewModel(Repository repository1, Repository repository2)
{
Repository1 = repository1;
Repository2 = repository2;
}
public Repository Repository1 { get; }
public Repository Repository2 { get; }
}
// SAMPLE
var repository1 = container.Resolve<Repository>();
var repository2 = container.Resolve<Repository>();
var viewModel = container.Resolve<ViewModel>();
- repository1 和 repository2 变量的上下文引用应该是不同的实例。
- viewModel.Repository1 和 viewModel.Repository2 的上下文引用应该是同一个实例。
ViewModel 是可能具有类似依赖层次结构的众多类之一。
我可以让它在我的情况下工作的方法是创建一个服务,该服务仅在非根范围内将实例作为单例进行管理。
// CLASSES
public class ScopeSingletons
{
private readonly List<object> _instances = new List<object>();
public T Get<T>(Func<T> factory)
{
var instance = _instances.OfType<T>().SingleOrDefault();
if (instance == null)
_instances.Add(instance = factory());
return instance;
}
}
// SAMPLE
var builder = new ContainerBuilder();
builder.RegisterType<ScopeSingletons>().AsSelf().InstancePerLifetimeScope();
builder.RegisterType<ViewModel>().AsSelf();
builder.RegisterType<Repository>().AsSelf();
builder.Register<Context>(c =>
{
if (Equals((c as IInstanceLookup)?.ActivationScope.Tag, "root"))
return new Context();
return c.Resolve<ScopeSingletons>().Get(() => new Context());
});
var container = builder.Build();
var scope = container.BeginLifetimeScope();
var repository1 = container.Resolve<Repository>();
var repository2 = container.Resolve<Repository>();
var viewModel = scope.Resolve<ViewModel>();
在这种情况下,一切都会按照我的需要进行。上下文解析对于根范围内的每个请求都是唯一的,并在子范围内共享。
【问题讨论】: