继承自定义PageModel后,如何在父模型中实现重定向?
问题描述
为了给布局传递导航栏所需变量(如用户名),我创建了继承自PageModel的LayoutModel类,代码如下:
public class LayoutModel : PageModel { public NavbarDataModel Navbar { get; set; } public readonly FeaturesConfiguration _config; public LayoutModel(IHttpContextAccessor httpContextAccessor, IOptionsSnapshot<FeaturesConfiguration> options) : base() { Navbar = new NavbarDataModel(); Navbar.UserName = httpContextAccessor.HttpContext.Session.GetString("username"); if (string.IsNullOrEmpty(Navbar.UserName)) { RedirectToPage("Login"); // 此处重定向不生效,因为没有返回值,但这是预期的行为 } _config = options.Value; } }
当前重定向未生效,若在父模型中创建IActionResult类型的OnGet()方法返回重定向,会与子类的OnGet()冲突导致程序报错。请问能否在父模型中完成该校验,无需在所有子类中重复实现?
解决方案
可以通过以下几种方式实现父类统一校验,避免子类重复编写逻辑:
方法1:使用页面过滤器(Page Filter)
创建一个实现IAsyncPageFilter的过滤器类,在过滤器中统一处理登录校验和导航栏数据注入,所有继承LayoutModel的页面会自动应用该逻辑,完全解耦页面模型与校验逻辑:
public class NavbarAuthFilter : IAsyncPageFilter { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IOptionsSnapshot<FeaturesConfiguration> _options; public NavbarAuthFilter(IHttpContextAccessor httpContextAccessor, IOptionsSnapshot<FeaturesConfiguration> options) { _httpContextAccessor = httpContextAccessor; _options = options; } public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) { // 仅对继承LayoutModel的页面生效 if (context.HandlerInstance is LayoutModel layoutModel) { var username = _httpContextAccessor.HttpContext.Session.GetString("username"); layoutModel.Navbar = new NavbarDataModel { UserName = username }; layoutModel._config = _options.Value; if (string.IsNullOrEmpty(username)) { context.Result = new RedirectToPageResult("Login"); } } } public Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) { return next(); } }
在Program.cs中注册过滤器:
builder.Services.AddMvc(options => { options.Filters.Add<NavbarAuthFilter>(); });
方法2:父类重写OnPageHandlerExecuting方法
利用Razor Pages的生命周期方法OnPageHandlerExecuting,它会在页面处理方法(如OnGet)执行前触发,在父类中重写该方法完成校验:
public class LayoutModel : PageModel { public NavbarDataModel Navbar { get; set; } public FeaturesConfiguration _config; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IOptionsSnapshot<FeaturesConfiguration> _options; public LayoutModel(IHttpContextAccessor httpContextAccessor, IOptionsSnapshot<FeaturesConfiguration> options) { _httpContextAccessor = httpContextAccessor; _options = options; } public override void OnPageHandlerExecuting(PageHandlerExecutingContext context) { Navbar = new NavbarDataModel(); Navbar.UserName = _httpContextAccessor.HttpContext.Session.GetString("username"); _config = _options.Value; if (string.IsNullOrEmpty(Navbar.UserName)) { context.Result = new RedirectToPageResult("Login"); return; } base.OnPageHandlerExecuting(context); } }
所有继承LayoutModel的页面会自动执行该校验逻辑,一旦设置context.Result,后续页面处理方法将不再执行,完全不会与子类OnGet冲突。
方法3:父类提供虚OnGet方法(需子类配合)
如果偏好使用OnGet方法,可将父类OnGet设为虚方法,子类重写时调用基类方法即可:
public class LayoutModel : PageModel { public NavbarDataModel Navbar { get; set; } public FeaturesConfiguration _config; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IOptionsSnapshot<FeaturesConfiguration> _options; public LayoutModel(IHttpContextAccessor httpContextAccessor, IOptionsSnapshot<FeaturesConfiguration> options) { _httpContextAccessor = httpContextAccessor; _options = options; } public virtual IActionResult OnGet() { Navbar = new NavbarDataModel(); Navbar.UserName = _httpContextAccessor.HttpContext.Session.GetString("username"); _config = _options.Value; if (string.IsNullOrEmpty(Navbar.UserName)) { return RedirectToPage("Login"); } return Page(); } }
子类重写示例:
public class HomeModel : LayoutModel { public HomeModel(IHttpContextAccessor httpContextAccessor, IOptionsSnapshot<FeaturesConfiguration> options) : base(httpContextAccessor, options) { } public override IActionResult OnGet() { var baseResult = base.OnGet(); // 若基类返回重定向,直接返回;否则执行子类逻辑 if (baseResult is RedirectToPageResult) { return baseResult; } // 子类自定义逻辑 return Page(); } }
此方式需要子类主动调用基类方法,相对前两种灵活性稍弱。
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

