Html.BeginForm传递多对象时参数值重复的问题及解决方法
这个问题的核心在于ASP.NET MVC模型绑定的工作逻辑,以及你当前Razor视图生成的HTML输入元素存在name属性重复的问题——模型绑定器无法区分哪个值对应控制器的model参数,哪个对应model1参数,最终导致两个参数拿到完全相同的值。
问题根源拆解
你原来的视图代码中,@Html.TextBoxFor(model => model.Number)会生成一个name="Number"的输入框,而@Html.TextBoxFor(model1 => model1.Number)同样会生成name="Number"的输入框。当表单提交时,浏览器会将两个同名参数发送到服务器,但模型绑定器无法区分归属,会把同一个值同时绑定到model.Number和model1.Number上,这就是你看到两个对象值完全相同的原因。
推荐解决方案:使用视图模型(ViewModel)
这是ASP.NET MVC处理复杂表单场景的最佳实践,通过创建一个专门的视图模型来封装你需要的两个Adress对象,让模型绑定器能清晰识别每个参数的归属。
步骤1:创建视图模型类
在项目中新增一个包含两个Adress属性的视图模型:
public class AdressPairViewModel { // 存储原始地址信息 public Adress OriginalAdress { get; set; } // 存储新地址信息 public Adress NewAdress { get; set; } }
步骤2:修改Razor视图
将视图的模型类型改为AdressPairViewModel,并通过强类型表达式生成正确的name属性:
@model AdressPairViewModel @using (Html.BeginForm("chAdress", "Adress", FormMethod.Post)) { <h4>原始地址</h4> @Html.LabelFor(model => model.OriginalAdress.Number) @Html.TextBoxFor(model => model.OriginalAdress.Number) @Html.ValidationMessageFor(model => model.OriginalAdress.Number) @Html.LabelFor(model => model.OriginalAdress.Distance) @Html.TextBoxFor(model => model.OriginalAdress.Distance) @Html.ValidationMessageFor(model => model.OriginalAdress.Distance) <h4>新地址</h4> @Html.LabelFor(model => model.NewAdress.Number) @Html.TextBoxFor(model => model.NewAdress.Number) @Html.ValidationMessageFor(model => model.NewAdress.Number) @Html.LabelFor(model => model.NewAdress.Distance) @Html.TextBoxFor(model => model.NewAdress.Distance) @Html.ValidationMessageFor(model => model.NewAdress.Distance) <button type="submit">修改地址</button> }
此时生成的输入框name属性会是OriginalAdress.Number和NewAdress.Number,模型绑定器能准确区分归属。
步骤3:修改控制器方法
将控制器的参数改为接收AdressPairViewModel:
public void chAdress(AdressPairViewModel viewModel) { prepareConnection(); string distance = viewModel.OriginalAdress.Distance.ToString(); string newDistance = viewModel.NewAdress.Distance.ToString(); Dictionary<string, object> queryDict = new Dictionary<string, object>(); queryDict.Add("distance", distance); queryDict.Add("newDistance", newDistance); var query = new Neo4jClient.Cypher.CypherQuery( "start n=node(*) where (n:Adress) and exists(n.distance) and n.distance =~ {distance} set n.distance = {newDistance} return n", queryDict, CypherResultMode.Set ); List<Adress> adrese = ((IRawGraphClient)client).ExecuteGetCypherResults<Adress>(query).ToList(); }
备选方案:手动指定输入框name属性
如果不想创建视图模型,也可以直接手动指定输入框的name属性,让模型绑定器识别对应参数:
@using (Html.BeginForm("chAdress", "Adress", FormMethod.Post)) { @Html.Label("Number") @Html.TextBox("model.Number", Model?.Number) @Html.ValidationMessage("model.Number") @Html.Label("Distance") @Html.TextBox("model.Distance", Model?.Distance) @Html.ValidationMessage("model.Distance") @Html.Label("New Number") @Html.TextBox("model1.Number") @Html.ValidationMessage("model1.Number") @Html.Label("New Distance") @Html.TextBox("model1.Distance") @Html.ValidationMessage("model1.Distance") <button type="submit">修改地址</button> }
这种方式无需修改控制器,但强类型支持和验证体验不如视图模型方案。
内容的提问来源于stack exchange,提问作者Milos Stamenkovic

