与下面的代码一样,我必须使用factory/func方式向容器注册,因为我不知道"userId";属性,但仅在运行时。这是有效的&功能方面没有问题。
container.AddSingleton<IBLogic, BLogic>(); //explicitly registration 'BLogic' service object
container.AddSingleton<Func<string, IDBCache>>
(p=> (userId) => new IDBCache(userId, p.GetService<IBLogic>()));
由于在这里我使用";新IDBCache";,根据链接框架不自动处理服务。
问题:
要让框架自动处理服务,有什么办法吗?
集装箱AddSingleton<Func<字符串,IDBCache>gt;(p=>(userId(=>新IDBCache(userId,p.GetService(((;
由于我只是注册func/factory的定义,而不是服务对象(如"BLogic"(本身,因此AddSingleton与下面的"AddScoped"或"AddTransisent"相比有什么优势吗?
container.AddTransisent<Func<string, IDBCache>>
(p=> (userId) => new IDBCache(userId, p.GetService<IBLogic>()));
没有简单的解决方法。MS.DI不包含可以调用的RegisterForDisposal
方法。您必须创建一个单独的包装器来实现一次性,您可以将创建的实例挂接到该包装器。例如:
services.AddSingleton<IBLogic, BLogic>();
services.AddScoped<DisposeWrapper>();
services.AddScoped<Func<string, IDBCache>>(p => (userId) =>
{
var cache = new IDBCache(userId, p.GetRequiredService<IBLogic>());
p.GetRequiredService<DisposeWrapper>().Add(cache);
return cache;
});
DisposeWrapper
如下所示:
public sealed class DisposeWrapper : List<IDisposable>, IDisposable
{
public void Dispose()
{
// Dispose in reverse order as creation.
for (int i = this.Count - 1; i >= 0; i--) this[i].Dispose();
}
}
然而,这样的实现附带了一些注意事项,因为DisposeWrapper
应该使用与缓存IDBCache
相同的作用域进行注册。这就是为什么在上面的示例中,我将DisposeWrapper
和工厂都注册为Scoped
。
将DisposeWrapper
注册为Singleton意味着创建的IDBCache
实例只有在应用程序结束时才会被释放。如果在应用程序的生存期内创建了许多IDBCache
实例,则会导致内存泄漏。在你的情况下,这不太可能是个好主意。
另一方面,将两者注册为瞬态仍然可能(令人困惑(导致内存泄漏,因为工厂可能被注入到单例中,导致它(及其DisposeWrapper
(成为Captive依赖项。
由于这种设计的复杂性,我建议您更改设计。
如果重新设计IDBCache
,使得在对象构建过程中不需要运行时数据,则可以允许IDBCache
在容器中注册,而无需工厂(例如AddTransient<IDBCache>()
(,从而允许容器正常处理它。这将消除上述所有引入的复杂性。