添加具有依赖性的新IFileProvider:使其与asp.net核心的DI

时间:2019-01-28 12:13:10

标签: asp.net-core dependency-injection singleton

我已经创建了一个自定义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时创建“真实”单例的唯一方法吗?对于这些类型的方案是否有更好的解决方案?

谢谢。

0 个答案:

没有答案