用例 一个独立的模板引擎,在任何情况下都不会干扰AspNetCore(2.X)Web应用程序中的常规Razor操作。
问题 在尝试实现上述方法的同时,我基于RazorViewEngine,RazorViewCompilerProvider,DefaultRazorPageFactoryProvider,DefaultRazorViewEngineFileProviderAccessor和RazorViewEngineOptions创建了一堆派生的包装器类,以使它们可以在DI中注册并注入,而不会在常规Razor中产生副作用代码路径。除一个烦人的问题外,我已经成功了,因为我仍然需要在常规RazorViewEngineOptions而不是包装类中配置自定义FileProvider(TemplateRepository)。
例如在Startup.cs的以下代码中,即使在我的自定义Options对象中指定了文件提供程序,也就是注入到包装类中的文件提供程序,也不会为View请求调用TemplateRepository,除非第二个服务也是如此。包含(使用RazorViewEngineOptions)。
services.Configure<TemplateOptions>(options =>
{
options.ViewLocationExpanders.Add(new TemplateNameExpander());
options.ViewLocationFormats.Add("{0}");
options.AreaViewLocationFormats.Add("{0}");
options.FileProviders.Clear();
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
services.Configure<RazorViewEngineOptions>(
options =>
{
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
这将向我建议RazorViewEngine依赖关系树中的某个位置将RazorViewEngineOptions注入到某个位置,但是我找不到它。
完整来源@ GitHub
答案 0 :(得分:0)
似乎您已经定义了自定义的RazorViewEngine,但没有告诉MVC使用它。
尝试添加以下代码以将TemplateRazorEngine添加到MVC视图引擎。
services.Configure<TemplateOptions>(options =>
{
options.ViewLocationExpanders.Add(new TemplateNameExpander());
options.ViewLocationFormats.Add("{0}");
options.AreaViewLocationFormats.Add("{0}");
options.FileProviders.Clear();
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
services.Configure<MvcViewOptions>(options => {
var engine = services.BuildServiceProvider().GetRequiredService<TemplateRazorEngine>();
options.ViewEngines.Add(engine);
});
答案 1 :(得分:0)
迟到聚会,但也许将来您会用到它。我还尝试了很多选择,最后得出结论,子容器可以解决我的特定问题。不幸的是,AspNetCore容器不支持它们,因此我不得不快速实施一些可能无法解决您的问题的方法。另一种选择是使用StructureMap或任何其他支持此功能的容器。
public class ChildServiceProvider : IServiceProvider, IDisposable
{
private readonly IServiceProvider _child;
private readonly IServiceProvider _parent;
public ChildServiceProvider(IServiceProvider parent, IServiceProvider child)
{
_parent = parent;
_child = child;
}
public ChildServiceProvider(IServiceProvider parent, IServiceCollection services)
{
_parent = parent;
_child = services.BuildServiceProvider();
}
public void Dispose()
{
(_child as IDisposable)?.Dispose();
}
public object GetService(Type serviceType)
{
return _child.GetService(serviceType) ?? _parent.GetService(serviceType);
}
}
这就是我的用法
public class Startup : IStartup
{
public IServiceProvider ChildServiceProvider { get; set; }
IServiceProvider IStartup.ConfigureServices(IServiceCollection services)
{
// Define a wrapper for the RazorViewEngine and it as a singleton
services.AddSingleton<CustomRazorEngine>(serviceProvider =>
{
// get the RazorViewEngine from the childContainer
var razorViewEngine = ChildServiceProvider.GetRequiredService<IRazorViewEngine>();
return new CustomRazorEngine(razorViewEngine);
});
return services.BuildServiceProvider();
}
public void Configure(IApplicationBuilder app)
{
ChildServiceProvider = CreateChildServiceProvider(app);
app.UseMvc();
}
IServiceProvider CreateChildServiceProvider(IApplicationBuilder parentApp)
{
// create the child container from the parentApp and register
// the custom RazorViewEngineOptions that you need for the isolated templating engine
// and whatever custom services that you need
var server = parentApp.ApplicationServices.GetRequiredService<IServer>();
var webHost = WebHost.CreateDefaultBuilder()
.ConfigureServices(services =>
{
services.AddOptions();
services.Configure<RazorViewEngineOptions>(opts =>
{
opts.FileProviders.Clear();
opts.FileProviders.Add(new CustomFileProvider());
});
services.AddMvc();
})
.Build();
return new ChildServiceProvider(parentApp.ApplicationServices, webHost.Services);
}
}
以及您需要实现的自定义类
public class CustomFileProvider : IFileProvider
{
}
public class CustomRazorEngine
{
private readonly IRazorViewEngine _razorViewEngine;
public CustomRazorEngine(IRazorViewEngine razorViewEngine)
{
_razorViewEngine = razorViewEngine;
}
}
这是在dotnet 2.2上进行的测试,但尚未完全测试到100%没有性能问题或其他隐藏问题。
也很想知道您是否找到了另一个解决方案:)