locked
FormValueProvider skips form values RRS feed

  • Question

  • User-1712691489 posted

    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. 

    Monday, November 5, 2012 7:32 AM

All replies

  • User1080785583 posted

    do you have duplicate id's in your object?

    Monday, November 5, 2012 11:38 AM
  • User-1712691489 posted

    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. 

    Tuesday, November 6, 2012 12:08 AM
  • User1080785583 posted
    1. use fiddler to detect your header request and parse the values to see if they are what you require
    2. if you want to binary search your properties, then they must all exist, please provide your object and  html
    3. is your properties nullable? it almost sounds as if you would require IComparable

    Hope this helps.

    Tuesday, November 6, 2012 10:41 AM
  • User-1712691489 posted

    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. 

    Wednesday, November 7, 2012 5:10 AM
  • User197322208 posted

    but I described possible bug in MVC 4 code, not in mine

    Could you provide a simple example, with less fields?

    Wednesday, November 7, 2012 5:42 AM
  • User-1712691489 posted

    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). 

    Wednesday, November 7, 2012 7:15 AM
  • User1080785583 posted

    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>
    }
    
    mvc3 querystring:
    SomeData=123&ValueIsSequence=True&Value%5B0%5D.Data=ABC
    
    mvc4 querystring:
    SomeData=123&ValueIsSequence=True&Value%5B0%5D.Data=ABC

    My model has the same problems as you described, model.Value.Count = 0

    Wednesday, November 7, 2012 9:36 AM
  • User-1712691489 posted

    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. 

    Wednesday, November 7, 2012 11:19 AM
  • User-1397638033 posted

    Is this question ready  to correct ??

    Thursday, December 6, 2012 10:41 PM
  • User-1712691489 posted

    This is a real bug in MVC4, registered as issue #616 in the ASP.NET MVC issue tracker, resolving in progress.

    Thursday, December 6, 2012 10:50 PM
  • User401360897 posted

    Nice finding. Just install ImranB.ModelBindingFix package and add this line in Application_Start, Fixer.FixModelBindingIssue(); You can find the details at here.

    Saturday, December 8, 2012 9:11 AM
  • User119035498 posted

    This bug is now fixed in the next release of MVC and Web API (MVC5, Web API 2), and is also available in the nightly build at: https://www.myget.org/gallery/aspnetwebstacknightly.

    Tuesday, September 10, 2013 5:55 PM