ASP.NET Core迁移到.NET 5后仅IIS环境下出现Partial view not found异常
问题根因
- ASP.NET Core 与 .NET Framework 的 MVC 视图查找逻辑差异很大:默认情况下ASP.NET Core优先加载预编译视图,且默认仅扫描
Views、Pages目录下的视图文件,你自定义的~/Resources/Customer/Views/路径不在默认扫描范围内 - 本地调试时Visual Studio默认开启了Razor运行时编译,会实时扫描磁盘文件,所以能正常加载;部署后默认关闭运行时编译,仅查找预编译视图或默认目录下的文件,所以报错
- 你当前代码的路径处理逻辑和视图引擎的路径解析逻辑不匹配:自行判断文件存在的逻辑用了磁盘路径拼接,但调用
RenderPartialAsync时传入的是原始虚拟路径,视图引擎无法解析到对应位置 - IIS虚拟目录部署场景下,自行截取字符串处理路径的方式容易出现路径映射错误
解决方案
1. 开启Razor运行时编译并添加自定义扫描路径
- 安装NuGet包:
Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation - 在启动配置中添加运行时编译,同时指定额外的视图扫描目录,示例代码(Startup/Program.cs):
// .NET 6+ 顶层语句写法 builder.Services.AddControllersWithViews() .AddRazorRuntimeCompilation(options => { // 添加你的自定义视图根目录到扫描路径 options.FileProviders.Add(new PhysicalFileProvider( Path.Combine(builder.Environment.ContentRootPath, "Resources"))); }); // .NET 5 Startup写法放到ConfigureServices方法中即可 services.AddControllersWithViews() .AddRazorRuntimeCompilation(options => { options.FileProviders.Add(new PhysicalFileProvider( Path.Combine(HostEnvironment.ContentRootPath, "Resources"))); });- 安装NuGet包:
2. 配置自定义视图位置扩展器
新增类实现
IViewLocationExpander,告诉视图引擎你的自定义视图路径规则:public class CustomViewLocationExpander : IViewLocationExpander { public void PopulateValues(ViewLocationExpanderContext context) {} public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) { // 添加你的自定义视图路径模板,{0}对应视图名 return new[] { "~/Resources/Customer/Views/{0}.cshtml" }.Concat(viewLocations); } }在启动配置中注册该扩展器:
builder.Services.Configure<RazorViewEngineOptions>(options => { options.ViewLocationExpanders.Add(new CustomViewLocationExpander()); });3. 修正路径处理逻辑
不要自行截取虚拟路径前缀,注入
IWebHostEnvironment用官方提供的路径转换方法处理,避免虚拟目录场景下路径映射错误:string viewPath = configuration.OrderPageSetting["OrderInfoViewRenderFile"]; bool viewExists = false; if (!string.IsNullOrWhiteSpace(viewPath)) { // 官方方法将虚拟路径转换为物理路径,自动适配虚拟目录场景 var physicalPath = _webHostEnvironment.ContentRootFileProvider.GetFileInfo(viewPath).PhysicalPath; viewExists = System.IO.File.Exists(physicalPath); } if (viewExists) { var data = new ViewDataDictionary<object>(new EmptyModelMetadataProvider(), new ModelStateDictionary()); data.Add("Order", order); data.Add("Config", configuration); await Html.RenderPartialAsync(viewPath, data); } else { // 原有默认渲染逻辑 }4. 确认IIS权限配置
给IIS应用池运行身份(路径格式为
IIS AppPool\你的应用池名称)授予应用根目录下Resources文件夹的读取、列出目录内容权限,避免权限不足导致的文件读取失败。5. 适配站点层级无web.config的场景
你当前应用根目录的web.config已经配置了
inheritInChildApplications="false",不会继承上层站点的配置,只需确认IIS服务器全局功能中已启用AspNetCoreModuleV2,即可在站点层级无web.config时正常运行。
内容的提问来源于stack exchange,提问作者Justin
相关产品推荐
相关产品推荐

