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

使用RedirectToAction跳转后嵌套ViewModel数据丢失问题

嵌套ViewModel在RedirectToAction后数据丢失问题

我被这个问题卡了好久,之前类似操作都正常,现在找不到问题出在哪,求帮忙!

我在页面加载3个ViewModel,通过BeginForm提交字段到控制器方法,对部分字段用三元表达式处理后,用RedirectToAction跳转到确认页面(Verification),想展示用户刚提交的内容。

Submit方法里ViewModel的字段数据都正常,但跳转后两个嵌套ViewModel的数据没了。Post方法里能看到完整数据,也把模型传给了RedirectToAction,但进入Verification视图后数据就丢了?


视图模型

public class MainViewModel
{
    public Guid Id { get; set; }

    public string? Name { get; set; }
    public string? Email {get; set;}

    public TypesViewModel TypeViewModel {get; set;}
}

public class TypesViewModel
{
    public Guid Id { get; set; }
    public Guid ExternalId {get; set;}

    public bool Type {get; set;}

    public string? Name { get; set; }

    public CustomFieldsViewModel CustomFieldViewModel {get; set;}
}

public class CustomFieldsViewModel 
{
    public bool Email { get; set; } 
    public bool Phone {get; set;}
    public bool Text {get; set;}

    public string? EmailContact { get; set; } 
    public string? PhoneNumberContact {get; set;}
    public string? TextMessageContact {get; set;}
    public String? PhoneNumber {get; set;}
}

控制器代码

public class PrimaryController : Controller
{
    public IActionResult Index()
    {
        MainViewModel mainViewModel = new MainViewModel();

        TypesViewModel typesViewModel = new TypesViewModel();
        mainViewModel.TypeViewModel = typesViewModel;

        CustomFieldsViewModel customFieldsViewModel = new CustomFieldsViewModel();
        mainViewModel.TypeViewModel.CustomFieldViewModel = customFieldsViewModel;

        return View(mainViewModel);
    }

    [HttpPost]
    public ActionResult Submit(MainViewModel model)
    {
        model.Id = Guid.NewGuid();
        model.TypeViewModel.Id = Guid.NewGuid();
        model.TypeViewModel.ExternalId = Guid.NewGuid();
        model.TypeViewModel.Name = model.TypeViewModel.Type == true ? "Yes, Contact me." : "No, Do not contact me.";

        model.TypeViewModel.CustomFieldViewModel.EmailContact = model.TypeViewModel.CustomFieldViewModel.Email == true ? "Contact by Email" : "Do Not Contact By Email";
        model.TypeViewModel.CustomFieldViewModel.PhoneNumberContact = model.TypeViewModel.CustomFieldViewModel.Phone == true ? "Contact by Phone Number" : "Do Not Contact By Phone Number";
        model.TypeViewModel.CustomFieldViewModel.TextMessageContact = model.TypeViewModel.CustomFieldViewModel.Text == true ? "Contact by Text Message" : "Do Not Contact By Text Message";
    
        return RedirectToAction("Verification", model);
    }

    public ActionResult Verification(MainViewModel model)
    {
        return View(model);
    }
}

视图代码

Index视图

@model MainViewModel

@{
    ViewData["Title"] = "Primary Output";
}

<div class="container d-flex align-items-center justify-content-center">
<div class="box">
    @using (Html.BeginForm("Submit", "Primary", FormMethod.Post))
    {
        <label>Name</label>
        @Html.TextBoxFor(m => m.Name, new { @class = "form-control"})

        <label>Email Address</label>
        @Html.TextBoxFor(m => m.Email, new { @class = "form-control", onblur="checkEmail(this.value)", Type = "email"})

        <label>Can we contact you?</label>
        @Html.CheckBoxFor(m => m.TypeViewModel.Type)
        <span>Yes</span>

        <div class="contact-options">
            <label>Prefered form of communication?</label>
            <ul class="list">
                <li> <input type="checkbox" value="true" name="Model.TypeViewModel.CustomFieldViewModel.Email" id="Email"> 
                    <span>Email</span> 
                </li>
                <li> <input type="checkbox" value="true" name="Model.TypeViewModel.CustomFieldViewModel.Phone" onclick="ShowHideDiv(this)" id="Phone">
                    <span>Phone</span>
                </li>
                <li> <input type="checkbox" value="true" name="Model.TypeViewModel.CustomFieldViewModel.Text" onclick="ShowHideDiv(this)" id="Text">
                    <span>Text</span>
                </li>
            </ul>
        </div>

        <div id="Phone-Number">
            <label>Phone Number</label>
            <input class="form-control" type="tel" name="Model.TypeViewModel.CustomFieldViewModel.PhoneNumber" />
        </div>

        <div class="button-container">
            <input id="Submit" type="Submit" value="Submit" />
        </div>
    }
</div>
</div>

Verification视图

@model MainViewModel
@{
    ViewData["Title"] = "Verification";
}

<div class="container d-flex align-items-center justify-content-center">
    <div class="circular-square">
        <img src="https://i.ibb.co/YpsHjmW/The-Big-Lebowski-hp-GQ-25-Feb16-rex-b.jpg" border="0">
    </div>
