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.
Related
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.
I've understood that a viewmodel in MVC is supposed to reflect data on a single page rather than objects in the model. But should the viewmodel correspond to the data you want to show on that page or to the data you want back from that page? If we for example look at a login page then I just want username and password back in the post, but I might need more variables than that when displaying the login page (previous error messages etc).
Should the viewmodel then just contain username and password as parameters and the rest of the variables end up in viewbags. Or should the viewmodel contain all values I want to show even though I'm only interested in a few of them in the response.
What is best practice when using viewmodels?
All data that somehow interacts between the html and your server should be in a ViewModel.
This allows you to perform formatting and such outside your html and inside your ViewModel properties.
However, if your page contains a lot of controls or data, you may want to split it into multiple ViewModels (example one for the Get and one for the Post).
The post model may contain only data that you entered and needs to be validated.
I think it's best to put everything in the view-model. This keeps the code cleaner and makes discovery and maintenance easier as well. The view-model should be your primary mechanism here.
I would say only properties you need, in your case username and password. If you want to display error messages then that's what ModelState is for. You can always append any error messages to your ModelState:
ModelState.AddModelError("PropertyName", "Error Text")
Beyond that let's say you have a form that contains a list of categories that you need to pick one category from a drop down. In this case I usually attach that list to my model even though the only thing being submitted is the actual selected value. But this is a matter of preference, meaning I could also set a ViewBag to contain this SelectList of categories and then bind that to your DropDownList. I suppose it's better to place this in a model because ViewBag is dynamic and you will have to cast anything in the ViewBag into it's underlying type on your views.
I have a view, model and a controller, I want the user to start editing the page of a new contact.
They will
Enter the First and Last Name
Click Save
The Controller commits the save.
Expand the page to Show display name for editing.
In forms Asp.net I stick the Primary Key of the Saved record in the view state so on the next save, I do an update vs. an Insert.
How do I do that in MVC, Razor? I have seen examples using a Hidden Field but I would think there is a better way. I would prefer it not shown at all, or at least encrypted but I do not want to build the encryption or decryption routines.
User HiddenFor() method of Html helper class. #Html.HiddenFor(model => model.Id). By the way, ViewState is stored in a hidden field in ASP.NET.
If you are really wanting to encrypt the data like in viewState, you can use Html.Serialize()method which serializes and encrypts entire model in view and you will then have to De-serialize it in the controller after it's posted. Have a look at this article
I have a Product edit screen. The user can select a Vendor for the Product. To do this, I display a jQueryUI dialog box which allows them to browse for and select a Vendor. When the user selects the Vendor, I update a hidden VendorID input on the page, which is part of my page's model. I also update several divs with details about the Vendor they have selected. These are for display purposes only--only the id is needed to persist the selected Vendor.
This all works fine and dandy except when there is an error on postback, in which case I redisplay the same view. ModelState takes care of preserving all my form fields (including the hidden VendorID). However, my divs with the Vendor text are (of course) empty since they're not posted to the server.
I first went down the path of creating hidden fields for each of my Vendor display fields and putting them on the model. Then the hidden fields survive the postback, but that doesn't solve the problem of actually redisplaying the text on the screen.
The three options I can think of are:
On postback, if there is an error, go to the database, fetch the Vendor using the supplied VendorID and re-populate the model with the text I want to display.
Use RenderAction and have an action which renders the details of the selected Vendor.
Use readonly textboxes instead of divs to display the Vendor details.
None of these feel very satisfactory to me. I feel like I might be missing an obvious solution. Are there any better solutions?
I would suggest you not have the extra Vendor information come down as part of the main page. Create a javascript function showVendorInfo(). When called, if the VendorID hidden input has a value, it gets the relevant Vendor information via AJAX and displays it, using an AjaxGetVendorInfo action method. Call this function from two places:
In document.ready()
after a Vendor is selected with jQueryUI display.
Now, this would be in an action method. You could, if you expect your users to have latency issues, do the following to avoid some ajax calls: In the view check if you know the VendorID; if so, call Html.RenderAction call the same AjaxGetVendorInfo action method from the view.
A bonus to this is that it avoids what I have found to be a big no-no: Including both display-only values and model-binding values in your ViewModel. This makes for a very confusing ViewModel, especially when there are validation errors. [Getting on soap box] It's best to have your ViewModel to just have properties intended for modelbinding, for your state. Put list values, extra display information, etc., into ViewData or have them show up via AJAX.
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.