Web API + MVC 4 regarding model binding of complex types

Go To StackoverFlow.com

1

I have the following classes:

public class State
{
    public long Id                    { get; set; }
    public string Name                { get; set; }
    public string Abbreviation        { get; set; }

    // Navigation Properties
    public virtual Country Country    { get; set; }
}

public class School
{
    public long Id                    { get; set; }
    public string Name                { get; set; }
    public string Abbreviation        { get; set; }

    // Navigation Properties
    public virtual State State        { get; set; }
}

and the following data in my SQL Server

| School|             |               |
|  Id   | Name        |    State      |
|  1    | UCLA        |      1        |
+-------+-------------+---------------+
| State |             |               |
|  Id   | Name        | Abbreviation  |
|  1    | California  |      CA       |

I'm attempting to create a Rest controller that creates an instance of school using the HTTP POST verb using Web API.

public HttpResponseMessage<School> Post( School school )
{
    SchoolService.CreateSchool( school );
    var response = new HttpResponseMessage<School>( school, HttpStatusCode.Created );
    string uri = Url.Route( null, new { id = school.Id } );

    response.Headers.Location = new Uri( Request.RequestUri, uri );
    return response;
}

Web API properly binds my School class's Name and Abbreviation properties from my web form and calls the POST method in the controller, but it doesn't know what to do with the State class. I'm not quite sure how to set that up. I'd like to have a dropdown that is bound to the State class and when I submit the creation of the School, the correct state from my existing data will get assigned to the new school instance.

2012-04-03 21:44
by khaihon
How do you submit the value for Store class? can you post the HTTP Request details (headers, form fields & values, etc.) - tugberk 2012-04-04 08:28
I'm having the same issue; I'm XML deserializing a complex type in a POST and it tries going for ModelBinders instead of the default XmlMediaTypeFormatter. There is mention that JSON works fine for this - are you using XML or JSON Serialization - Steve 2012-04-25 15:34


1

First of all, your domain model design is a little rough. Your School table should have a FK to State table and you should have that inside your POCO classes as well:

public class School
{
    public long Id                    { get; set; }
    public long StateId               { get; set; }
    public string Name                { get; set; }
    public string Abbreviation        { get; set; }

    // Navigation Properties
    public virtual State State        { get; set; }
}

Then you should have a form field as similar to below:

<select id="StateId" name="StateId">
    <option value="">Select a State</option>
    <option value="310">CA</option>
    <option value="311">NY</option>
</select>
2012-04-04 08:37
by tugberk
Hi Tugberk, In my previous iterations, I would have a ViewModel of School that includes the FK. Since Web API was introduced, I wanted to attempt to do this without using FKs and without a viewmodel class altogether, hoping there would be some way to bind complex types, such as State in this case. I guess my question is if it is possible to implement it this way without using FKs and if so, how to set up the Post method and how to submit the value for state. I may have to wind up doing it the FK/viewmodel way if it's not possible - khaihon 2012-04-04 16:52


0

In my current project I have achieved something similar using following approach:

I have a Device class (POCO) and a DeviceCommand class (POCO). Device can have many commands and each command will have exactly one device.

I did not bother with ViewModel and POCO classes are used between layers.

public class Device
{
    [Key]
    public int ID { get; set; }

    public int DeviceID { get; set; }

    public bool IsActive { get; set; }

    // Navigational properties
    public ICollection<DeviceCommand> CommandList { get; set; }
}

And

public class DeviceCommand
{
    public int Id { get; set; }

    public string CommandText { get; set; }
    public string CommandId { get; set; }

    // Navigational properties
    public int DeviceId { get; set; }
    public Device Device { get; set; }
}

And in my DbContext derived class I have following code:

    protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
    {         
        modelBuilder.Entity<DeviceCommand>()
            .HasRequired(d => d.Device)
            .WithMany(l => l.CommandList)
            .HasForeignKey(b => b.DeviceId)
            .WillCascadeOnDelete();
    }

IMO you will have to setup a foreign key relationship either using annotations or fluent API.

If the parameter in the POST method has no attribute on it, then the decision is made purely on the parameter’s .NET type.“Simple types” uses model binding. Complex types uses the formatters.

Please refer this link to understand web api binding better:

http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx

Hope this helps.

2013-06-05 14:03
by SBirthare