Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC model binding to nested classes

When I try and create a new 'Flow' class the nested classes ('Action') always come back as null in the controller

So I have classes within classes like so:

public class Flow
{
    private Action actionField
    private string nameField
    private bool enabledField
    ...
}

public class Action
{
    private ActionSchedule actionScheduleField
    private ActionParameter actionParameterField
    private nameField
}
public class ActionSchedule
...

And a single create view for a 'Flow'

@model ProjectZeus.Models.Flow
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)

   @Html.TextBoxFor(model => model.name, new { @placeholder = "Flow name" })
   @Html.ValidationMessageFor(model => model.name)


   @Html.LabelFor(model => model.enabled)

   @Html.EditorFor(model => model.enabled)
   @Html.ValidationMessageFor(model => model.enabled)

@Html.Partial("FlowAction")
...

and then partial views for each of the subclasses

@model ProjectZeus.Models.FlowAction

    @Html.TextBoxFor(model => model.name, new { @placeholder = "Action name" })
    ...

I've tried creating instances of the classes and calling the view - error,

I've tried creating instances of the classes in the views themselves - error,

I've tried not using PartialViews:

@Html.TextBoxFor(model => model.action.name, new { @placeholder = "Action name" })

I've googled and googled and googleedddd but with no luck, help please!?

Edit:

Implementing a customer model binder seems like overkill. This page describes the same problem but the solution code won't compile for me ‘The name ‘helper’ does not exist in the current context’? - http://danielhalldev.wordpress.com/2013/08/23/partial-views-and-nested-mvc-model-binding/

Edit2:

I changed the model defintions for brevity - the model is actually auto generated from an xsd:

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class D53ESBFlow
{

    private D53ESBFlowAction actionField;

    [Required]
    private string nameField;

    ...

    private bool enabledField;

    /// <remarks/>
    public D53ESBFlowAction action
    {
        get
        {
            return this.actionField;
        }
        set
        {
            this.actionField = value;
        }
    }
    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string name
    {
        get
        {
            return this.nameField;
        }
        set
        {
            this.nameField = value;

Edit 3 (bump):

It looks like the 'binder'is creating a property and not a class object? whereRu

like image 413
Jimmy Avatar asked Jul 11 '14 13:07

Jimmy


People also ask

Does MVC use data binding?

MVC doesn't use data bindings like old web api. You have to use model bindings in a MVC or MVVM approach.

What is bind property in MVC?

Model binding allows you map request parameters to actions. This means action methods will have one or more parameters and those parameters will receive their values from the model binding framework.

What is model binding in C#?

Model binding is a simplistic way to correlate C# code with an HTTP request. The model binding applies to transforming the HTTP request data in the query's form string and form collection of the action method parameters. We can consider these parameters to be primitive type or complex type.


2 Answers

Did you forget the { get; set; } accessors on the property names?

like image 98
niico Avatar answered Oct 21 '22 18:10

niico


I had a similar issue with MVC 5, .NET 4.5, Visual Studio 2013.

Here's what worked for me: Add a constructor so the contained class gets instantiated, make them properties (not variables) like AntoineLev said, and add the class to the Binding:

public class Flow
{
    public Action actionField {get; set; }

    public class Flow()
    {
        actionField = new Action();  // otherwise it shows up as null
    }
}

In your controller, Add the the whole class in the binding:

public ActionResult Create([Bind(Include="action,name,enabled")] Flow flow)
{
   ... 
}

Your Mileage may vary.

}

like image 1
TomEberhard Avatar answered Oct 21 '22 18:10

TomEberhard