You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

继承自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 18:33:16