4

I am attempting to model bind a complex object with a non-sequential list using an ApiController. All of the fields except the list are set correctly, but the list contains one element (even though two list elements were posted) and the element is null. If I take the exact same code and point it to an MVC Controller using the same parameter type in my action method, everything works as expected.

Since I am using a non-sequential list, I am using the hidden ".Index" input as described by Phil Haack (http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx)

The ApiController also binds the list correctly if I remove the ".Index" input and send the list as a sequential list starting at 0. (This option work for testing, but is not a great option in production as the list items can be added and removed by the user, which is why I want to use the non-sequential list.)

I understand that Web API Controllers do parameter binding differently than MVC Controllers as discussed here, but it seems like non-sequential lists should bind correctly in Web API Controllers. Am I missing something? Why does the same code work for an MVC Controller and not a Web API Controller? How can I get non-sequential lists to bind correctly in Web API?

Here are my Post parameters:

Parameters application/x-www-form-urlencoded

BatchProductLots.Index  1
BatchProductLots.Index  2
BatchProductLots[1].BrandId     1
BatchProductLots[1].ContainerId 9
BatchProductLots[1].ContainerLot    123
BatchProductLots[1].PackageId   2
BatchProductLots[1].PlannedQuantity 0
BatchProductLots[1].ProducedQuantity    20
BatchProductLots[2].BrandId     1
BatchProductLots[2].ContainerId 9
BatchProductLots[2].ContainerLot    123
BatchProductLots[2].PackageId   1
BatchProductLots[2].PlannedQuantity 0
BatchProductLots[2].ProducedQuantity    1
BatchStatusId   1
LotNumber   070313
ProductionDate  07/03/2013
RecipeId    1
RecipeQuantity  1
SauceId 22
X-Requested-With    XMLHttpRequest 

Here is my Web API Controller Action:

(request.BatchProductLots list is set to one element (even though two elements were posted) and that one element is null)

public Response Create(BatchCreateRequest request)
{
    Response response = new Response();

    try
    {
        Batch batch = Mapper.Map<Batch>(request);
        batchService.Save(batch);
        response.Success = true;
    }
    catch (Exception ex)
    {
        response.Message = ex.Message;
        response.Success = false;
    }

    return response;
}

Here is the complex object with the list that I am attempting to bind to:

public class BatchCreateRequest
{
    public int BatchStatusId { get; set; }
    public DateTime ProductionDate { get; set; }
    public string LotNumber { get; set; }
    public int SauceId { get; set; }
    public int RecipeId { get; set; }
    public int RecipeQuantity { get; set; }
    public List<BatchProductLot> BatchProductLots { get; set; }

    public class BatchProductLot
    {
        public int BrandId { get; set; }
        public int ContainerId { get; set; }
        public string ContainerLot { get; set; }
        public int PackageId { get; set; }
        public int PlannedQuantity { get; set; }
        public int ProducedQuantity { get; set; }
    }
}

2 Answers 2

1

Short answer, it's not possible using Web Api's Model Binder. MVC and Web Api use different model binders and the Web Api model binder only works on simple types.

See this answer for links that explain further as well as possible solutions.

Longer answer, create a custom implementation of System.Web.Http.ModelBinding.IModelBinder and change your Action's signature to the following

public Response Create([ModelBinder(CustomModelBinder)]BatchCreateRequest request)
Sign up to request clarification or add additional context in comments.

Comments

0

Do you really need Index to be set? In that case, one possible solution could be to make Index part of the BatchProductLot class. The sequence of list won't matter then and Web Api should be able to bind it.

Another idea would be to use application/json content type and send JSON. You can use Json.Net to deserialize and model binding would work.

Read Using an alternate JSON Serializer in ASP.NET Web API and even use this Nuget Package WebApi Json.NET MediaTypeFormatter if you don't want to do the hand wiring.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.