Model binder does not populate items in nested lists

I have the following model:

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; } } } } 

A simplified controller is as follows:

 [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 } ... } 

The context of the problem is as follows:

  • The EditPolicy view is quite complex, where Knockout.JS is used to dynamically add / remove value elements, the input element looks like this:
 <input class="text-box single-line" type="text" data-bind="value: Data" name="Properties[@i].ValueItem" /> 

But when submitting the form, the JavaScript code updates the attributes of the name to have the correct names, for example 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"); } } 

The data from the HTTP request form in Fiddler looks like this (in WebForms mode):

Property Value Items

The raw HTTP request payload is as follows:

 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 
  • When the form is submitted to the server, the form data actually contains such fields, Fiddler confirms this. Moreover, I assigned (via ModelBinderAttribute ) a custom ModelBinderAttribute to see how the fields really ModelBinderAttribute with the model — yes, they do.
  • But when the binder creates a model instance by default, the Property instance has no elements in its Value list.
  • And the strangest thing: this problem arises from time to time, and it seems to depend on the number of elements of value. If the property has one value element, the Value list is likely to be populated, but with six element values, there are no elements inserted in the Value list.

Can anyone advise how to solve the problem? Thanks a lot in advance.

+4
source share
2 answers

Make sure numbering is continuous. Each missing Id causes all large identifiers to not fill in the model.

Specifically, I did a similar test on the MVC website and noticed that:

  • when I have identifiers 1, 2, 3, 4, 5, 6, 7 on my client, all the elements are correctly filled in the model
  • for identifiers 1, 2, 3, 5, 6, 7 only elements 1, 2 and 3 are filled in (5, 6 and 7 are lost due to the absence of 4).
+1
source

The following works great:

 @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> } 

and correctly attached to the following action:

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

The following information is transmitted by cable:

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

So, if this does not work for you, there may be another reason, such as a custom model binding that interferes with the default standard, or the payload of your request does not look like the one shown here.

+1
source

Source: https://habr.com/ru/post/1443587/


All Articles