【问题标题】:Dependency inject a custom file provider for runtime compilation依赖注入自定义文件提供程序以进行运行时编译
【发布时间】:2021-08-28 14:47:29
【问题描述】:

我正在尝试使用loading views from a database,正如文章中所建议的那样,可能需要添加一些缓存以防止每次都访问数据库。

ConfigureServices:

services.AddHttpContextAccessor();
services.AddMemoryCache();

services.AddRazorPages()
    .AddRazorRuntimeCompilation(opt =>
    {
        opt.FileProviders.Add(new DatabaseFileProvider(Configuration["AppSettings:SQLConnectionString"]));
    });

DatabaseFileProvider构造函数:

private string _connection;

public DatabaseFileProvider(string connection)
{
    _connection = connection;
}

如何依赖注入 IMemoryCache 的实例到 DatabaseFileProvider 类?单身人士:

ConfigureServices:

services.AddSingleton<AppUtils>();

AppUtils构造函数:

private static IMemoryCache _cache;

public AppUtils(IMemoryCache cache)
{
    _cache = cache;
}

【问题讨论】:

  • @Nkosi -- 如果您可以提供一个示例的答案,如果我将 Options 和 IMemoryCache 都注入到 DatabaseFileProvider 中,我将不胜感激,因为我不能看看应该怎么做(当谈到 ASP.NET Core 及其设置/配置方式时,我是一个真正的新手)。

标签: c# dependency-injection asp.net-core-5.0 runtime-compilation fileprovider


【解决方案1】:

使用DI服务直接配置MvcRazorRuntimeCompilationOptions

假设目标提供者像

public class DatabaseFileProvider : IFileProvider {
    private string connection;
    private IMemoryCache cache;

    public DatabaseFileProvider(string connection, IMemoryCache cache) {
        this.connection = connection;
        this.cache = cache;
    }

    //...

}

借助 DI 服务创建提供程序将允许解析任何已注册的依赖项,并使用延迟配置委托显式注入。

参考Use DI services to configure options

services.AddHttpContextAccessor();
services.AddMemoryCache();

services
    .AddOptions<MvcRazorRuntimeCompilationOptions>() 
    .Configure<IServiceProvider>((options, sp) => { //<-- Configuration here
        var cs = Configuration["AppSettings:SQLConnectionString"]);
        var provider = ActivatorUtilities.CreateInstance<DatabaseFileProvider>(sp, cs);
        options.FileProviders.Add(provider);
    });

services.AddRazorPages()
    .AddRazorRuntimeCompilation(); //remove configuration delegate here

Configure 允许使用最多五个服务来配置选项,但如果注入了IServiceProvider,则可以在需要时使用提供程序来解决更多依赖关系。

如果该服务定位器方法不是首选,则可以重新安排设置以遵循更纯粹的 DI 设计。

services.AddHttpContextAccessor();
services.AddMemoryCache();

service.AddTransient<IFileProvider, DatabaseFileProvider>(sp => {
    var cs = Configuration["AppSettings:SQLConnectionString"]);
    var provider = ActivatorUtilities.CreateInstance<DatabaseFileProvider>(sp, cs);
    return provider;
});

//... register other providers if any

services
    .AddOptions<MvcRazorRuntimeCompilationOptions>() 
    .Configure<IEnumerable<IFileProvider>>((options, providers) => {
        //add all registered providers
        foreach(IFileProvider provider in providers) {
            options.FileProviders.Add(provider);
        }
    });

services.AddRazorPages()
    .AddRazorRuntimeCompilation();

【讨论】:

  • 我有一个具体的 IFileProvider,它依赖于范围服务。如果我使用此解决方案,我会收到错误“无法从根提供程序解析范围服务 {path to my class}”。我们怎样才能解决这个问题?
  • @ctorx 您在解决方案中使用了哪种方法?第一个还是第二个?
  • 我实际上都试过了,但都没有运气。我本质上需要 IFileProvider 实现来解析实体框架 DBContext 的范围实例,以便我可以使用它从上下文中获取剃刀视图。
  • @ctorx 然后通过提供者创建一个作用域来解析上下文。
  • 谢谢。这正是我所需要的。
猜你喜欢
  • 2018-11-02
  • 1970-01-01
  • 2016-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-07
  • 1970-01-01
  • 2010-11-29
相关资源
最近更新 更多