升级至ASP.NET Core 2.1.0后自定义RazorTemplateEngine失效
解决ASP.NET Core 2.1中自定义RazorTemplateEngine失效的问题
这个问题的核心原因是ASP.NET Core 2.1对Razor视图编译系统做了重大调整——框架不再直接注入RazorTemplateEngine实例,而是通过IRazorTemplateEngineFactory工厂接口来创建模板引擎。你之前直接注册CustomRazorTemplateEngine单例的方式,已经无法被框架识别和调用了。
下面是修复后的完整方案:
1. 实现自定义的IRazorTemplateEngineFactory
我们需要创建一个工厂类,负责生成你的自定义模板引擎实例,让框架能够正确获取到它:
using Microsoft.AspNetCore.Razor.Language; public class CustomRazorTemplateEngineFactory : IRazorTemplateEngineFactory { private readonly RazorEngine _engine; private readonly RazorProject _project; private readonly HtmlMinifier _htmlMinifier; public CustomRazorTemplateEngineFactory(RazorEngine engine, RazorProject project) { _engine = engine; _project = project; _htmlMinifier = new HtmlMinifier(); } public RazorTemplateEngine Create() { var customEngine = new CustomRazorTemplateEngine(_engine, _project, _htmlMinifier); customEngine.Options.ImportsFileName = "_ViewImports.cshtml"; return customEngine; } }
2. 调整自定义RazorTemplateEngine的实现
把HtmlMinifier通过构造函数注入(解耦依赖,也方便后续扩展),同时修复原代码中可能出现的索引越界问题:
using System.IO; using System.Text; using Microsoft.AspNetCore.Razor.Language; public class CustomRazorTemplateEngine : RazorTemplateEngine { private readonly HtmlMinifier _htmlMinifier; public CustomRazorTemplateEngine(RazorEngine engine, RazorProject project, HtmlMinifier htmlMinifier) : base(engine, project) { _htmlMinifier = htmlMinifier; } public override RazorCodeDocument CreateCodeDocument(RazorProjectItem projectItem) { using (var inputStream = projectItem.Read()) using (var reader = new StreamReader(inputStream)) { var text = reader.ReadToEnd(); var markupStart = text.IndexOf("<!DOCTYPE"); // 处理视图中没有DOCTYPE的情况,避免索引越界 if (markupStart == -1) { markupStart = 0; } var directives = text.Substring(0, markupStart); var markup = text.Substring(markupStart); text = directives + Minify(markup); var byteArray = Encoding.UTF8.GetBytes(text); using (var minifiedInputStream = new MemoryStream(byteArray)) { var source = RazorSourceDocument.ReadFrom(minifiedInputStream, projectItem.PhysicalPath); var imports = GetImports(projectItem); return RazorCodeDocument.Create(source, imports); } } } private string Minify(string markup) { var result = _htmlMinifier.Minify(markup, string.Empty, Encoding.UTF8, true); if (result.Errors.Count == 0) { var statistics = result.Statistics; if (statistics != null) { Console.WriteLine(); Console.WriteLine($"Original size: {statistics.OriginalSize:N0} Bytes | Minified size: {statistics.MinifiedSize:N0} Bytes | Saved: {statistics.SavedInPercent:N2}%"); } return result.MinifiedContent; } else { Console.WriteLine(); Console.WriteLine($"Found {result.Errors.Count:N0} error(s):"); foreach (var error in result.Errors) { Console.WriteLine($" - Line {error.LineNumber}, Column {error.ColumnNumber}: {error.Message}"); } return markup; } } }
3. 注册自定义工厂到服务容器
替换你原来的services.AddSingleton<CustomRazorTemplateEngine>();,改为注册工厂接口:
// Startup.cs 中的 ConfigureServices 方法 services.AddSingleton<IRazorTemplateEngineFactory, CustomRazorTemplateEngineFactory>();
为什么原来的方案失效?
在ASP.NET Core 2.1之前,框架直接依赖RazorTemplateEngine实例来处理视图编译,但2.1版本引入了Razor SDK的优化,改用IRazorTemplateEngineFactory来管理模板引擎的创建逻辑。这意味着你之前注册的CustomRazorTemplateEngine单例根本不会被框架调用,自然重写的CreateCodeDocument方法也不会执行。
额外提示:如果你的项目使用了预编译视图,可能需要在项目文件中添加额外配置来启用运行时编译支持,否则自定义压缩逻辑可能不会生效。
内容的提问来源于stack exchange,提问作者Adem Çınar
相关产品推荐
相关产品推荐

