K7Buoy K7Buoy - 1 year ago 164
C# Question

ASP.Net Core Exception - Could not create a model binder for model object

I am still new to MVC and I am struggling to resolve an issue where the default binding is failing on form submit to a controller expecting a view model. I have tried adding model binding attributes [FromForm] to the constructor with no success and I have started to read about custom binders but that feel overkill in this case. If I need to post the full HTML I can do.

I would really appreciate some guidance on this, all help greatly appreciated? I am struggling to even debug and hit breakpoints.


InvalidOperationException: Could not create a model binder for model object >of type 'XX.Models.ClientEditViewModel'.


MODEL

public partial class ClientEditViewModel
{
public ClientEditViewModel(List<ProgramViewModel> programs)
{
this.Programs = programs;
}
public int ClientId { get; set; }
public string ClientName { get; set; }
public List<ProgramViewModel> Programs { get; set; }
}


FORM

@model XX.Models.ClientEditViewModel
<form asp-action="EditClient" method="post">
<div class="form-horizontal">
<input type="hidden" asp-for="@Model.ClientId" />
<div class="form-group">
<label asp-for="@Model.ClientName" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="@Model.ClientName" class="form-control" />
<span asp-validation-for="@Model.ClientName" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Update" class="btn btn-default" />
</div>
</div>
</div>
</form>


CONTROLLER

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditClient(ClientEditViewModel clientedit)
{
if (ModelState.IsValid)
{
Client client = await dbcontext.Client.SingleOrDefaultAsync(m => m.Id == clientedit.ClientId);
try
{
client.Name = clientedit.ClientName;
dbcontext.Client.Update(client);
await dbcontext.SaveChangesAsync();
}
catch (Exception ex)
{
string error = ex.InnerException.ToString();
if (!ClientExists(clientedit.ClientId))
{
return NotFound();
}
else
{
throw;
}
}

TempData["msg"] = "You have successfully edited " + clientedit.ClientName + ".";
return RedirectToAction("Index");
}

return null;
}

Answer Source

The default binding uses a parameterless constructor, while your model has a custom constructor which would require a custom binding. Here is a similar post Posting data when my view model has a constructor does not work

In your case, Programs has a setter, so I would remove the custom constructor completely.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download