Search code examples
c#asp.net-core-mvchttp-postasp.net-core-8

ASP.NET Core 8 MVC : model value is not passed back in POST if a child class property


For some reason, when I use a child property as an asp-for value, the HTTP Post model property shows that they were not modified and my ModelState validation does not trigger.

Here is the example - view

@model ViewModel
<form asp-action="Login" asp-controller="App" method="POST">
   <input asp-for="subClass1.user.email_addr" type="text" class="form-control" autocomplete="on" />
   
   <input asp-for="test" type="text" class="form-control" autocomplete="on" />
</form>

Model

public class ViewModel
{
    public string test { get; set; } = "test value";
    public User subClass1 = new User();
}

public class User 
{    
     public UserL user { get; set; } = new UserL();
}

public class UserL
{
    [CustomEAttribute]
    public string? email_addr { get; set; } 
}

HTTP POST method:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(ViewModel model, Microsoft.AspNetCore.Http.IFormCollection collection)
{
   // I've also found ModelState is not triggered on subClass1 
   // properties... only the 'test' property triggered.
   if (!ModelState.IsValid)
   {
   }
}

From what I can tell in my controller, the property ViewModel model has not changed (ie not returning my view input value) for email_addr.

I've tried using @Html.TextBoxFor instead of plain html input and I still have no luck.

So many examples online say you should be able to do my example above without issues so not sure what is wrong with my code.

I do know the Microsoft.AspNetCore.Http.IFormCollection collection property does show subClass1.user.email_addr being set. So why does accessing that same value in "model" not work?


Solution

  • When defining a data model in the ASP.NET MVC it's necessary to use properties not fields. If fields are used the MVC engine will not able to make data binding correctly. Change the view model declaration to:

    public class ViewModel
    {
        public string test { get; set; } = "test value";
        public User subClass1 { get; set; } = new User();
    }