如何通过_Layout页传递全局变量至所有视图?技术方案咨询
嘿,我完全懂你的需求——就是想让用户选的年份能在所有视图里顺畅用起来,还得避开Session那种一刷新、切页面就丢数据的坑对吧?下面几个方案应该能完美解决你的问题,你可以根据项目情况挑合适的:
方案一:Cookie + 全局ActionFilter(最推荐)
这个方案把年份持久存在用户浏览器的Cookie里,同时通过全局过滤器自动把年份注入到所有视图,彻底解决数据丢失的问题:
1. 处理年份选择的存储逻辑
先写一个Action接收用户选的年份,把它存到Cookie里:
public IActionResult SetSelectedYear(int year) { var cookieOptions = new CookieOptions { Expires = DateTime.Now.AddMonths(1), // 有效期设1个月,按需调整时长 HttpOnly = false, // 允许前端读取,方便下拉列表默认选中对应年份 SameSite = SameSiteMode.Lax }; Response.Cookies.Append("UserSelectedYear", year.ToString(), cookieOptions); return Redirect(Request.Headers["Referer"].ToString()); // 跳回原页面,体验更流畅 }
2. 创建全局ActionFilter自动注入年份
写一个过滤器,在每个Action执行前从Cookie里读取年份,自动注入到所有视图:
public class GlobalYearFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { var httpContext = context.HttpContext; // 尝试从Cookie读年份,读不到就用当前年份当默认值 if (httpContext.Request.Cookies.TryGetValue("UserSelectedYear", out var yearStr) && int.TryParse(yearStr, out var selectedYear)) { context.Controller.ViewBag.SelectedYear = selectedYear; } else { context.Controller.ViewBag.SelectedYear = DateTime.Now.Year; } } public void OnActionExecuted(ActionExecutedContext context) { } }
3. 注册全局Filter
在Program.cs(.NET Core)里注册这个过滤器,让它对所有Action生效:
builder.Services.AddControllersWithViews(options => { options.Filters.Add<GlobalYearFilter>(); });
4. 前端使用示例
在任意视图(包括_Layout.cshtml)里直接用@ViewBag.SelectedYear,下拉列表也能默认选中用户之前选的年份:
<select onchange="window.location.href='@Url.Action("SetSelectedYear", "Home")?year='+this.value"> @for (int y = DateTime.Now.Year - 3; y <= DateTime.Now.Year + 3; y++) { <option value="@y" @(y == ViewBag.SelectedYear ? "selected" : "")>@y</option> } </select>
方案二:使用ViewComponent(适合复杂展示逻辑)
如果你的年份展示需要结合权限、额外业务数据等复杂逻辑,可以用ViewComponent来封装:
1. 创建YearSelectorViewComponent
public class YearSelectorViewComponent : ViewComponent { public IViewComponentResult Invoke() { var selectedYear = DateTime.Now.Year; if (HttpContext.Request.Cookies.TryGetValue("UserSelectedYear", out var yearStr) && int.TryParse(yearStr, out var year)) { selectedYear = year; } // 返回带年份模型的视图 return View(selectedYear); } }
2. 编写ViewComponent的视图
在Views/Shared/Components/YearSelector/Default.cshtml里写下拉列表逻辑:
@model int <select onchange="window.location.href='@Url.Action("SetSelectedYear", "Home")?year='+this.value"> @for (int y = DateTime.Now.Year - 3; y <= DateTime.Now.Year + 3; y++) { <option value="@y" @(y == Model ? "selected" : "")>@y</option> } </select>
3. 在任意视图调用
@await Component.InvokeAsync("YearSelector")
需要在其他地方获取年份的话,也可以在ViewComponent里把年份存入ViewBag,或者通过模型传递。
关于你之前的Session问题
你提到Session刷新后丢失,大概率是Session配置的问题——比如默认Session有效期只有20分钟,或者你用了无状态托管环境(比如Azure App Service)但没配置分布式缓存。不过相比Session,Cookie更适合这种用户偏好类的存储,因为它存在用户端,不依赖服务器存储,稳定性更高。
内容的提问来源于stack exchange,提问作者user3481085

