Patrick Szalapski
Patrick Szalapski

Reputation: 9439

ASP.NET MVC parameter binding: How to POST a list or array to a controller method?

I can't seem to figure out how to pass an array of GUIDs as a parameter to a ASP.NET MVC controller via POST. What am I missing? Is there a simpler way to do this?

In my AngularJS markup:

<form method="post" action="/Foo/Bar" >
  <input name="itemIds" type="hidden" value="{{ ctrl.itemIds }}">
  <button type="submit">Submit</button>
</form>

Which results in HTML:

<form method="post" action="/Foo/Bar" >
  <input name="itemIds" type="hidden" value="[&quot;8cd52539-c371-402a-b8be-12775f03ab68&quot;,&quot;8c97f9e0-666c-41ba-a914-72815745d1f0&quot;]">
  <button type="submit">Submit</button>
</form>

In my FooController:

[System.Web.Mvc.HttpPost]
public ActionResult Bar([FromBody]Guid[] itemIds) => ...

When I debug the above, my HTTP POST seems to be correct but I get null itemIds in Bar. Can you help me change this to work? Is there a better way to populate my request body, given that I already have an array of GUIDs in my JS model?

Upvotes: 2

Views: 5854

Answers (1)

CodingYoshi
CodingYoshi

Reputation: 27009

Here is what's really happening:

itemIds is being posted as one single string to the controller. Why? Because itemIds is not interpreted as an array. If you want an array, you need to have multiple hidden values named itemIds[0], itemsIds[1] and so on. Here is a quick test to prove that what I am saying is actually what is happening:

Create a form like this. See we create one hidden value named itemIdsOld and then 2 more hidden values named itemIds[0] and itemIds[1]:

<form method="post" action="/Foo/Bar">
    <input name="itemIdsOld" type="hidden" value="[&quot;f8b21933-419c-4bdd-b5b6-75295ff65612&quot;,&quot;67bb1d75-ae78-49e4-bc29-ee82a51bb9a1&quot;]">
    <input name="itemIds[0]" type="hidden" value="f8b21933-419c-4bdd-b5b6-75295ff65612">
    <input name="itemIds[1]" type="hidden" value="67bb1d75-ae78-49e4-bc29-ee82a51bb9a1">
    <button type="submit">Submit</button>
</form>

Create a controller like this:

[System.Web.Mvc.HttpPost]
public ActionResult Index(string[] itemIdsOld, Guid[] itemIds)
{
    return null;
}

When you post the above form, you will notice that a single string is created in itemIdsOld and it will have both the Guids in it as a string. However, the second one, since we created controls named itemIds[0] and itemIds[1] will be converted to a Guid[] itemIds as you expected.

I am not sure how to do this in Angular, but with C# and Razor, one way to do it would be like this:

@using System.Collections.Generic
@{ 
    var guids = new List<Guid> { Guid.NewGuid(), Guid.NewGuid() };
}
<form method="post" action="/Test/Index">
    <input name="itemIdsOld" type="hidden" value="[&quot;f8b21933-419c-4bdd-b5b6-75295ff65612&quot;,&quot;67bb1d75-ae78-49e4-bc29-ee82a51bb9a1&quot;]">
    @{
        for (int i = 0; i < guids.Count; i++)
        {
            <input name="itemIds[@i]" type="hidden" value="@guids[i]">
        }
    }
    <button type="submit">Submit</button>
</form>

I hard coded the guids but you can get this from a model...you get the point.


Alternatively, you can use Javascript to intercept the form submission and retrieve the value from itemIds and turn it into an array and submit that to the controller, that would work too.

Upvotes: 2

Related Questions