我已经创建了一个自定义IFileProvider
实现。该类依赖于另一个对象(配置为单例),但是在设置它时遇到了一些问题。最初,我首先编写一种如下所示的方法:
public static IServiceCollection SetupPluginSystem(this IServiceCollection services) {
try {
//register related services before initializing
// new plugin model
services.AddSingleton<IPluginInstanceCreator, PluginInstanceCreator>();
services.AddSingleton<IAuthPluginProviderManager>(sp => new AuthPluginProviderManager(
sp.GetService<IPluginInstanceCreator>(),
sp.GetService<ILogger<AuthPluginProviderManager>>()
));
var provider = services.BuildServiceProvider();
//plugins loaded during 1st instantication (singleton)
//now we're setting up the view embeded file provider with required info
var pluginManager = provider.GetService<IAuthPluginProviderManager>();
var logService = provider.GetService<ILogService>();
var cnn = provider.GetService<IDbConnection>();
LoadPluginsFromDb(pluginManager, cnn, logService);
services.Configure<RazorViewEngineOptions>(x => x.FileProviders.Add(new EmbeddedPluginFileProvider(pluginManager)));
}
catch (Exception ex) {
var provider = services.BuildServiceProvider();
var logService = provider.GetService<ILogService>();
logService.LogException(ex, new List<KeyValuePair<string, string>> {new KeyValuePair<string, string>("Method Name", "LoadAuthPlugins")});
}
return services;
}
如您所见,该想法是使用数据库中的信息初始化插件管理器。不,它不起作用,因为在运行时我最终得到了两个IAuthPluginProviderManager
实例(一个实例是由我的BuildServiceProvider
调用创建的容器构建的,另一个实例是由生成的容器构建的由ASP.NET Core基础结构提供。)
所以,我想到了初始化代码移动到拉姆达那个寄存器中的AuthPluginProviderManager
作为一个单:
public static IServiceCollection SetupPluginSystem(this IServiceCollection services) {
try {
//register related services before initializing
// new plugin model
services.AddSingleton<IPluginInstanceCreator, PluginInstanceCreator>();
services.AddSingleton<IAuthPluginProviderManager>(sp => {
var pluginManager = new AuthPluginProviderManager(
sp.GetService<IPluginInstanceCreator>(),
sp.GetService<ILogger<AuthPluginProviderManager>>());
var logService = sp.GetService<ILogService>();
var cnn = sp.GetService<IDbConnection>();
LoadPluginsFromDb(pluginManager, cnn, logService);
});
// but now how do I register my IFileProvider?
services.Configure<RazorViewEngineOptions>(x => x.FileProviders.Add(new EmbeddedPluginFileProvider(pluginManager)));
}
catch (Exception ex) { ... }
return services;
}
不幸的是,存在将插件管理器单例传递给自定义IFileProvider
的构造函数的问题……与用于注册服务的AddXXX方法不同,Configure
没有重载接受Func
用于在运行时解析实例的方法。
最后,我不得不做出这样的妥协:
public static IServiceCollection SetupPluginSystem(this IServiceCollection services) {
try {
services.AddSingleton<IPluginInstanceCreator, PluginInstanceCreator>();
var provider = services.BuildServiceProvider();
var pluginManager = new AuthPluginProviderManager(
provider.GetService<IPluginInstanceCreator>(),
provider.GetService<ILogger<AuthPluginProviderManager>>()
);
var logService = provider.GetService<ILogService>();
var cnn = provider.GetService<IDbConnection>();
LoadPluginsFromDb(pluginManager, cnn, logService);
services.AddSingleton<IAuthPluginProviderManager>(sp => pluginManager);
services.Configure<RazorViewEngineOptions>(x => x.FileProviders.Add(new EmbeddedPluginFileProvider(pluginManager)));
}
catch (Exception ex) {...}
return services;
}
使用此解决方案,我创建了该对象的实例,该实例应在有人要求IAuthPluginProviderManager
时使用。是的,即使您多次调用BuildServiceProvider
,它也将始终返回相同的对象。
即使这可行,但我想知道对于这些情况是否还有另一个更优雅的解决方案。我的意思是,这是使用ASP.NET Core的DI时创建“真实”单例的唯一方法吗?对于这些类型的方案是否有更好的解决方案?
谢谢。