5

I'm trying to get custom model binding to work, but for some reason the values aren't set. The code seems ligit when comparing it to working code, but still it doesnt bind. I guess it some trivial thing i'm missing.

Custom model:

//Cluster is from Entity Framework

//BaseViewModelAdmin defines:
public List<KeyValuePair<string, string>> MenuItems;
public IPrincipal CurrentUser = null;
public Foundation Foundation; //also from Entity Framework

public class AdminClusterCreateModel : BaseViewModelAdmin
{
    public Cluster Item;
    public AdminClusterCreateModel()
    {
        Item = new Cluster();
    }
}

The view form looks like:

@using (Html.BeginForm()) {
  @Html.ValidationSummary(true)

  <fieldset>
      <legend>Cluster</legend>

      <div class="editor-label">
          @Html.LabelFor(model => model.Item.Active)
      </div>
      <div class="editor-field">
          @Html.EditorFor(model => model.Item.Active)
          @Html.ValidationMessageFor(model => model.Item.Active)
      </div>


      <div class="editor-label">
          @Html.LabelFor(model => model.Item.Name)
      </div>
      <div class="editor-field">
          @Html.EditorFor(model => model.Item.Name)
          @Html.ValidationMessageFor(model => model.Item.Name)
      </div>

      <p>
          <input type="submit" value="Create" />
      </p>
  </fieldset>
}

And the controller:

[HttpPost]
public ActionResult Create(AdminClusterCreateModel model, FormCollection form)
{
    if(ModelState.IsValid) //true
    {
        var test = form["Item.Name"]; //Value is correct from form (EG: Test)
        UpdateModel(model);  //no error
    }

    //At this point model.Item.Name = null <--- WHY?

    return View(model);
}

Cluster on request

public partial class Cluster
{
    public Cluster()
    {
        this.Team = new HashSet<Team>();
    }

    public long Id { get; set; }
    public System.DateTime Created { get; set; }
    public System.DateTime Modified { get; set; }
    public bool Active { get; set; }
    public long FoundationId { get; set; }
    public string Name { get; set; }

    public virtual Foundation Foundation { get; set; }
    public virtual ICollection<Team> Team { get; set; }
}
14
  • 1
    Can we see your Cluster class? Is Item.Name definitely a public property rather than a public field? It's been a while but IIRC it will only bind to properties. Commented Apr 16, 2013 at 10:58
  • I've added it to the question Commented Apr 16, 2013 at 11:16
  • Have you checked if there is something in UpdateModel that updates model.Item? Commented Apr 16, 2013 at 11:26
  • 1
    @HugoDelsing by default 'DefaultModelBinder' comes into play and constructs the object in action method parameter from 'FormCollection'. There is a way to alter binding works for a specific type by 'Custom Model Binder'(relevant codeproject.com/Articles/228826/ASP-NET-MVC-Model-Binders). I asked about it because maybe i misread 'I'm trying to get custom model binding to work'. Now i think there is no 'Custom Binder' and 'DefaultModelBinder' is still playing the role. In that case you might want to change 'public Cluster Item;' to 'public Cluster Item {get; set;};' to make it work. Commented Apr 17, 2013 at 8:39
  • 1
    Thanks! Indeed public Cluster Item {get; set;} was enough to make it work. My apoligies for the misleading info. I was binding to a custom model, so thats why I used that term. if you post it as an answer I will accept it. Commented Apr 17, 2013 at 9:10

2 Answers 2

10

DefaultModelBinder works explicitly on 'Properties', not on 'Fields'

Changing public Cluster Item to public Cluster Item {get; set;} in AdminClusterCreateModel should do the trick.

public class AdminClusterCreateModel : BaseViewModelAdmin
{
    public Cluster Item {get; set;}

    public AdminClusterCreateModel()
    {
        Item = new Cluster();
    }
 }

Regards

Sign up to request clarification or add additional context in comments.

Comments

0

This is a trivial and a corner case, yet if it might help someone:

If your model has a property, named model this to will cause the DefaultModelBinder to return a null.

public class VehicleModel
{
    public string Model { get; set; }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.