System.Web.Mvc.FormValueProvider uses System.Web.PrefixContainer class, which applies binary search algo to determine a prefix is contained in the container. But using binary search for prefixes seems incorrect. In my case,
the PrefixContainer has the following sorted list of form fields:
The DefaultModelBinder is creating an instance of model and asks
FormValueProvider for Property[0].Value prefix to fill
Value list in a property (which is the first item in property list). Binary search algo makes first probing to item #21 (Targets[1].Items[0].Selected) and determines that the prefix value is less. So next probing is item #10 (Properties[0].ValueIsSequence)
and it is less as well, so the 3rd probing is item #4 (InheritanceLevel[1].Level) etc. Fields such as
Properties[0].Value[n].Data never detected, and Value list of a property is not filled at all, though form fields actually exist.
Please correct me, but imho this seems like a bug? Or this is some design feature? Please advise.
No, I don't, all form field names are unique, no gaps in indicies for list items.
Taking into consideration the screenshot, the problem is that System.Web.PrefixContainer.IsPrefixMatch() method, looking for
Properties[0].Value prefix, expects a name starting with "Properties[0].Value[" or
"Properties[0].Value." but it detects Properties[0].ValueIsSequence that does not match and binary search in
System.Web.PrefixContainer.ContainsPrefix() moves to incorrect dicrection.
Probably I wrote the initial post in confusing style, but I described possible bug in MVC 4 code, not in mine.
The story began that I detected my model is not filled properly. I used Fiddler, verified HTTP request payload, form fields naming, checked the C# model classes/properties - from my side anything was correct.
Then I installed .NET Reflector add-in for VS to debug the MVC 4 behavior, and detected the possible bug in internal
System.Web.PrefixContainer class, which skips form fields when they are actually provided (more precise place of the bug is System.Web.PrefixContainer.IsPrefixMatch() method).
The screenshot in the inital post is a dump of internal sorted array in
System.Web.PrefixContainer class, and System.Web.PrefixContainer fails on such data set - it never detects
Properties[0].Value[*].Data fields because of presence Properties[0].ValueIsSequence and the bug in System.Web.PrefixContainer.IsPrefixMatch() method.
The bug is reproduced with the following model, view and controller action method:
public class Model
{
public Model()
{
Value = new List<Item>();
}
public string SomeData { get; set; }
public string ValueIsSequence { get; set; }
public class Item
{
public string Data { get; set; }
}
public List<Item> Value { get; set; }
}
[HttpPost]
public ActionResult Testing(Model model)
{
var failed = model.Value.Count == 0;
return View();
}
Model.Value list is empty (incorrect behavior), but if rename
ValueIsSequence to IsSequence for example, the
Model.Value list will be filled with one item with Data = "ABC" (correct behavior).
strange. perhaps you are doing something in global.asax to prevent your model from binding properly?
This code works fine in mvc3, will try in mvc4
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers {
public class HomeController : Controller {
public ActionResult Index() {
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About() {
return View();
}
[HttpGet]
public ActionResult Testing() {
return View();
}
[HttpPost]
public ActionResult Testing(Model model) {
var failed = model.Value.Count == 0;
return View();
}
}
}
public class Model {
public Model() {
Value = new List<Item>();
}
public string SomeData { get; set; }
public string ValueIsSequence { get; set; }
public class Item {
public string Data { get; set; }
}
public List<Item> Value { get; set; }
}
@using (Html.BeginForm())
{
<input type="text" name="SomeData" value="123" />
<input type="text" name="ValueIsSequence" value="True" />
<input type="text" name="Value[0].Data" value="ABC" />
<button type="submit">OK</button>
}
MaxNo
Member
12 Points
7 Posts
FormValueProvider skips form values
Nov 05, 2012 11:32 AM|LINK
System.Web.Mvc.FormValueProvider uses System.Web.PrefixContainer class, which applies binary search algo to determine a prefix is contained in the container. But using binary search for prefixes seems incorrect. In my case, the PrefixContainer has the following sorted list of form fields:
The DefaultModelBinder is creating an instance of model and asks FormValueProvider for Property[0].Value prefix to fill Value list in a property (which is the first item in property list). Binary search algo makes first probing to item #21 (Targets[1].Items[0].Selected) and determines that the prefix value is less. So next probing is item #10 (Properties[0].ValueIsSequence) and it is less as well, so the 3rd probing is item #4 (InheritanceLevel[1].Level) etc. Fields such as Properties[0].Value[n].Data never detected, and Value list of a property is not filled at all, though form fields actually exist.
Please correct me, but imho this seems like a bug? Or this is some design feature? Please advise.
Xequence
Contributor
4313 Points
1528 Posts
Re: FormValueProvider skips form values
Nov 05, 2012 03:38 PM|LINK
do you have duplicate id's in your object?
Credentials
MaxNo
Member
12 Points
7 Posts
Re: FormValueProvider skips form values
Nov 06, 2012 04:08 AM|LINK
No, I don't, all form field names are unique, no gaps in indicies for list items.
Taking into consideration the screenshot, the problem is that System.Web.PrefixContainer.IsPrefixMatch() method, looking for Properties[0].Value prefix, expects a name starting with "Properties[0].Value[" or "Properties[0].Value." but it detects Properties[0].ValueIsSequence that does not match and binary search in System.Web.PrefixContainer.ContainsPrefix() moves to incorrect dicrection.
Xequence
Contributor
4313 Points
1528 Posts
Re: FormValueProvider skips form values
Nov 06, 2012 02:41 PM|LINK
Hope this helps.
Credentials
MaxNo
Member
12 Points
7 Posts
Re: FormValueProvider skips form values
Nov 07, 2012 09:10 AM|LINK
Probably I wrote the initial post in confusing style, but I described possible bug in MVC 4 code, not in mine.
The story began that I detected my model is not filled properly. I used Fiddler, verified HTTP request payload, form fields naming, checked the C# model classes/properties - from my side anything was correct.
Then I installed .NET Reflector add-in for VS to debug the MVC 4 behavior, and detected the possible bug in internal System.Web.PrefixContainer class, which skips form fields when they are actually provided (more precise place of the bug is System.Web.PrefixContainer.IsPrefixMatch() method).
The screenshot in the inital post is a dump of internal sorted array in System.Web.PrefixContainer class, and System.Web.PrefixContainer fails on such data set - it never detects Properties[0].Value[*].Data fields because of presence Properties[0].ValueIsSequence and the bug in System.Web.PrefixContainer.IsPrefixMatch() method.
ignatandrei
All-Star
135047 Points
21654 Posts
Moderator
MVP
Re: FormValueProvider skips form values
Nov 07, 2012 09:42 AM|LINK
Could you provide a simple example, with less fields?
MaxNo
Member
12 Points
7 Posts
Re: FormValueProvider skips form values
Nov 07, 2012 11:15 AM|LINK
The bug is reproduced with the following model, view and controller action method:
public class Model { public Model() { Value = new List<Item>(); } public string SomeData { get; set; } public string ValueIsSequence { get; set; } public class Item { public string Data { get; set; } } public List<Item> Value { get; set; } }@using (Html.BeginForm()) { <input type="text" name="SomeData" value="123" /> <input type="text" name="ValueIsSequence" value="True" /> <input type="text" name="Value[0].Data" value="ABC" /> <button type="submit">OK</button> }[HttpPost] public ActionResult Testing(Model model) { var failed = model.Value.Count == 0; return View(); }Model.Value list is empty (incorrect behavior), but if rename ValueIsSequence to IsSequence for example, the Model.Value list will be filled with one item with Data = "ABC" (correct behavior).
Xequence
Contributor
4313 Points
1528 Posts
Re: FormValueProvider skips form values
Nov 07, 2012 01:36 PM|LINK
strange. perhaps you are doing something in global.asax to prevent your model from binding properly?
This code works fine in mvc3, will try in mvc4
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MvcApplication1.Models; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!"; return View(); } public ActionResult About() { return View(); } [HttpGet] public ActionResult Testing() { return View(); } [HttpPost] public ActionResult Testing(Model model) { var failed = model.Value.Count == 0; return View(); } } } public class Model { public Model() { Value = new List<Item>(); } public string SomeData { get; set; } public string ValueIsSequence { get; set; } public class Item { public string Data { get; set; } } public List<Item> Value { get; set; } } @using (Html.BeginForm()) { <input type="text" name="SomeData" value="123" /> <input type="text" name="ValueIsSequence" value="True" /> <input type="text" name="Value[0].Data" value="ABC" /> <button type="submit">OK</button> }My model has the same problems as you described, model.Value.Count = 0
Credentials
MaxNo
Member
12 Points
7 Posts
Re: FormValueProvider skips form values
Nov 07, 2012 03:19 PM|LINK
MVC 3 and MVC 4 have different implementation of System.Web.Mvc.FormValueProvider class, so the bug seems to be specific to MVC 4.
Probably internal System.Web.PrefixContainer class was introduced in MVC 4, and it has this bug.
yinchang
Member
2 Points
3 Posts
Re: FormValueProvider skips form values
Dec 07, 2012 02:41 AM|LINK
Is this question ready to correct ??