Asp.NET 核心 MVC Razor 页面呈现中的 NotSupportedException
NotSupportedException in Asp.NET Core MVC Razor Pages Rendering
我最近创建了一个小型 ASP.Net 核心 MVC 项目,并将我所有的 .cshtml 文件放在 Views 目录中。然后我在 Startup.cs 中使用以下代码更改 Razor 搜索视图文件的位置:
services.Configure<RazorViewEngineOptions>(options => {
//{2} is area, {1} is controller, {0} is the action
options.ViewLocationFormats.Clear();
options.ViewLocationFormats.Add("/Views/{1}" + RazorViewEngine.ViewExtension);
});
.cshtml 文件映射到相应的控制器名称,其中所有控制器都包含一个默认的 "Index" 操作,该操作只是 returns 关联的 View()。
这是当前路由:
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Index}/{action=Index}/{id?}");
});
在我看来,此配置应该有效,但是每当我尝试调用任何页面时,Razor 都会抛出 "NotSupportedException",我不确定如何调试它:
NotSupportedException: Specified method is not supported.
Microsoft.AspNetCore.Mvc.RazorPages.PageBase.EnsureRenderedBodyOrSections()
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync(ViewContext context, ViewBufferTextWriter bodyWriter)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync<TFilter, TFilterAsync>()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
我看了一下EnsureRenderedBodyOrSections()的源码,简单来说就是下面这样:
public override void EnsureRenderedBodyOrSections() {
//This will never be called by MVC. MVC only calls this method on layout pages, and a Page can never be a layout page.
throw new NotSupportedException();
}
MVC 显然在不该调用的时候调用了该函数。这里的问题到底是什么?
PS:这是 GitHub 上的项目:https://github.com/mathusummut/nemesys-Whosebug
调用 EnsureRenderedBodyOrSections
方法的原因是因为您要从控制器返回 View()
结果,并且此方法是 Views 渲染生命周期的一部分。但是,您的 Razor 文件在顶部有 @page
指令,这使它们成为 Razor Pages.
的页面文件
虽然您可以在同一个应用程序中使用 MVC 视图和 Razor 页面,但不能将它们混合用于一个 请求路径。如果您从视图文件中删除 @page
指令,它们将被编译为 Razor 视图而不是 Razor 页面,因此您将不会得到 NotSupportedException
.
作为旁注,我建议删除行 options.ViewLocationFormats.Clear();
并保留默认视图位置,以便您将来可以使用 Views/{Controller}/{Action}
查看位置,同时仍然能够拥有名为 Views/{Controller}
的视图文件。这样,当您向现在的 MVC 应用程序添加更多功能时,您可以使用传统的 MVC 模式来实现。
我最近创建了一个小型 ASP.Net 核心 MVC 项目,并将我所有的 .cshtml 文件放在 Views 目录中。然后我在 Startup.cs 中使用以下代码更改 Razor 搜索视图文件的位置:
services.Configure<RazorViewEngineOptions>(options => {
//{2} is area, {1} is controller, {0} is the action
options.ViewLocationFormats.Clear();
options.ViewLocationFormats.Add("/Views/{1}" + RazorViewEngine.ViewExtension);
});
.cshtml 文件映射到相应的控制器名称,其中所有控制器都包含一个默认的 "Index" 操作,该操作只是 returns 关联的 View()。
这是当前路由:
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Index}/{action=Index}/{id?}");
});
在我看来,此配置应该有效,但是每当我尝试调用任何页面时,Razor 都会抛出 "NotSupportedException",我不确定如何调试它:
NotSupportedException: Specified method is not supported.
Microsoft.AspNetCore.Mvc.RazorPages.PageBase.EnsureRenderedBodyOrSections()
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync(ViewContext context, ViewBufferTextWriter bodyWriter)
Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, string contentType, Nullable<int> statusCode)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync<TFilter, TFilterAsync>()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
我看了一下EnsureRenderedBodyOrSections()的源码,简单来说就是下面这样:
public override void EnsureRenderedBodyOrSections() {
//This will never be called by MVC. MVC only calls this method on layout pages, and a Page can never be a layout page.
throw new NotSupportedException();
}
MVC 显然在不该调用的时候调用了该函数。这里的问题到底是什么?
PS:这是 GitHub 上的项目:https://github.com/mathusummut/nemesys-Whosebug
调用 EnsureRenderedBodyOrSections
方法的原因是因为您要从控制器返回 View()
结果,并且此方法是 Views 渲染生命周期的一部分。但是,您的 Razor 文件在顶部有 @page
指令,这使它们成为 Razor Pages.
虽然您可以在同一个应用程序中使用 MVC 视图和 Razor 页面,但不能将它们混合用于一个 请求路径。如果您从视图文件中删除 @page
指令,它们将被编译为 Razor 视图而不是 Razor 页面,因此您将不会得到 NotSupportedException
.
作为旁注,我建议删除行 options.ViewLocationFormats.Clear();
并保留默认视图位置,以便您将来可以使用 Views/{Controller}/{Action}
查看位置,同时仍然能够拥有名为 Views/{Controller}
的视图文件。这样,当您向现在的 MVC 应用程序添加更多功能时,您可以使用传统的 MVC 模式来实现。