MVC中Controller-View-Controller流程丢失数据,如何从View正确获取Model?
这个问题的核心是ASP.NET MVC的ModelBinder无法自动识别整个List@Html.HiddenFor(model => model.Points)的方式,只会生成一个名为Points的隐藏字段,值是列表的字符串表示(比如System.Collections.Generic.List1[System.Drawing.Point]`),ModelBinder根本没法把这个字符串转换成有效的List
下面给你两种可行的解决方案:
方案一:为每个Point的属性生成隐藏字段(推荐)
这是最符合MVC ModelBinder工作逻辑的方式,直接在表单内部循环你的Points列表,为每个Point的X、Y坐标生成对应的隐藏字段:
@using (Html.BeginForm("DrawTranslatingCam", "Home")) { <!-- 你的Cam属性输入项保持不变 --> @Html.LabelFor(model => model.Cam.Rmin, htmlAttributes: new { @class = "control-label col-md-2" }) @Html.EditorFor(model => model.Cam.Rmin, new { htmlAttributes = new { @class = "form-control" } }) // 其他Cam属性的类似代码 <!-- 新增:为每个Point生成隐藏字段 --> @for (int i = 0; i < Model.Points.Count; i++) { @Html.HiddenFor(m => m.Points[i].X) @Html.HiddenFor(m => m.Points[i].Y) } <input type="submit" value="Draw" /> }
这样生成的HTML字段会是类似Points[0].X、Points[0].Y、Points[1].X这样的命名,ModelBinder会自动识别这些字段,把它们重新组装成完整的ListDrawTranslatingCam方法里拿到完整的Points数据了。而且这个方案扩展性很好,以后如果要支持用户修改Points,只需要把HiddenFor换成EditorFor就行,结构完全兼容。
方案二:序列化Points为JSON存储(适合大数据量场景)
如果你的Points列表非常大,生成大量隐藏字段会导致HTML体积过大,可以考虑把整个列表序列化成JSON字符串,存在一个单独的隐藏字段里,然后在Action里手动反序列化:
View部分:
@using (Html.BeginForm("DrawTranslatingCam", "Home")) { <!-- Cam属性输入项不变 --> @Html.LabelFor(model => model.Cam.Rmin, htmlAttributes: new { @class = "control-label col-md-2" }) @Html.EditorFor(model => model.Cam.Rmin, new { htmlAttributes = new { @class = "form-control" } }) // 其他Cam属性的类似代码 <!-- 序列化Points为JSON隐藏字段 --> @Html.Hidden("PointsJson", Json.Encode(Model.Points)) <input type="submit" value="Draw" /> }
Controller部分:
using System.Web.Script.Serialization; public ActionResult DrawTranslatingCam(TranslatingCamModel model, string PointsJson) { if (!string.IsNullOrEmpty(PointsJson)) { var serializer = new JavaScriptSerializer(); model.Points = serializer.Deserialize<List<Point>>(PointsJson); } // 后续处理逻辑 }
这个方法要注意两点:一是确保你的Point类可以被正常序列化(比如没有无参构造函数或者非公共属性的话可能会有问题);二是如果Points包含敏感数据,要注意防范XSS风险,不过你的场景里Points是可视化用的,应该没问题。
内容的提问来源于stack exchange,提问作者v.slobodzian