</div>
<div class="verification-container d-flex align-items-center justify-content-center">
    <div class="verification-title">The Dude Abides.</div>
</div>
<div class="verification-container d-flex align-items-center justify-content-center">
    <div class="box">
        <p>Congrats! You've made it to the final round. Below is the information you submitted!</p>
        <p><label>Id:</label> @Model.Id</p>
        <p><label>Name:</label> @Model.Name</p>
        <p><label>Email:</label> @Model.Email</p>
        <p><label>Type Id:</label> @Model.TypeViewModel.Id</p>
        <p><label>Type Name:</label> @Model.TypeViewModel.Name</p>
        <p><label>Custom Field 1:</label> @Model.TypeViewModel.CustomFieldViewModel.PhoneNumberContact</p>
        <p><label>Custom Field 2:</label> @Model.TypeViewModel.CustomFieldViewModel.EmailContact</p>
        <p><label>Custom Field 3:</label> @Model.TypeViewModel.CustomFieldViewModel.TextMessageContact</p>
        @if(@Model.TypeViewModel.CustomFieldViewModel.PhoneNumber != null) {
            <p><label>Phone Number:</label> @Model.TypeViewModel.CustomFieldViewModel.PhoneNumber</p>
        }
        <p><label>External Id:</label> @Model.TypeViewModel.ExternalId</p>
     </div>
</div>

问题原因及解决办法

核心问题1:RedirectToAction的模型传递机制

RedirectToAction是重定向操作,会发起新的GET请求。ASP.NET Core仅会将模型的顶级属性转换为URL查询参数,嵌套的ViewModel(如TypeViewModel、CustomFieldViewModel)无法被正确序列化,导致Verification方法接收到的嵌套模型为空。

核心问题2:视图表单字段命名错误

手动编写的input标签name属性带了Model.前缀(如Model.TypeViewModel.CustomFieldViewModel.Email),但正确的绑定命名应该去掉Model.,否则提交时嵌套字段无法正确绑定到MainViewModel。

解决步骤:

  1. 修复视图表单字段命名
    改用Html辅助方法生成字段,避免手动命名错误:

    <li> @Html.CheckBoxFor(m => m.TypeViewModel.CustomFieldViewModel.Email) 
        <span>Email</span> 
    </li>
    <li> @Html.CheckBoxFor(m => m.TypeViewModel.CustomFieldViewModel.Phone, new { onclick="ShowHideDiv(this)" })
        <span>Phone</span>
    </li>
    <li> @Html.CheckBoxFor(m => m.TypeViewModel.CustomFieldViewModel.Text, new { onclick="ShowHideDiv(this)" })
        <span>Text</span>
    </li>
    

    电话号码输入框修改为:

    @Html.TextBoxFor(m => m.TypeViewModel.CustomFieldViewModel.PhoneNumber, new { @class = "form-control", type = "tel" })
    
  2. 用TempData传递复杂模型
    因为RedirectToAction无法传递嵌套模型,改用TempData存储序列化后的模型:
    修改Submit方法:

    [HttpPost]
    public ActionResult Submit(MainViewModel model)
    {
        // 原有处理逻辑不变
        model.Id = Guid.NewGuid();
        model.TypeViewModel.Id = Guid.NewGuid();
        model.TypeViewModel.ExternalId = Guid.NewGuid();
        model.TypeViewModel.Name = model.TypeViewModel.Type ? "Yes, Contact me." : "No, Do not contact me.";
    
        model.TypeViewModel.CustomFieldViewModel.EmailContact = model.TypeViewModel.CustomFieldViewModel.Email ? "Contact by Email" : "Do Not Contact By Email";
        model.TypeViewModel.CustomFieldViewModel.PhoneNumberContact = model.TypeViewModel.CustomFieldViewModel.Phone ? "Contact by Phone Number" : "Do Not Contact By Phone Number";
        model.TypeViewModel.CustomFieldViewModel.TextMessageContact = model.TypeViewModel.CustomFieldViewModel.Text ? "Contact by Text Message" : "Do Not Contact By Text Message";
    
        // 序列化模型存入TempData
        TempData["MainModel"] = JsonSerializer.Serialize(model);
        return RedirectToAction("Verification");
    }
    

    修改Verification方法:

    public ActionResult Verification()
    {
        if (TempData["MainModel"] is string json)
        {
            var model = JsonSerializer.Deserialize<MainViewModel>(json);
            return View(model);
        }
        // 无数据时跳转回首页
        return RedirectToAction("Index");
    }
    
  3. 添加无参构造函数
    给每个ViewModel显式添加无参构造函数,避免后续模型绑定失败:

    public class MainViewModel
    {
        public MainViewModel() {}
        // 原有属性
    }
    
    public class TypesViewModel
    {
        public TypesViewModel() {}
        // 原有属性
    }
    
    public class CustomFieldsViewModel
    {
        public CustomFieldsViewModel() {}
        // 原有属性
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 15:17:39