AspNetCore RazorEngine将不使用在派生的IOptions <razorviewengineoptions>中配置的FileProviders

时间:2019-02-27 23:48:53

标签: razor asp.net-core-mvc asp.net-core-2.0

用例 一个独立的模板引擎,在任何情况下都不会干扰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

2 个答案:

答案 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%没有性能问题或其他隐藏问题。

也很想知道您是否找到了另一个解决方案:)