I build up a simple web page with asp.net core 3.1 for reproducing problem. There are 2 action in same HomeController.cs
.
one for rendering a html form, another for receiving form post data then rendering form again.
public class HomeController : Controller
{
// rendering form
[HttpGet]
public IActionResult Index()
{
var myForm = new MyForm();
myForm.Id = 100;
return View("index", myForm);
}
// after form post, rendering form with updated value.
[HttpPost]
public IActionResult Index(MyForm m)
{
m.Id = 200;
return View("index", m);
}
}
I use asp.net core tag helper in index.cshtml
@model MyForm
<div>
<form asp-controller="Home" asp-action="Index" method="post">
<span>@Model.Id</span>
<input type="text" asp-for="@Model.Id"/>
<button type="submit">Submit</button>
</form>
</div>
When I GET /index, everything is fine, both @Model.Id in span and input value are 100
Http Response for Get /index
<form method="post" action="/">
<span>100</span>
<input type="text" data-val="true"
data-val-required="The Id field is required."
id="Id" name="Id" value="100">
<button type="submit">Submit</button>
</form>
But When I post form, I expected both value in span and input should be 200, but it is 200 in span and 100 in form
Http Response for POST /index with 100 in input
<form method="post" action="/">
<span>200</span>
<input type="text" data-val="true"
data-val-required="The Id field is required."
id="Id" name="Id" value="100">
<button type="submit">Submit</button>
</form>
I guess "asp-for" choose to read data from original ModelState, which is built while modelbinding. Instead of read ViewModel passed for view Razor rendering.
Does Anyone know why tag helper asp-for
behavior like this? How should I avoid this behavior and make asp-for
use the Model I passed in View("index", m)
Yes, this is by design. Default TagHelper display ModelState value not Model.
If you want
asp-for
display the updated model value, you could addModelState.Clear();
in your post action.