RedirectToAction传递空对象问题求助
嘿,这个问题我之前也碰到过!核心原因其实是RedirectToAction的工作机制——它会发起一个全新的GET请求,而不是直接把内存里的ViewModel对象传递给目标方法。默认情况下,ASP.NET Core的模型绑定器没办法通过GET请求的QueryString正确还原复杂的ViewModel(尤其是带集合的,比如你的Items属性),所以才会出现SaveForm里对象为空的情况。
给你几个靠谱的解决方案:
1. 用TempData跨请求传递复杂对象
这是最适合重定向场景的方案,TempData专门用来在两次请求之间临时存储数据。你可以把ViewModel序列化后存到TempData里,然后在SaveForm里取出来反序列化:
// 在AddPerson方法里 [HttpPost] public IActionResult AddPerson(GikFormViewModel formViewModel) { if(formViewModel.Items == null) { // 你的初始化逻辑 } // 序列化ViewModel并存入TempData TempData["FormViewModel"] = JsonSerializer.Serialize(formViewModel); return RedirectToAction(nameof(SaveForm)); } // 在SaveForm方法里 public IActionResult SaveForm() { var jsonData = TempData["FormViewModel"] as string; if(string.IsNullOrEmpty(jsonData)) { // 处理数据丢失的情况,比如返回错误页 return BadRequest("无法获取表单数据"); } var formViewModel = JsonSerializer.Deserialize<GikFormViewModel>(jsonData); // 你的保存逻辑 return View(formViewModel); }
注意:如果你的ViewModel里有自定义类型,要确保这些类型是可序列化的(公共属性、无循环引用、有默认构造函数)。另外TempData默认读取一次后就会被清除,如果需要重复读取,可以用TempData.Keep("FormViewModel")。
2. 传递关键标识符,重新加载数据
如果你的ViewModel数据是来自数据库或者其他持久化存储,更推荐这种方式:在AddPerson里先把ViewModel的临时数据保存(比如存到数据库的临时表,或者缓存),然后传递一个唯一标识符给SaveForm,再在SaveForm里根据这个ID重新加载数据:
// 在AddPerson方法里 [HttpPost] public IActionResult AddPerson(GikFormViewModel formViewModel) { if(formViewModel.Items == null) { // 你的初始化逻辑 } // 生成临时ID,把数据存到数据库或缓存 var tempId = Guid.NewGuid().ToString(); _cache.Set(tempId, formViewModel, TimeSpan.FromMinutes(10)); // 用缓存示例 return RedirectToAction(nameof(SaveForm), new { tempId = tempId }); } // 在SaveForm方法里 public IActionResult SaveForm(string tempId) { if(!_cache.TryGetValue(tempId, out GikFormViewModel formViewModel)) { return BadRequest("数据已过期或不存在"); } // 你的保存逻辑,之后可以清除缓存 _cache.Remove(tempId); return View(formViewModel); }
这种方式更安全,尤其是在分布式系统里,不会有序列化的问题,也避免了TempData可能的生命周期问题。
3. 避免直接传递复杂对象到RedirectToAction
如果你之前是直接写return RedirectToAction(nameof(SaveForm), formViewModel),这种方式只适合简单的ViewModel(无嵌套、无集合),因为ASP.NET Core会把对象的每个属性转换成QueryString参数,但对于集合(比如Items),QueryString的格式很难被模型绑定器正确解析,所以会导致属性丢失或者整个对象为空。
总结一下,优先用TempData或者标识符重新加载的方式,这两种是处理重定向传递复杂数据的标准做法。
内容的提问来源于stack exchange,提问作者Daniel Jackson

