【问题标题】:AspNetCore RazorEngine will not use FileProviders configured in derived IOptions<RazorViewEngineOptions>AspNetCore RazorEngine 不会使用派生 IOptions<RazorViewEngineOptions> 中配置的 FileProviders
【发布时间】:2019-02-27 23:48:52
【问题描述】:

用例 一个独立的模板引擎,不会以任何方式干扰 AspNetCore (2.X) Web 应用程序中的正常 Razor 操作。

问题 在尝试实现上述内容的同时,我创建了一大堆基于 RazorViewEngine、RazorViewCompilerProvider、DefaultRazorPageFactoryProvider、DefaultRazorViewEngineFileProviderAccessor 和 RazorViewEngineOptions 的派生包装类,以便这些可以向 DI 注册并注入,同时在普通 Razor 中没有副作用代码路径。除了一个烦人的问题外,我已经成功了,我仍然需要在普通的 RazorViewEngineOptions 而不是我的包装类中配置我的自定义 FileProvider (TemplateRepository)。

例如在 Startup.cs 的以下代码中,即使在我的自定义 Options 对象中指定了文件提供程序,也就是注入包装类的内容,除非第二个 service.Configure 也是,否则不会为 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

【问题讨论】:

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


    【解决方案1】:

    您似乎已经定义了您的自定义 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);
            });
    

    【讨论】:

    • 你好 Xing Zou,我不是想让 MVC 使用它,这就是我所说的“一个独立的模板引擎,它不会以任何方式干扰 AspNetCore 中的正常 Razor 操作( 2.X) 网络应用程序”。作为可注入模板引擎,我想要实现的目标。
    【解决方案2】:

    聚会迟到了,但也许您将来会使用它。我也尝试了很多选择,最后我得出结论,子容器可以解决我的特定问题。不幸的是,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% 没有性能问题或其他隐藏问题。

    也很想知道您是否找到了其他解决方案:)

    【讨论】:

      猜你喜欢
      • 2022-11-09
      • 1970-01-01
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多