I have a Razor Pages page, and want to submit an array of objects and automatically bind them.
However, these objects will be edited (added, edited and deleted) on the client side. So rather than specify the index of each array item (name=Ship.Products[1].ProductId
), it would be much easier to omit the index (name=Ship.Products[].ProductId
).
However, Razor Pages does not appear to recognize the data without the array index.
Models
public class EditShipViewModel
{
public int Id { get; set; }
[Required]
[StringLength(80)]
public string Name { get; set; }
[StringLength(80)]
public string Shipper { get; set; }
[StringLength(80)]
[DisplayName("Port of Origin")]
public string PortOfOrigin { get; set; }
[DisplayName("Is Empty")]
public bool IsEmpty { get; set; }
[DisplayName("ETA")]
public DateTime? Eta { get; set; }
public DateTime? Arrival { get; set; }
public DateTime? Departure { get; set; }
public IEnumerable<EditShipProductViewModel> Products { get; set; }
}
public class EditShipProductViewModel
{
public int Id { get; set; }
[DisplayName("Product")]
public int ProductId { get; set; }
[DisplayName("Inbound Quantity")]
public double InboundQuantity { get; set; }
}
Property
[BindProperty]
public EditShipViewModel Ship { get; set; }
Markup
<table class="table table-striped">
<tbody id="ship-products">
<tr>
<td>
<input name="Ship.Products[].Id" type="hidden" value="1">
<input name="Ship.Products[].ProductId" type="hidden" value="1">
</td>
<td>
<input name="Ship.Products[].InboundQuantity" type="hidden" value="1000">
</td>
<td class="text-end">[Edit][Delete]</td>
</tr>
<tr>
<td>
<input name="Ship.Products[].Id" type="hidden" value="2">
<input name="Ship.Products[].ProductId" type="hidden" value="2">
</td>
<td>
<input name="Ship.Products[].InboundQuantity" type="hidden" value="2000">
</td>
<td class="text-end">[Edit][Delete]</td>
</tr>
<tr>
<td>
<input name="Ship.Products[].Id" type="hidden" value="3">
<input name="Ship.Products[].ProductId" type="hidden" value="3">
</td>
<td>
<input name="Ship.Products[].InboundQuantity" type="hidden" value="3000">
</td>
<td class="text-end">[Edit][Delete]</td>
</tr>
</body>
</table>
Is there any way to have Razor Pages binding recognize this markup as an array of objects?
Update
Here’s the actual data posted to my page.
2
Answers
Short answer; No.
You can bind a collection of simple values like
name=1&name=2&name=3
toint[] name
. But there’s no way this can work with complex objects, as the server would have no logical way to tell when one item stops and another begins.If you don’t want to worry about posting sequential values, then you can bind a
Dictionary<int,T>
instead of aList<T>
. That way the client can generate new dictionary keys, but can also remove them without needing to renumber everything else.As a side effect, this approach works well with preserving user supplied values in
ModelState
when re-rendering the same template, even if the user supplied data failed to parse.If you want to avoid failing model binding due to the index of array item not numbered sequentially starting at zero
You may try replace the index of array and add a input with the name
Ship.Products.index
as below: