ASP.NET Core MVC用TempData给中间件传值添加请求头为何失效
问题原因
你当前的实现方式本身不符合TempData的设计定位,失效是正常现象:
TempData的生命周期默认是仅单次请求读取有效,只要你读取了对应键的值,该数据就会被自动标记为待删除,哪怕你在控制器调用了TempData.Keep(),在中间件首次读取tempData["username"]后,下一次请求也无法再获取到该值。TempData是为控制器动作间的单次跳转传值设计的,并不适用跨多请求在中间件共享用户数据的场景。
解决方案
你提到的用Session实现是可行的,这也是这种场景下的标准实现思路,具体改造步骤如下:
1. 配置Session服务与中间件顺序
首先在Program.cs中注册Session服务,且必须保证Session中间件在你的自定义中间件之前注册,否则中间件无法读取Session数据:
// 注册Session服务 builder.Services.AddSession(options => { // 按需设置Session过期时间 options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); // 中间件管道顺序严格遵循:Session -> 自定义中间件 -> MVC相关中间件 app.UseSession(); app.UseMiddleware<CorrelationIdMiddleware>(); app.UseRouting(); // 其他鉴权、授权中间件 app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
2. 修改控制器代码,把username存入Session
删除原有的TempData相关逻辑,改为存入Session:
[HttpPost] public IActionResult AddressValidate(IFormCollection form) { string username = form["UserName"]; // 将username存入Session HttpContext.Session.SetString("username", username); string status = form["Status"]; _logger.LogInformation("Current user logged in: {@Username}", username); // 原有业务逻辑 return RedirectToAction("SecondIndex", "Second"); }
3. 修改中间件代码,从Session读取username
同时修正你原代码中CorrelationId取值的错误逻辑:
public async Task Invoke(HttpContext httpContext) { string correlationId = null; if (httpContext.Request.Headers.TryGetValue(CorrelationIdHeaderKey, out StringValues correlationIds)) { // 修正原有错误的取值逻辑,直接取请求头的值即可 correlationId = correlationIds.FirstOrDefault(); _logger.LogInformation("CorrelationId from Request Header: {@correlationId} ", correlationId); } else { // 从Session读取username var userName = httpContext.Session.GetString("username"); if (!string.IsNullOrEmpty(userName) && !httpContext.Request.Headers.ContainsKey("X-username")) { httpContext.Request.Headers.Add("X-username", userName); } correlationId = Guid.NewGuid().ToString(); httpContext.Request.Headers.Add(CorrelationIdHeaderKey, correlationId); _logger.LogInformation("Generated CorrelationId: {@correlationId}", correlationId); } httpContext.Response.OnStarting(() => { if (!httpContext.Response.Headers.TryGetValue(CorrelationIdHeaderKey, out correlationIds)) { httpContext.Response.Headers.Add(CorrelationIdHeaderKey, correlationId); } return Task.CompletedTask; }); await _next.Invoke(httpContext); }
其他可选方案
如果你的系统已经接入了ASP.NET Core身份认证,不需要自己存储username,直接在中间件读取httpContext.User.Identity?.Name即可,比Session方案更安全便捷。
内容的提问来源于stack exchange,提问作者MarkCo
相关产品推荐
相关产品推荐

