Search code examples
c#.netasp.net-mvcmodel-binding

Accessing ViewModel properties in ASP.NET Core controller


I've been following an EF core tutorial on basic CRUD operations, and am having trouble with getting data from my ViewModel.

I'm following their recommended practice of using TryUpdateModel (or in my specific case, TryUpdateModelAsync) in the following action.

[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(int id)
{
    var versionToUpdate = await _context.Versions.FirstOrDefaultAsync(a => a.Id == id);

    var editModel = new VersionEditModel() { Version = versionToUpdate };

    if (await TryUpdateModelAsync(
        editModel.Version,
        "Version",
        a => a.Name,
        ...further code removed for brevity

In the past, I would have passed the model itself in action signature, i.e.

public async Task<IActionResult> EditPost(VersionEditModel editModel)

But the recommendation in the tutorial was to use just the ID, fetch the item from the database and run TryUpdateModel against it.

This all works, but I want to access a value that has been POSTed to the action as part of the ViewModel, but I can't seem to access it.

If I add the model to the signature as an additional parameter, like this

public async Task<IActionResult> EditPost(int id, VersionEditModel editModel)

I can access it using editModel, but the TryUpdateAsync no longer works properly.

I assume there must be a way to get to this data, but I can't figure out the right way to get to it.

My main problem has been trying to find the right words to explain my issue and what I want, so please ask for clarification if something doesn't make sense.


Solution

  • I ended up passing the parameters in like so

    public async Task<IActionResult> EditPost(int id, 
        int[] myListOfInts, 
        int myInt,
        bool myBool)
    

    Which is then picked up automatically based on the name. So in my ViewModel I had the following properties

    //other properties removed for brevity
    public int MyInt{ get; set; }
    public List<int> MyListOfInts{ get; set; } = new();
    public bool MyBool{ get; set; }
    //other properties removed for brevity
    

    When these are POSTed to the endpoint, the model binder automatically picks them up. Its not ideal as a name change in the ViewModel will break the automatic model binding, but it works.