Why are my dotnet 5.0 mvc form fields retaining their input values on post? - asp.net-mvc

I have an dot net 5.0 mvc page which takes a model object (ClassFoo) which when constructed generates an instance of (classBar). ClassBar has various properties (FieldA, FieldB, FieldC) all are strings.
The Views content is all in a form and the form's input fields are all from ClassFoo.ClassBar's various properties. Initially, when the page is accessed, all form input values are empty. However when I put data into them and then submit the form, the form values are still there when the page loads. However I don't understand why this is because I'm explicitly creating a new model during the controller operation but I am not actually populating the Model.ClassBar with the content from the post before I return model to the View for generation.
What I would expect is that all of the form fields would be empty however that is not the case. I know if asp.net the form values are stored and restored automatically but I didn't think that happened in mvc.

After looking into ModelState recommended by Nick Albrech in the comments I reviewed the hint associated w/ the HtmlHelper.TextBoxFor() which states the following:
... Adds a "value" attribute to the element containing the first non-null value found in: the ActionContext.ModelState entry with full name, or the expression evaluated against ViewDataDictionary.Model. See [IHtmlHelper.NameFor] for more information about a "full name".
So effectively what's happening is similar to what I thought asp.net mvc wasn't doing in that it populates the ModelState from a get/post request with the name and values of the form being submitted. Then based on the use of these helper functions (and also asp-for attributes used in razor views views), it either provides values from the saved model state form values OR the model passed to the view. Note: this does not seem to work if you set the value of an input element = #Model.[someProperty]
The take away from this is that you do not necessarily need to update your model object with content from the previous form submit in order to have the page populate the form contents back to the screen. Allow asp.net mvc to do the manual tasks by making use of these razor helpers.
Shoutout to Nick for the assist on this one. A solid member of the stackOverflow community.

Related

New entries in nested ViewModel are not recreated on ModelState.Merge()

