ASP.NET Core: asp-* attributes use request payload over model?

It seems that in ASP.NET Core, the value in asp-* attributes (e.g. asp-for) is taken from the request payload before the model. Example:

Post this value:

MyProperty="User entered value."

To this action:

[HttpPost]
public IActionResult Foo(MyModel m)
{
    m.MyProperty = "Change it to this!";
    return View();
}

OR this action

[HttpPost]
public IActionResult Foo(MyModel m)
{
    m.MyProperty = "Change it to this!";
    return View(m);
}

View renders this:

<input asp-for="MyProperty" />

The value in the form input is User entered value. and not Change it to this!.

First of all, I’m surprised that we don’t need to pass the model to the view and it works. Secondly, I’m shocked that the request payload takes precedence over the model that’s passed into the view. Anyone know what the rationale is for this design decision? Is there a way to override the user entered value when using asp-for attributes?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I believe this is the expected behavior/by design. Because when you submit the form, the form data will be stored to ModelState dictionary and when razor renders your form elements, it will use the values from the Model state dictionary. That is why you are seeing your form element values even when you are not passing an object of your view model to the View() method.

If you want to update the input values, you need to explcitly clear the Model state dictionary. You can use ModelState.Clear() method to do so.

[HttpPost]
public IActionResult Create(YourviewModel model)
{       
    ModelState.Clear();
    model.YourProperty = "New Value";
    return View(model);
}

The reason it uses Model state dictionary to render the form element values is to support use cases like, showing the previously submitted values in the form when there is a validation error occurs.

EDIT : I found a link to the official github repo of aspnet mvc where this is confirmed by Eilon (asp.net team member)

https://github.com/aspnet/Mvc/issues/4486#issuecomment-210603605

Method 2

I can confirm your observation. What’s really going to blow your mind is that this:

[HttpPost]
public IActionResult Foo (MyModel m)
{
    m.MyProperty = "changed";
    var result = new MyModel { MyProperty = "changed" };
    return View(result);
}

…gives you the same result.

I think you should log a bug: https://github.com/aspnet/mvc/issues


Edit: I now remember this issue from previous encounters myself and concede that it isn’t necessarily a bug, but rather an unintended consequence. The reasons for the result of executing this code is not obvious. There likely isn’t a non-trivial way to surface a warning about this, but PRG is a good pattern to follow.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x