I am experimenting with loading views from a database, and as suggested in the article one might want to add some caching to prevent hitting the database every time.
ConfigureServices
:
services.AddHttpContextAccessor();
services.AddMemoryCache();
services.AddRazorPages()
.AddRazorRuntimeCompilation(opt =>
{
opt.FileProviders.Add(new DatabaseFileProvider(Configuration["AppSettings:SQLConnectionString"]));
});
DatabaseFileProvider
constructor:
private string _connection;
public DatabaseFileProvider(string connection)
{
_connection = connection;
}
How do I dependency inject an instance of IMemoryCache
to the DatabaseFileProvider
class?, as one can do with e.g. a singleton:
ConfigureServices
:
services.AddSingleton<AppUtils>();
AppUtils
constructor:
private static IMemoryCache _cache;
public AppUtils(IMemoryCache cache)
{
_cache = cache;
}
Use DI services to configure MvcRazorRuntimeCompilationOptions
directly
Assuming a target provider like
public class DatabaseFileProvider : IFileProvider {
private string connection;
private IMemoryCache cache;
public DatabaseFileProvider(string connection, IMemoryCache cache) {
this.connection = connection;
this.cache = cache;
}
//...
}
Creating the provider with the aid of the DI services will allow for any registered dependencies to be resolved and explicitly injected using the deferred configuration delegate.
Reference 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
allows the use of up to five services to configure options, but if a IServiceProvider
is injected, the provider can be used in resolve more dependencies if needed.
If that service locator approach is not preferred, the setup can be rearranged to follow a more pure DI design.
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();