Why isn’t my ModelState updating in the controller when using a View Model (MVC)?

I am sending some information to a controller on a view via an ajax call. The controller binds the post data to a viewmodel, like such:

UserController.cs

    [HttpPost]
    public ActionResult UserInfo(UserPositionVM userposvm)
    {
        //Check if user already exists in the database.
        int? user_id = userposvm.User.userid;
        var userindb = db.Users.Where(x => x.userid == user_id).FirstOrDefault();

        /If the user does exist in the database, assign that User model to the view model.
        if (userindb != null)
            userposvm.User = userindb;

        userposvm.User.Office = 3;
        return PartialView(userposvm);
    }

and my viewmodel…

UserPosition.cs

public class UserPositionVM
{
    public Users User { get; set; }
    public Positions Position { get; set; }
}

For the view, I have this:

AssignUser.cshtml

...
...
...
@Html.TextBoxFor(model => model.User.Office, new { @readonly = "readonly", @class = "form-control"})
@Model.User.Office
...
...
...

What is interesting is that the TextBoxFor does not populate with the value (3), but the @Model.User.Office does. After doing some research, I found out it has to do with the ModelState. However, I just can’t seem to update the ModelState in my controller post method.

I have tried using ModelState.Clear() at the start of my function, as well as UpdateModel(userposvm.User) immediately before my return PartialView(). I saw another post similar to mine (stackoverflow.com/questions/10248757), but it is outdated and I can no longer access the blog in one of the answers.

How can I fix this issue? Moreover, what’s the best approach to editing model values inside a controller, to be then sent back to a view?

Answer

Okay, I feel pretty silly now, but I was able to resolve my issue. First, to anyone else who is struggling with this, I STRONGLY recommend you check out this video: https://www.youtube.com/watch?v=9ul8oihM8hc&ab_channel=TechCBT

I wasn’t fully understanding the relationship between the ModelState and the Model itself. So, the ModelState is created in the controller by essentially binding from the post data. The whole idea behind ModelState (from what I understand) is that you can use HTML Helpers in your View, and then they will look for data from the ModelState.

Normally, when you would submit a form, if you redirect to the same page you submitted the form from, all the values you entered in the form will be cleared and reset. However, if you are using HTML Helpers, it will check to see if there are any values in the ModelState. If they are, they will load the corresponding value into the field.

The thing of it is, ModelState actually takes priority over the Model itself. In other words, the HTML Helper will check the ModelState FIRST. If it finds a corresponding key with a value, it will load that data. If it does not find anything in the ModelState, it will then reference the model. This is precisely why my TextBoxFor was loading a different value than what was in the Model; since it found something in the ModelState, it completely ignored the Model.

So, using ModelState.Clear() did fix the issue. However, the reason I wasn’t seeing results when I did ModelState.Clear() is because (embarrassingly enough) I had specified the help incorrectly in my View. So it was just showing null rather than 3. Hopefully this helps anyone else who has a similar problem!