I'm trying to dip my toe into frontend development with ASP.NET Core 5 MVC - but I'm not really having much success so far... I'm more of a backend developer - give me a SQL Server database, and a ASP.NET Core Web API, and I'm happy - but this frontend wizardry is not quite my strong suit ...
OK, so I'm trying something extremely simple - a Razor page to edit a list of something, add a numerical value to each of those somethings, and then storing them.
I have a model/DTO class like:
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
Of course, in reality, it has many more properties - but those aren't relevant here. What is: name and city are given, and I need to add the CustomerId to it (in our case, the CustomerId is handled by SAP - so we need to manually add those after the customer has been created there).
I have a really simple Razor page which basically shows the list of customers, allows me to enter the CustomerId in the last column, and then I have a POST method on the same Razor page that gets hit when the user clicks on the Update (submit) button.
Here's my view:
@page
@model IndexModel
<h3 class="display-4">Customers</h3>
@if (!string.IsNullOrWhiteSpace(@Model.Message))
{
<div class="container">
<span class="@Model.MessageClass mt-4 mb-5">@Model.Message</span>
</div>
}
<div class="container">
<form method="post">
<table class="table table-striped table-bordered table-hover table-sm">
<thead class="thead-dark">
<tr>
<th scope="col-md-2">Name</th>
<th scope="col-md-2">City</th>
<th scope="col-md-1">CustomerId</th>
</tr>
</thead>
<tbody>
@for (int index = 0; index < Model.Customers.Count; index++)
{
<tr>
<td>@Model.Customers[index].Name</td>
<td>@Model.Customers[index].City</td>
<td>
<input type="number" asp-for="Customers[index].CustomerId" id="Customers[@index]" />
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="Update" class="btn btn-primary" />
</form>
</div>
and this is my "code-behind" for this Razor page:
public class IndexModel : PageModel
{
public string Message { get; set; }
public string MessageClass { get; set; }
public List<Customer> Customers { get; set; }
public async Task OnGetAsync()
{
Customers = CustomerProvider.GetCustomers();
}
public async Task OnPostAsync()
{
Customers = CustomerProvider.GetCustomers();
if (await TryUpdateModelAsync(Customers))
{
Message = "Customers successfully updated";
MessageClass = "alert-success";
}
else
{
Message = "Customer update did not work";
MessageClass = "alert-danger";
}
}
}
Nothing too fancy here - I basically get a list of customers from somewhere (a database, in reality), I display that list, I can enter customer id values into the grid, and I was expecting to get back the updated Customers in my OnPostAsync method.
Now the code runs fine, shows the list of customers, I can enter values into the CustomerId column, and I can click on "Update". The OnPostAsync method gets called, I fetch the customers again, and I was expecting the await TryUpdateModelAsync to update my customers with the CustomerId values that I have entered.
But it does not do that - after my GetCustomers call, I have my four test customers - as expected - but after the TryUpdateModelAsync, that list is empty... The call to TryUpdateModelAsync works - it returns true - but the list of customers isn't updated with the information entered on screen - quite the contrary, the list is wiped out ...
I also tried to use
public async Task OnPostAsync([FromForm] List<Customer> updatedCustomers)
hoping that the MVC data binding would return back the list of updated customers - but this updatedCustomers is null and doesn't send back the entered data...
But when I look at HttpContext.Request.Form - I do see the values that were entered:
but somehow, those aren't handled properly and not applied to the Customers list...
Any ideas? I must be missing something really silly somewhere - but I just cannot find it...
