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

Asp.net Core调用TempData.Keep()返回HTTP 500错误问题咨询

问题根源

你遇到的两个问题核心都是Asp.net Core中TempData的特性限制:

  1. 生命周期特性:TempData存储的内容默认被读取一次后就会被标记为删除,你在GET方法存入的TempData["cities"]在视图渲染下拉框时已经被读取,所以POST请求拿到的就是null,触发空引用异常。
  2. 存储类型限制:默认的Cookie型TempData提供程序只支持字符串、数值等基础类型,无法直接存储自定义类、集合这类复杂类型,你直接存List<City>的话,运行时序列化失败就会抛出500错误,调用Keep()时触发持久化逻辑自然也会报错。

解决方案1:兼容TempData的修改方案(按现有逻辑调整)

步骤1:序列化复杂类型存储

存取TempData时都通过JSON序列化/反序列化处理,首先确保你的City类是普通POCO类(有无参构造函数、属性都是公开可读写)。
修改GET方法CitiesOnMap:

public IActionResult CitiesOnMap()
{
    List<City> cities = new List<City>
    {
        new City { CityName = "Hatay", Latitude = 123, Longtitude = 435 },
        new City { CityName = "Konya", Latitude = 123, Longtitude = 435 },
        // 其余城市初始化逻辑保持不变
    };
    // 序列化为字符串再存TempData
    TempData["cities"] = System.Text.Json.JsonSerializer.Serialize(cities);
    return View();
}

步骤2:视图读取后保留TempData

修改CitiesOnMap.cshtml的下拉框渲染逻辑,读完TempData后调用Keep()保留内容供POST请求使用:

@{
    var cities = new List<MVC.Models.City>();
    if (TempData["cities"] != null)
    {
        cities = System.Text.Json.JsonSerializer.Deserialize<List<MVC.Models.City>>(TempData["cities"].ToString());
        // 标记保留该键值,不被删除
        TempData.Keep("cities");
    }
}
<!-- 下拉框部分 -->
<select id="drpEmpList" name="SelectedCity" class="form-control">
    <option disabled selected hidden>Choose a City </option>
    @foreach (var city in cities)
    {
        <option>@city.CityName</option>
    }
</select>

步骤3:POST方法反序列化读取

修改POST版CitiesOnMap方法,先反序列化再使用:

[HttpPost]
public IActionResult CitiesOnMap(string SelectedCity)
{
    if (TempData["cities"] != null)
    {
        var cities = System.Text.Json.JsonSerializer.Deserialize<List<City>>(TempData["cities"].ToString());
        foreach (var redirectedCity in cities)
        {
            if (string.Equals(redirectedCity.CityName, SelectedCity))
            {
                // 选中的城市也序列化后存TempData
                TempData["selectedCity"] = System.Text.Json.JsonSerializer.Serialize(redirectedCity);
                return RedirectToAction(redirectedCity.CityName, "City");
            }
        }
    }
    return RedirectToAction(SelectedCity, "City");
}

解决方案2:更合理的优化方案(推荐)

你的场景完全不需要在TempData里存整个城市列表:城市列表是固定的,你可以把城市列表抽成控制器的静态只读字段,GET方法直接传视图,POST方法直接用静态列表查询即可,完全规避TempData的特性问题,性能也更好:

public class CityController : Controller
{
    private readonly ILogger<CityController> _logger;
    // 抽成静态只读的城市列表,所有请求共用
    private static readonly List<City> _cities = new List<City>
    {
        new City { CityName = "Hatay", Latitude = 123, Longtitude = 435 },
        new City { CityName = "Konya", Latitude = 123, Longtitude = 435 },
        // 其余城市初始化逻辑保持不变
    };

    public CityController(ILogger<CityController> logger)
    {
        _logger = logger;
    }

    public IActionResult CitiesOnMap()
    {
        // 直接用View传列表给视图,不需要TempData
        return View(_cities); 
    }

    [HttpPost]
    public IActionResult CitiesOnMap(string SelectedCity)
    {
        var targetCity = _cities.FirstOrDefault(c => string.Equals(c.CityName, SelectedCity));
        if(targetCity != null)
        {
            TempData["selectedCity"] = System.Text.Json.JsonSerializer.Serialize(targetCity);
            return RedirectToAction(targetCity.CityName, "City");
        }
        return RedirectToAction(SelectedCity, "City");
    }

    // 其余方法保持不变
}

对应视图直接接收模型即可,不需要处理TempData:

@model List<MVC.Models.City>
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    ViewData["Title"] = "CitiesOnMap";
}
<!-- 其余页面结构保持不变 -->
<select id="drpEmpList" name="SelectedCity" class="form-control">
    <option disabled selected hidden>Choose a City </option>
    @foreach (var city in Model)
    {
        <option>@city.CityName</option>
    }
</select>

内容的提问来源于stack exchange,提问作者Mertcan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 11:18:01