我在我的应用程序中使用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>();
ViewModel是许多可以具有类似依赖关系层次结构的类之一。
我能够让它适应我的情况的方法是创建一个服务,只在非root用户的范围内管理实例作为单例。
// 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>();
在这种情况下,everthing将按我的需要工作。上下文解析对于根范围内的每个请求都是唯一的,并在子范围内共享。
答案 0 :(得分:1)
这是......有点复杂,有些暗示可能存在一些设计问题。根据我自己的经验,每当我发现我想做X 时,除了这个奇怪的情况,我想要Y ,这意味着我设计了一些错误。
但是,让我们说出你需要的东西。
来自&#34;要求&#34;这听起来像是ConfigurationServices
用法......
DbContext
实例DbContext
。 (它可以但它不会 。) Sounds like a prime use case for the Owned<T>
relationship.
我将其设置为......
ConfigurationServices
是一个无国籍的单身人士。ConfigurationServices
中需要上下文时,它会处理上下文的解析,执行和清理。它看起来像这样:
public class ConfigurationServices
{
Func<Owned<DbContext>> _contextFactory;
public ConfigurationServices(Func<Owned<DbContext>> contextFactory)
{
this._contextFactory = contextFactory;
}
public void DoWork()
{
using(var context = this._contextFactory().Value)
{
context.DoSomethingInDatabase();
}
}
}
Func<T>
关系可以动态解决Owned<T>
的全新实例。 Owned<T>
部分表示容器赢得在处置中保留对它的引用,而是让你控制处置。
鉴于ConfigurationServices
在这种情况下将是无状态单身,你可以像这样注册它。
builder.RegisterType<ConfigurationServices>()
.SingleInstance();
无论它在何处被解析,它都来自根容器范围(所有单身人士都这样做),这意味着Func<Owned<DbContext>>
也将来自那里......但是因为你正在使用Owned<T>
您无法避免内存泄漏。容器不会保留参考资料进行处置。