We are using the well known Post-Redirect-Get pattern to prevent double posting in our MVC application. Like most implementations we store the Model-State inside TempData in the Http-Post-Action on errors and restore the Model-State with ModelState.Merge() inside the action we are redirected to. This works very well in most cases but breaks in the following case where we are adding new elements to a nested View-Model.
A editor template on the page is refreshed and contains an additional nested view-model element.
In another field on the surrounding view that incorporates the editor template another field is invalid and will prevent the commit into the db and forces the PRG into the error path (redirect to GET).
When the page gets submitted the Model-State contains the new nested element Property[n+1].Value and its value and is stored into TempData. After the Merge() the model-state in filterContext of the redirected to Get-Method contains the additional element.
Now when the view gets rendered the new element does not recreate because it is only in the model-state but not in the model. View creation loops over the model (that doesn't have the new nested object) and the EditorFor<> gets the value from the model-state which is as expected. Is there a generic solution to this problem?
Apparently there is no quick solution to the problem. We switched from a redirect on the error path in the controller (strict PRG) to a implementation described in this blog. It works very well and did even speed up the application as the returned json on the controllers error path is handled much faster than a full ViewResult.

asp.net mvc implicit population of input fields

In our asp.net mvc I've created view with two partial views inside.
That view accepts model of some type, for example Customer.
First partial view doesn't have model because it is search form with empty field.
Second form is form with populated fields.
What I found out that on first view, if I have called input fields like properties in model and if I don't provide value for them, mvc implicitly binds values from model to the fields.
First I was thinking is some of kind of mistake, but then I've expiremented little bit with a code:
-I've added native input element with id and name called the same like model, input field is empty in browser
-If I try the same thing with Html.TextBox helper and don't provide value, mvc gets that value from my model object(by name of property/field) and in browser that field is populated.
Is this a bug or am I doing something wrong?
Thanx
That's by design.
I'd recomend reading:
http://asp.net/mvc
http://weblogs.asp.net/scottgu/archive/tags/MVC/default.aspx
and last but not least:
http://channel9.msdn.com/Events/MIX
especially mix10 has a tonn of sessions about mvc
all are good read and watch (-:
That is by design. If you send a model to a view and you're using the HTML input Helpers that come with ASP.NET MVC, they'll implicitly populate themselves from the model.
This is helpful in many situations. If you don't want this behavior, you can always NOT use the helpers or write your own simple helpers.

Editing collections and disabling form persistance

Is there anyway to disable MVC "refilling" from form data for a particular request?
I'm developing an MVC sample that edits a "shopping cart", which contains of a simple list of items and their quantities. So far, so typical.
I'm using editor templates so that I can use EditorFor on the list of items and MVC will generate the Items[x] field prefix and provide me with basically free model binding on the post back.
Part of the sample is to remove items with a quantity of zero between posts. Unfortunately, since the HTML helper methods prioritise form values over model values, this is resulting in the number of items being reduced but the form data of the previous item that was posted at that position. Non-posted data for the row obviously remains correct.
NB. I realise that one would usually utilise the PRG pattern here, but since this is a sample there is no persistance layer (I'm relying on form data + a static product repository implementation).
Edit: To be clear I'm not arguing against the PRG pattern, the sample is simply highlighting model binders and server side validation.
OK, it seems to be the problem I encountered: Strange behaviour in ASP.NET MVC: removing item from a list in a nested structure always removes the last item
The solution I found was to clear the ModelState and then populate with what you need.
Also PRG is possible, you have to store the model and modelstate temporarily in the session and on the GET, retrieve from session and remove. This is exactly what ASP NET MVC Contrib 2 was doing in ActionFilter PassParametersDuringRedirect.

Where do form fields in ASP.Net MVC take their values from?

I understand that fields such as Html.TextBox() accept two values, the first one being the name and the second one being the value. And so does Html.TextArea(). But in a case where the form is submitted as AJAX and the div where the form is placed is replaced with a view from the server, the form fields insist on taking the previous values. An image is worth a thousand words:
image http://img132.imageshack.us/img132/4171/aspnetmvcbug.png
I've checked everything on the controller and the model and the image is from debugging the view itself. The model is empty but the fields generated from it take the value of the previous submission.
The postback data is held in the ModelState. The built in HtmlHelper methods will look for values stored in the model state based on the name of the form element when rendering their content.
Check the View.ModelState property. Forms can grab values from there in certain circumstances.
Do you have an entry ViewData["Body"]? MVC will also attempt to bind a control to a ViewData item based on the name.

asp.net image in a form and HTTPPost

HI,
I'm sure I'm missing something very obvious here so please forgive me.
I'm using MVC 2 Beta and I have a model that has several properties, strings, ints etc. the usual stuff.
It also has a byte array that contains an image.
I have an edit action method on my controller decorated with a [HTTPGet] attribute.
The method passes the model to the view which is a form that has the usual text boxes that bind to the various string properties and an img element that is bound to the byte array/image.
This all works as it should and I see all the data including the image. This is all pretty standard stuff.
But when the user submits the form to my [HTTPPost] version of the action method that accepts the same model as its parameter the image property is null. i.e. the image property does not appear to be part of the model binding.
In the normal course of events we would do some validation and pass the model back to the view to be rendered so the user can see if the edits were successfull or not. But just passing the model back "as is" - the view does not render the image again because its no longer in the model.
I know I can go and get the image again (from the database or where ever) and put it back in the model before passing it to the view, but is that the right stratergy or have I missed something?
Regards,
Simon
How do you render the image that is contained as binary data in model? Do you use classic webforms controls (what would be not recomded in mvc terminology)?
Anyway, if the image is only displayed in the view it is not posted when the user submits the form because only input fields (checkboxes, text fields, hiddens) are submited to the server. image element is not. Remember that in MVC it is simple HTML doing all the work of posting data to the server - there is no viewstate nor automatical postback that will persist the state of the controls.
You have two solutions:
Encode binary data in some hidden field so it would be posted again.
(better) Do not send the image data back and forth between the client and the server, but detect if the user provided new image (i expect you wolud use file input for that) and if the user left the file input empty then update the model with the image already stored in database to display it again. Otherwise update the image in the database.
Anyway, i'm curious how do you display image from binary data in model. I think it would be simpler to create some controller action that would return binary data so you could use URL of that action in src attribute of img tag, or store images as files and use their URL instead of binary data.

Resources