HttpPost方法无法读取TempData引发NullReferenceException与500错误求助
问题根因
- 触发
NullReferenceException的核心原因是TempData默认不支持直接存储自定义类这类复杂类型,如果你使用的是ASP.NET Core默认的Cookie式TempData提供器,存储非字符串类型时会序列化失败,Post请求读取TempData["cities"]时会得到null,强制类型转换后依然是空引用,遍历null对象直接抛出空引用异常,进而触发HTTP 500错误。 - 你的代码未对转换后的城市列表做空校验,一旦获取失败直接遍历就会触发报错。
- 原有Post方法末尾未匹配到城市时直接用传入的
SelectedCity跳转,若对应Action不存在也会触发500错误。
修复方案
方案1:手动序列化/反序列化(无需修改全局配置,推荐)
用.NET自带的JSON序列化工具将复杂类型转成字符串再存入TempData,避免类型丢失问题:
1. 修改GET方法存值逻辑
// 引入命名空间 using System.Text.Json; public IActionResult CitiesOnMap() { List<City> cities = new List<City>(); // 原有城市赋值逻辑保持不变 cities.Add(new City { CityName = "Hatay", Latitude = 123, Longtitude = 435 }); cities.Add(new City { CityName = "Konya", Latitude = 123, Longtitude = 435 }); // ...其他城市添加逻辑不变 // 序列化后存字符串到TempData TempData["cities"] = JsonSerializer.Serialize(cities); return View(); }
2. 修改视图读取逻辑
@using System.Text.Json @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ ViewData["Title"] = "CitiesOnMap"; } <div class="text-center pt-5"> <h1 class="display-4 pb-2 ">LET'S SEE THE CITIES!</h1> <p class="pb-3">Now, Please Choose A City You Want to See on Map.</p> <h3> @TempData["SelectedMap"] </h3> <div class="text-center mx-auto pt-5"> <form asp-action="CitiesOnMap" asp-controller="City" method="post"> <div class="row"> <div class="col-9 mx-auto"> <select id="drpEmpList" name="SelectedCity" class="form-control"> <option disabled selected hidden>Choose a City </option> <!-- 反序列化后遍历 --> @foreach (var name in JsonSerializer.Deserialize<List<MVC.Models.City>>(TempData["cities"].ToString())) { <option>@name.CityName </option> } </select> @{ TempData.Keep("cities"); } <input type="hidden" /> </div> </div> <div class="row"> <div class="col-md-12 pt-4"> <input type="submit" name="btnSubmit" value="Let's See" class="btn btn-success btn-lg" /> </div> </div> </form> </div> </div>
3. 修改Post方法逻辑,增加空校验
[HttpPost] public IActionResult CitiesOnMap(string SelectedCity) { // 先判空,避免空引用错误 if (TempData["cities"] == null || string.IsNullOrEmpty(SelectedCity)) { return RedirectToAction("CitiesOnMap"); } // 反序列化得到城市列表 var cities = JsonSerializer.Deserialize<List<MVC.Models.City>>(TempData["cities"].ToString()); foreach (var redirectedCity in cities) { Console.WriteLine("bumbum"); // 增加忽略大小写匹配,避免大小写不一致匹配失败 if (String.Equals(redirectedCity.CityName, SelectedCity, StringComparison.OrdinalIgnoreCase)) { // 选中的城市如果要存TempData,同样序列化后存储 TempData["selectedCity"] = JsonSerializer.Serialize(redirectedCity); return RedirectToAction(redirectedCity.CityName , "City"); } } // 匹配失败跳回选择页,避免跳转到不存在的Action报错 return RedirectToAction("CitiesOnMap"); }
方案2:全局配置Session式TempData(可选)
如果不想手动序列化,可修改全局配置让TempData支持复杂类型存储,在Program.cs中添加以下配置即可保留原有存值逻辑:
// 注册Session服务 builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(20); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); // 指定TempData用Session存储 builder.Services.AddControllersWithViews().AddSessionStateTempDataProvider(); // 中间件配置顺序不能变,要放在UseRouting之前 app.UseSession(); app.UseRouting();
配置完成后依然要给Post方法增加空校验,避免异常抛出。
内容的提问来源于stack exchange,提问作者Mertcan
相关产品推荐
相关产品推荐

