如何在继承BaseController的控制器中保留页面信息,无需重复传pageId?
解决页面上下文持久化的两种方案
场景回顾
我有供所有控制器和视图模型继承的BaseController与BaseViewModel,用来处理多数页面通用的页面信息。点击侧边菜单时,链接会带pageId的QueryString,BaseController会在OnActionExecuted阶段用这个参数获取对应数据,注入到视图模型里。现在需要解决:同一控制器的后续请求(比如表单提交)即便没传pageId,系统也能保留当前页面信息;只有点击浏览器返回,或者QueryString指定不同pageId时,才更新页面信息。另外,我也可以通过控制器名称获取页面,但不知道怎么在BaseController里拿到原始调用的控制器名称。
方案一:用Session持久化当前pageId
核心思路是把有效的pageId存在Session中,后续请求优先使用QueryString的pageId,无参数时直接从Session取值,自动延续页面上下文:
- 将逻辑移至
OnActionExecuting阶段(比OnActionExecuted更早,先处理上下文再执行Action) - 优先读取QueryString中的
pageId,若存在则更新Session并获取对应页面信息 - 无
pageId参数时,直接从Session取出之前存储的pageId,用其获取页面信息 - 浏览器返回场景:只要返回后的URL无新
pageId,就沿用Session中的旧值;若URL包含不同pageId,则自动覆盖更新
代码示例:
public class BaseController : Controller { protected override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); var currentPageId = Request.Query["pageId"]; if (!string.IsNullOrEmpty(currentPageId)) { // 更新Session中存储的当前pageId HttpContext.Session.SetString("CurrentPageId", currentPageId); // 获取页面信息并注入ViewModel var pageInfo = FetchPageInfoById(currentPageId); PopulatePageInfoToViewModel(pageInfo); } else { // 从Session读取之前保存的pageId var savedPageId = HttpContext.Session.GetString("CurrentPageId"); if (!string.IsNullOrEmpty(savedPageId)) { var pageInfo = FetchPageInfoById(savedPageId); PopulatePageInfoToViewModel(pageInfo); } // 可选:若Session无值,可结合方案二用控制器名称兜底 } } // 自定义根据pageId获取页面信息的方法 private PageInfo FetchPageInfoById(string pageId) { // 示例:从数据库或配置文件中查询对应页面信息 return new PageInfo(); } // 将页面信息注入BaseViewModel private void PopulatePageInfoToViewModel(PageInfo pageInfo) { if (ViewData.Model is BaseViewModel baseVm) { baseVm.PageInfo = pageInfo; } } }
方案二:通过控制器名称自动匹配页面信息
如果页面与控制器是一一对应的关系,这个方案更省心,完全不需要依赖pageId参数:
在BaseController中获取当前控制器名称非常简单,直接使用ControllerContext.RouteData.Values["controller"]即可,它会自动获取路由中的控制器名称,无论是初始请求还是表单回发都有效。
代码示例:
public class BaseController : Controller { protected override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); // 直接获取当前控制器名称 var controllerName = ControllerContext.RouteData.Values["controller"].ToString(); var pageInfo = FetchPageInfoByControllerName(controllerName); if (ViewData.Model is BaseViewModel baseVm) { baseVm.PageInfo = pageInfo; } } // 自定义根据控制器名称获取页面信息的方法 private PageInfo FetchPageInfoByControllerName(string controllerName) { // 示例:从数据库或配置文件中根据控制器名称匹配页面 return new PageInfo(); } }
方案选择建议
- 方案一适合一个控制器对应多个页面的场景,灵活度更高
- 方案二适合控制器与页面一一对应的场景,代码更简洁,无需维护额外参数
- 也可混合使用:优先判断QueryString中的
pageId,无参数时再用控制器名称兜底
内容的提问来源于stack exchange,提问作者Pedro Costa
相关产品推荐
相关产品推荐

