如何在重写的Razor页面中避免使用GetAwaiter().GetResult()
解决方案
问题根源
- 基类
ApplicationPageModel中的OnGet是具体实现,子类定义同名方法会导致ASP.NET Core路由匹配到多个处理程序,触发InvalidOperationException。 OnPageHandlerExecuted是处理程序执行后的生命周期钩子,此时页面渲染流程已启动,异步操作无法及时更新模型,引发空引用异常;阻塞调用.GetAwaiter().GetResult()会导致线程死锁等风险。
方案一:重构基类为异步虚方法
将基类的通用逻辑封装到异步虚方法中,遵循ASP.NET Core命名约定(后缀Async),子类重写时先执行基类逻辑,再处理页面特定异步操作:
基类代码
public class ApplicationPageModel : PageModel { public virtual async Task<IActionResult?> OnGetAsync() { // cookie handling // page set up // security checking // etc return null; // 返回null表示继续执行子类逻辑 } }
子类代码
public class PermissionsModel : ApplicationPageModel { public override async Task<IActionResult?> OnGetAsync() { // 先执行基类通用逻辑,若基类返回非空结果(如跳转)则直接返回 var baseResult = await base.OnGetAsync(); if (baseResult != null) { return baseResult; } string page = HttpContext.Request.Query["id"].ToString(); // 执行页面特定异步逻辑(此时操作在页面渲染前完成) // Model.Stuff = await GetPagePermissionsAsync(page); return Page(); } }
方案二:使用页面过滤器分离通用逻辑
如果不想依赖基类继承,可通过异步页面过滤器实现通用逻辑复用,完全解耦页面特定代码:
实现页面过滤器
public class ApplicationPageFilter : IAsyncPageFilter { public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { // 处理程序选择阶段:执行安全检查、Cookie验证等前置逻辑 var httpContext = context.HttpContext; // cookie handling // security checking } public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) { // 处理程序执行前:完成页面配置等通用设置 // page set up // 执行页面处理程序(如OnGetAsync) await next(); // (可选)处理程序执行后的逻辑 } }
注册过滤器
在Program.cs中全局注册过滤器:
builder.Services.AddRazorPages(options => { options.Filters.Add<ApplicationPageFilter>(); });
子类简化代码
此时子类无需继承自定义基类,直接编写页面特定异步逻辑:
public class PermissionsModel : PageModel { public async Task<IActionResult> OnGetAsync() { string page = HttpContext.Request.Query["id"].ToString(); // 执行异步操作,模型更新在渲染前完成 // Model.Stuff = await GetPagePermissionsAsync(page); return Page(); } }
内容的提问来源于stack exchange,提问作者djack109
相关产品推荐
相关产品推荐

