0

i want to model bind this this data that is sent from the client

tag[15-d] : Little Owl
tag[19-a] : Merlin

name : value

into IEnumrable<AutoCompleteItem>

public class AutoCompleteItem
{
  public string Key { get; set; }
  public string Value { get; set; }
}

for example

Key = 15-d
Value = Little Owl

i don't know how to implement my own model binder in this scenario , any solution ?

Nadeem Khedr
  • 5,273
  • 3
  • 30
  • 37

2 Answers2

1

Here is a model binder that I did for you and does what you want. It by no means complete (no validation, no error checking etc), but it can kick start you. One thing I particularly dislike is that the ModelBinder directly accesses the form collection instead of using the ValueProvider of the context, but the latter doesn't let you get all bindable values.

public class AutoCompleteItemModelBinder : IModelBinder
{
    // Normally we would use bindingContext.ValueProvider here, but it doesn't let us
    // do pattern matching.
    public object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        string pattern =  @"tag\[(?<Key>.*)\]";
        if (!String.IsNullOrWhiteSpace (bindingContext.ModelName))
            pattern = bindingContext.ModelName + "." + pattern;

        IEnumerable<string> matchedInputNames = 
            controllerContext.HttpContext.Request.Form.AllKeys.Where(inputName => Regex.IsMatch(inputName, pattern, RegexOptions.IgnoreCase));

        return matchedInputNames.Select (inputName =>
            new AutoCompleteItem {
                Value = controllerContext.HttpContext.Request.Form[inputName],
                Key = Regex.Match(inputName, pattern).Groups["Key"].Value
            }).ToList();
    }
}

Here is a sample action that uses it:

[HttpPost]
public void TestModelBinder ([ModelBinder(typeof(AutoCompleteItemModelBinder))]
                             IList<AutoCompleteItem> items)
{
}

And a sample view. Note the "items." prefix - it's the Model Name (you can drop it depending on how you submit this list of items:

@using (Html.BeginForm ("TestModelBinder", "Home")) {
    <input type="text" name="items.tag[15-d]" value="Little Owl" />
    <input type="text" name="items.tag[19-a]" value="Merlin" />
    <input type="submit" value="Submit" />
}

If you have questions - add a comment and I will expand this answer.

Ivan Zlatev
  • 13,016
  • 9
  • 41
  • 50
  • sorry i have a question , if i am using a complex class and one of its properties is the `IList` how can i bind that property with that model binder and the rest with the default model binder ? – Nadeem Khedr Jun 09 '11 at 01:40
  • You register the ModelBinder in Global.asx in Application_Start via: `ModelBinders.Binders.Add(typeof(IList), new AutoCompleteItemModelBinder ());` – Ivan Zlatev Jun 09 '11 at 11:57
0

You should just be able to name your fields key[0], value[0] (1,2,3 etc) and it should bind automatically since these are just strings. If you need to customize this for some reason - still name your fields key[0] value[0] (then 1,2,3 etc) and do exactly as specified here: ASP.NET MVC - Custom model binder able to process arrays

Community
  • 1
  • 1
Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
  • i know but the i am not in control of the key it is not in sequence like 0 ,1 ,2 its 14-d , 19-a ,etc – Nadeem Khedr Jun 07 '11 at 17:03
  • ok.. then you need the other link I posted and your logic has to be built into the model binder to look for tag* items to parse out. – Adam Tuliper Jun 07 '11 at 17:50