为什么IList的UpdateModel()绑定不起作用,但作为方法参数却起作用

本文关键字:方法 参数 起作用 不起作用 IList UpdateModel 绑定 为什么 | 更新日期: 2023-09-27 18:20:33

我有一个简单的类:

[Serializable]
public class RatePerPurpose
{
    public int ValueId { get; set; }
    public double Rate { get; set; }
}

,和简单的数据到POST:

<input type="hidden" name="[0].ValueId" value="1" />
<input type="hidden" name="[0].Rate" value="2.34" />
<input type="hidden" name="[1].ValueId" value="10" />
<input type="hidden" name="[1].Rate" value="20.34" />

这工作没有任何问题:

[HttpPost]
public virtual ActionResult MyActionPost(List<RatePerPurpose> rates)
{
  // no problem, this works
}

我的问题是,为什么这些不起作用(我已经测试了ASP.NET MVC 5)?或者如何改变这一点,让它发挥作用?

[HttpPost]
public virtual ActionResult MyActionPost()
{
  List<RatePerPurpose> rates = new List<RatePerPurpose>();
  this.UpdateModel(rates);
  // This DOES NOT work, 'rates' is empty :-(
  this.UpdateModel(rates, prefix:"");
  // Setting 'none' prefix, also DOES NOT work. 'rates' is still empty
}

PS:我也测试过List<>IList<>,但出现了同样的问题。

为什么IList的UpdateModel()绑定不起作用,但作为方法参数却起作用

问题是在第二个示例中,您有一个空列表。UpdateModel将更新项目(如果存在),并且它可以找到相关性,但它不会为您填充空列表。如果你做了这样的事情:

var rates = db.RatePerPurposes.ToList();
UpdateModel(rates);

可能会起作用,假设它可以将POST主体中的RatePerPurpose实例与数据库返回的RatePerPurpose实例相匹配。

我终于想通了(经过三天的不眠之夜)。实际上有两个问题。

问题1

在我的应用程序的global.asax上调用Application_Start:时,出现了DoubleModelBinder漏洞

...
ModelBinders.Binders.Add(typeof(double), new DoubleModelBinder());
...

该粘合剂依赖于UICulture,因此从作用方法参数进行绑定是有效的。但MyActionPost()的身体有不同的文化,所以我的DoubleModelBinder抛出了一些内部异常。有点奇怪的是,这个异常没有从UpdateModel()传播出去。

问题2

像在我的例子中那样使用UpdateModel()(或TryUpdateModel())是非常好的。我在Adam Freeman的一本书Pro ASP.NET MVC 5(第654页)中也发现了类似的例子,但"正确"的版本应该使用FormCollection作为操作方法参数。因此,工作示例:

[HttpPost]
public virtual ActionResult MyActionPost(FormCollection form)
{
  List<RatePerPurpose> rates = new List<RatePerPurpose>();
  this.UpdateModel(rates, "MyList", form);
  // This works, 'rates' is binded properly
}

PS:

还有最后一条建议。绑定集合时使用.Index。(当索引从0开始并且项目之间没有间隙时,这不是必需的,但我现在可以睡得更好了。:)所以数据应该是这样的:

<input type="hidden" name="MyList.Index" value="0" />
<input type="hidden" name="MyList[0].ValueId" value="1" />
<input type="hidden" name="MyList[0].Rate" value="2.34" />
<input type="hidden" name="MyList.Index" value="1" />
<input type="hidden" name="MyList[1].ValueId" value="10" />
<input type="hidden" name="MyList[1].Rate" value="20.34" />