模型绑定器不会填充嵌套列表中的项目

时间:2012-11-02 05:46:16

标签: c# razor asp.net-mvc-4 model-binding

我有以下型号:

public class ConfigurationPolicyModel
{
    public ConfigurationPolicyModel()
    {
        Properties = new List<Property>();
    }

    public List<Property> Properties { get; set; }

    public class Property
    {
        public Property()
        {
            Value = new List<ValueItem>();
        }

        public List<ValueItem> Value { get; set; }

        public class ValueItem
        {
            public string Data { get; set; }
        }
    }
}

简化控制器如下:

[HttpPost]
public ActionResult EditPolicy(ConfigurationPolicyModel model)
{
    foreach (var prop in model.Properties)
    {
        var n = prop.Value.Count; // The problem is here: prop.Value is empty
    }
    ...
}

问题背景如下:

  • EditPolicy视图足够复杂,其中Knockout.JS用于动态添加/删除值项,输入元素如下所示:
<input class="text-box single-line" type="text" data-bind="value: Data" name="Properties[@i].ValueItem" />

但是在表单提交时,JavaScript代码会更新名称属性,使其具有正确的名称,如Properties[0].Value[0].Data

for (var i = 0; i < viewModel.properties().length; ++i)
{
    var valueItems = $('input[name="Properties[' + i + '].ValueItem"]');

    for (var j = 0; j < valueItems.length; ++j)
    {
        $(valueItems[j]).attr("name", "Properties[" + i + "].Value[" + j + "].Data");
    }
}

Fiddler中HTTP请求的表单数据如下所示(在WebForms模式下):

Property Value Items

HTTP请求的原始有效负载如下:

Id=00000000-0000-0000-0000-000000000000&Level=Platform&Name=SmsPolicy&InheritanceLevels[0].Level=SafeCenter&InheritanceLevels[0].InheritanceType=Force&InheritanceLevels[1].Level=TeamSafe&InheritanceLevels[1].InheritanceType=Force&Properties[0].Name=Providers&Properties[0].ValueIsSequence=True&Properties[0].Value[0].Data=O2&Properties[0].Value[1].Data=Telecom&Properties[0].Value[2].Data=&Properties[0].Value[3].Data=&Properties[0].Minimum=&Properties[0].Maximum=&Targets[0].Level=Platform&Targets[0].Name=Platform&Targets[0].Selected=true&Targets[0].Selected=false&Targets[1].Level=SafeCenter&Targets[1].Name=SafeCenters&Targets[1].Selected=true&Targets[1].Selected=false&Targets[1].Items[0].Level=SafeCenter&Targets[1].Items[0].OwnerId=7292f9aa-b168-43ab-83a7-db193599d02f&Targets[1].Items[0].Name=Google+Inc.&Targets[1].Items[0].Selected=true&Targets[1].Items[0].Selected=false&Targets[1].Items[1].Level=SafeCenter&Targets[1].Items[1].OwnerId=6c481d66-0ece-4269-8256-c02d3b8c5109&Targets[1].Items[1].Name=SC11&Targets[1].Items[1].Selected=true&Targets[1].Items[1].Selected=false&Targets[1].Items[2].Level=SafeCenter&Targets[1].Items[2].OwnerId=9afd1968-6742-435d-919e-36068ff4b235&Targets[1].Items[2].Name=SC2&Targets[1].Items[2].Selected=true&Targets[1].Items[2].Selected=false&Targets[1].Items[3].Level=SafeCenter&Targets[1].Items[3].OwnerId=995813e1-91d4-4fad-bf10-fbafa0354cbb&Targets[1].Items[3].Name=SC4&Targets[1].Items[3].Selected=true&Targets[1].Items[3].Selected=false&Targets[1].Items[4].Level=SafeCenter&Targets[1].Items[4].OwnerId=acbd68a8-cb9b-4e50-8eeb-59b374fedae0&Targets[1].Items[4].Name=SC5&Targets[1].Items[4].Selected=true&Targets[1].Items[4].Selected=false&Targets[2].Level=TeamSafe&Targets[2].Name=TeamSafes&Targets[2].Selected=true&Targets[2].Selected=false
  • 当表单发布到服务器时,表单数据实际上包含这些字段,Fiddler确认这一点。此外,我指定(通过ModelBinderAttribute)自定义模型绑定器来观察字段实际到达模型绑定器, - 是的,他们这样做。
  • 但是当默认绑定器创建模型的实例时,Property实例的Value列表中没有项目。
  • 最奇怪的一点是:这个问题一次又一次地出现,似乎取决于有价物品的数量。如果属性具有一个值项,则Value列表可能已填充,但如果有六个值项,则Value列表中不会插入任何项。

有人可以建议如何解决问题吗?非常感谢你提前。

2 个答案:

答案 0 :(得分:1)

确保编号是连续的。 跳过的每个Id都会导致模型中没有填充所有更大的ID。

具体而言,我在MVC网站上进行了类似的测试并注意到:

  • 当我在客户端上时,Ids 1,2,3,4,5,6,7所有元素都在模型中正确填充
  • 对于Ids 1,2,3,5,6,7仅填充元素1,2和3(由于缺少4,因此丢失了5,6和7)。

答案 1 :(得分:1)

以下工作正常:

@using (Html.BeginForm())
{
    <input type="text" name="Properties[0].Value[0].Data" value="O2" />
    <input type="text" name="Properties[0].Value[1].Data" value="Telecom" />
    <input type="text" name="Properties[0].Value[2].Data" value="" />
    <input type="text" name="Properties[0].Value[3].Data" value="" />

    <button type="submit">OK</button>
}

并正确绑定到以下操作:

[HttpPost]
public ActionResult EditPolicy(ConfigurationPolicyModel model)
{
    return View();
}

通过网络发送以下有效负载:

Properties[0].Value[0].Data = O2
Properties[0].Value[1].Data = Telecom
Properties[0].Value[2].Data =
Properties[0].Value[3].Data =

因此,如果这对您不起作用,可能还有其他一些原因,例如自定义模型绑定器会干扰默认约定,或者您的请求有效负载看起来不像此处所示。