sanmolhec
sanmolhec

Reputation: 416

asp.net core binding null in controller post request (list with inside elements lists in view)

I have a view with a list of items that among their properties have a list of items (in View asp.net core).

I use a generic list to have common properties that I use in the view.

The ViewModels are these:

public class AgaqEleViewModel
{        
    public int CodEle { get; set; }

    public int AbrEle { get; set; }

    public string Valor { get; set; }

    ...
}

public class AgaqViewModel
{
    [Required(ErrorMessageResourceType = typeof(AguasResx.DataAnnotations), ErrorMessageResourceName = nameof(AguasResx.DataAnnotations.Required))]
    public int Hoja { get; set; } // Key Id compossed
    
    [Required(ErrorMessageResourceType = typeof(AguasResx.DataAnnotations), ErrorMessageResourceName = nameof(AguasResx.DataAnnotations.Required))]
    public DateTime FechaTomaAq { get; set; }
    
    public float? ProfmuestraM { get; set; }

    ...


    // List test
    public List<AgaqEleViewModel> AgaqEle { get; set; }


    ...
            
}

public class GenericListViewModel<T>
{

    public RespViewModel Resp { get; set; }

    public List<T> ItemsList { get; set; }


    public GenericListViewModel()
    {

    }

    public GenericListViewModel(RespViewModel resp, List<T> genericList)
    {
        Resp = resp;
        ItemsList = genericList;
    }

}

My Razor View is this:

@model GenericListViewModel<AgaqViewModel>

@{
// get max number of columns of different elements 
int numColElements = Model.ItemsList.Select(s => s.AgaqEle.Count).Max();
}


<form asp-action="AgaqLoaded" method="post" id="agaqExcelForm">

    @if(Model.Resp.XXX)
    {
        ...
    }
    
    <table class="table table-bordered table-sm table-striped">
        <thead>
            <tr>
                @* header columns *@
                <th title="@Literals.Hoja">@Literals.Hoja</th>
                ...

                @* create elements columns header´s *@
                @for(int i = 0; i < numColElements; i++)
                {
                    <th>@Literals.Element</th>
                }
                ...


        <tbody>
            // iterate each item in Model list
            @for (var i = 0; i < Model.ItemsList.Count(); i++)
            {               
                <tr>                    
                    <td class="">
                        <input asp-for="@Model.ItemsList[i].Hoja" type="hidden" />
                        @Model.ItemsList[i].Hoja
                    </td>
                    <td>
                        <input asp-for="@Model.ItemsList[i].FechaTomaAq" type="hidden" />
                        @Model.ItemsList[i].FechaTomaAq
                    </td>
                    ...

                    // iterate each list elements in each item in Model list
                    @for(int j = 0; j < numColElements; j++)
                        {
                            <td>                                
                                <input asp-for="@Model.ItemsList[i].AgaqEle[j].CodEle" type="hidden" />
                                <input asp-for="@Model.ItemsList[i].AgaqEle[j].AbrEle" type="hidden" />
                                <input asp-for="@Model.ItemsList[i].AgaqEle[j].Valor" type="hidden" />
                                ...
                                @elemAgaq.AbrEle: @elemAgaq.Valor
                            </td>                           
                        }
            }
...
<tfoot>
<button id="btnLoad" type="submit" class="btn btn-sm btn-primary"><i class="fa fa-upload"></i>&nbsp;@AguasLiterals.LoadData</button>
    ...
</form>

and my Controller is this:

[HttpPost("{controller}/{action}/")]
public async Task<IActionResult> AgaqLoaded(GenericListViewModel<AgaqViewModel> listToLoad)
{   
    // save 
    foreach (AgaqViewModel agaqEx in listToLoad.ItemsList)
    {
        AgaqDto saveAgaq = null;
        AgaqDto agaq = _mapper.Map<AgaqDto>(agaqEx);
            
        // save Agaq
        saveAgaq = await _service.SetAgaqAsync(agaq);
        ...

The generated HTML code is:

<td>
    <input type="hidden" data-val="true" data-val-range="El valor ..." data-val-range-max="9999" data-val-range-min="1" data-val-required="Este campo es obligatorio." id="ItemsList_0__Hoja" name="ItemsList[0].Hoja" value="1921">
    1921
</td>
<td>
    <input type="hidden" data-val="true" data-val-required="Este campo es obligatorio." id="ItemsList_0__FechaTomaAq" name="ItemsList[0].FechaTomaAq" value="20/07/2021 0:00:00">
    20/07/2021 0:00:00 
</td>


<td>
    <input type="hidden" data-val="true" data-val-required="The CodEle field is required." id="ItemsList_0__AgaqEle_0__CodEle" name="ItemsList[0].AgaqEle[0].CodEle" value="3">
    <input type="hidden" id="ItemsList_0__AgaqEle_0__AbrEle" name="ItemsList[0].AgaqEle[0].AbrEle" value="Na">
    <input type="hidden" id="ItemsList_0__AgaqEle_0__Valor" name="ItemsList[0].AgaqEle[0].Valor" value="48">
    ...
    Na: 48
</td>
<td>
    <input type="hidden" data-val="true" data-val-required="The CodEle field is required." id="ItemsList_0__AgaqEle_1__CodEle" name="ItemsList[0].AgaqEle[1].CodEle" value="3">
    <input type="hidden" id="ItemsList_0__AgaqEle_1__AbrEle" name="ItemsList[0].AgaqEle[1].AbrEle" value="Ca">
    <input type="hidden" id="ItemsList_0__AgaqEle_1__Valor" name="ItemsList[0].AgaqEle[1].Valor" value="16">
    ...
    Ca: 16
</td>

The objects arrive correctly to the view and the generated HMTL is apparently correct. (The rest of the items/elements have the correct numbering: ItemsList_1__AgaqEle_0__CodEle, ItemsList_1__AgaqEle_0__AbrEle ... ItemsList_7__AgaqEle_0__CodEle ...)

When in the view I comment out the part of the elements (second loop, asp-for hidden properties) inside each item in the list, I get it correctly.

enter image description here

But if I don't comment the elements, although the HTML is apparently correct, the post request call arrives null without any item or elements.

enter image description here

I have several "simple" lists of complex elements that work fine, but this list composed of items with a list of elements I can't binding it.

What am I doing wrong?

I've tried removing the generic viewmodel and leaving it as a list of items, I've tried using list[i][j] or list[i].[j] and everything I could think of but nothing works? Any ideas? Thanks.

Upvotes: 2

Views: 1069

Answers (1)

sanmolhec
sanmolhec

Reputation: 416

In the end, the problem was not the binding of the properties, but rather the fact that the information was not arriving because of the large volume of information (as it was a list of items with a list of elements for each item).

Instead of giving an error with information, the input parameter of the binding simply arrived null.

To solve it we have added in the startup.cs, in the ConfigureServices part:

services.Configure<FormOptions>(options =>
{
    options.ValueCountLimit = int.MaxValue;
});

I hope it helps someone else.

Upvotes: 2

Related Questions