This is actually the correct behavior. MVC has a concept called ModelState (accessible via the Controller.ModelState property) which contains information about the model the MVC request is currently working with. The ModelState collection stores raw values
submitted by the user and a list of validation errors for each of those values.
When displaying a form, all HTML helpers look in ModelState first to get the value that should be displayed to the user, then they look at the actual model itself if ModelState doesn't contain anything useful. The reason for this is so that user input isn't
blasted away in the event of a conversion error. For example, say that the user types "Decembr 21, 1998" (note the misspelling) for a textbox that corresponds to a DateTime property on your model. When the form is redisplayed to the user in error, the textbox
will contain the original text "Decembr 21, 1998" (which can't be represented by a DateTime) rather than the model property's actual value of default(DateTime), which is "January 1, 0001".
Now, how is this relevant to your case? Your action method takes a parameter called
username. The existence of this parameter signals to MVC that username
is user input that should be added to ModelState, thus the helpers treat username
parameter with a higher precedence than the actual model itself.
If you did not intend this, remove the username parameter from your action method. This will prevent the MVC pipeline from treating
username as user input and thus prevent the parameter from propagating to the form. If for some reason you cannot remove the parameter, call ModelState.Clear() as the first line in your action method. This tells the MVC pipeline that there are no user
input values for the current request. Or change the route definition such that it doesn't contain a
{username} path segment, as the username appears to be unused by the current request.
levib
Star
7702 Points
1099 Posts
Microsoft
Re: Model Binding Precedence
May 18, 2010 11:35 PM|LINK
Thanks for the report.
This is actually the correct behavior. MVC has a concept called ModelState (accessible via the Controller.ModelState property) which contains information about the model the MVC request is currently working with. The ModelState collection stores raw values submitted by the user and a list of validation errors for each of those values.
When displaying a form, all HTML helpers look in ModelState first to get the value that should be displayed to the user, then they look at the actual model itself if ModelState doesn't contain anything useful. The reason for this is so that user input isn't blasted away in the event of a conversion error. For example, say that the user types "Decembr 21, 1998" (note the misspelling) for a textbox that corresponds to a DateTime property on your model. When the form is redisplayed to the user in error, the textbox will contain the original text "Decembr 21, 1998" (which can't be represented by a DateTime) rather than the model property's actual value of default(DateTime), which is "January 1, 0001".
Now, how is this relevant to your case? Your action method takes a parameter called username. The existence of this parameter signals to MVC that username is user input that should be added to ModelState, thus the helpers treat username parameter with a higher precedence than the actual model itself.
If you did not intend this, remove the username parameter from your action method. This will prevent the MVC pipeline from treating username as user input and thus prevent the parameter from propagating to the form. If for some reason you cannot remove the parameter, call ModelState.Clear() as the first line in your action method. This tells the MVC pipeline that there are no user input values for the current request. Or change the route definition such that it doesn't contain a {username} path segment, as the username appears to be unused by the current request.
Hope this helps!