在采用了博文 ASP.NET Core 3.0 自动挡换手动挡:在 Middleware 中执行 Controller Action 中手动执行 Action 的方法后,遇到了一个新问题,找不到放在 Razor Class Library 中的视图文件,错误信息如下:
System.InvalidOperationException: The view '500' was not found. The following locations were searched:
/Views/Errors/500.cshtml
/Views/Shared/500.cshtml
/Pages/Shared/500.cshtml
at Microsoft.AspNetCore.Mvc.ViewEngines.ViewEngineResult.EnsureSuccessful(IEnumerable`1 originalLocations)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
而如果把视图文件放在 web 项目中没有这个问题,请问如何解决?
通过在 ASP.NET Core 源码 DefaultRazorPageFactoryProvider.CreateFactory 方法中打点
var compileTask = Compiler.CompileAsync(relativePath);
var viewDescriptor = compileTask.GetAwaiter().GetResult();
var viewType = viewDescriptor.Type;
Console.WriteLine("viewType: " + viewType);
发现出问题时 viewType 的值为 null ,正常时 viewType 的值为 AspNetCore.Views_Errors_404
将 Razor Class Library 项目的 TargetFramework 由 netcoreapp3.0
改为 netstandard2.0
后问题解决了。
【解决后的表现】
ASP.NET Core 源码中 DefaultViewCompiler 构造函数的埋点输出为
compiledView: /Views/Errors/500.cshtml
ASP.NET Core debug 日志输出
dbug: Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler[3]
Initializing Razor view compiler with compiled view: '/Views/Errors/500.cshtml'.
DefaultRazorPageFactoryProvider.CreateFactory() 中的埋点
Console.WriteLine("relativePath: " + relativePath);
Console.WriteLine("Compiler: " + Compiler);
var compileTask = Compiler.CompileAsync(relativePath);
var viewDescriptor = compileTask.GetAwaiter().GetResult();
var viewType = viewDescriptor.Type;
Console.WriteLine("viewType: " + viewType);
及输出
relativePath: /Views/Errors/500.cshtml
Compiler: Microsoft.AspNetCore.Mvc.Razor.Compilation.DefaultViewCompiler
viewType: AspNetCore.Views_Errors_500
后来发现问题的真正原因是 Razor Class Library 的 .csproj 中的配置,正确的配置如下:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
从源码看是由于 ViewResultExecutor.FindView 没有找到视图
– dudu 5年前阅读源码找线索: ViewResult.ExecuteResultAsync() -> ViewResultExecutor.ExecuteAsync() -> CompositeViewEngine.GetView() -> RazorViewEngine.GetView() -> LocatePageFromPath() -> CreateCacheResult() -> DefaultRazorPageFactoryProvider.CreateFactory() -> DefaultViewCompiler.CompileAsync()
– dudu 5年前对应的 debug 日志:"Initializing Razor view compiler with no compiled views"
– dudu 5年前