MVC posted values - asp.net-mvc

In asp.net MVC application we have mechanism where, when we submit
a form and if there is any problem with the values (validation fails),
the form is displayed back maintaining old values. How does it happen ?
Where are these values kept ? or they collected from FormCollection.
Help will be apprititated.
Regards
Parminder

It really depends on how you set up your Controller Actions and your Views, because ASP.NET MVC looks in multiple places for the values.
Your assumption that it uses the FormCollection is kind of wrong, since the FormCollection is something that your controller Action takes in as a parameter and is totally separate from your View, where the values actually end up being displayed.
In 1.0, by default, the Edit template for views uses the 2nd parameter on most of the HtmlHelpers, like:
<%=Html.Textbox("Title", Model.ID)%>
This would have the old value pulled from the bound model object. So if you explicitly fail validation and return a View(object), the values would be pulled from that object. Still, if you are explicitly failing validation like:
if (ModelState.IsValid == false)
{
return View();
}
Then the HtmlHelper code will likely result in an error, because no Model was bound.
If you completely leave off the 2nd parameter, like:
<%=Html.Textbox("Title")%>
The value will be pulled from the post (Request.Form) values.

One way to do it is to use ModelState.AddModelError
A good tutorial on MVC Error handling can be found here

You can do that by returning the view with tha data
if (ModelState.IsValid == false)
{
return View(X);
}
X is the data u need to return

Related

Is returning different view with object bad practice in ASP.net MVC 5?

I need to pass objects between ActionMethods and Views in an ASP.net MVC 5 app.
I'm using it for a multi page signup - and for a multi page payment.
Is this bad practice? I haven't seen a good way to pass objects between different controllers.
Code:
public ActionResult Join1()
{
//
return View("Join2", MyObject);
}
[HttpPost]
public ActionResult Join2(MyObject MyObj)
{
//manipulate object
//return
}
It seems to be an effective way to do it - though I haven't seen many people do it this way. I haven't seen objects being passed between action methods much at all.
Is there a flaw in this approach, a better way of passing models between Views - or should each ActionMethod stick to passing simple data with, say, TempData instead of objects?
Why haven't I seen any sample projects doing things like this?
I've seen return RedirectToAction("act"); plenty - but that is Get and passing an object in a URI is limiting - and I don't want users to be able to manipulate or see the data being passed.
thx.
Unless I have misunderstood the description, your code is not doing what you think it's doing. That first return View("Join2", MyObject); statement is not executing the second ActionMethod, it is only passing your data into the View that happens to have the same name as the second method. Therefore the code implied by //manipulate object will not run before that View is rendered and sent back to the user.
Assuming the View file Join2.cshtml exists, and it contains the default #using (Html.BeginForm()), then users submitting the form will cause the Join2 Action to be executed and the same view rendered with the manipulated data - unless, of course, you add another return View() statement that names a different View.
The reason you haven't seen this done much is that the MVC convention is to have a View named the same as the ActionMethod, this makes the code slightly simpler and also much easier for other ASP.NET developers to understand because it is what they are expecting to see.
If you want the form rendered by each View to then execute a different ActionMethod when it is posted back, the place to do that is in the View code, where Html.BeginForm() has several overloads that allow you to do just that, e.g. in Join.cshtml you could write:
#using (Html.BeginForm("Join2", "JoinController"))
{
// form fields and stuff
}
// Produces the following form element
// <form action="/JoinController/Join2" action="post">
To address the final part of your question, "I don't want users to be able to manipulate or see the data being passed", sorry to say it but your proposed code doesn't prevent that: users can see the data in the web form, before it is ever posted back to the Join2 method; they can manipulate the data by sending an HTTP POST containing any data they want back to the Join2 method.
If you absolutely, positively need to actually execute Join2() from within Join(), before anything is passed back to the user, then you can call it just like any other C# method:
var myResult = Join2(MyObject);
Then you have an ActionResult object that you can manipulate or return straight to the browser. But why you would want to do this, is beyond me.

How to access data from differnt partial view after POST

I have 3 partialviews with 3 viewmodels on page:
List of accounts
Modal popup (you can modify multiple accounts here)
Search panel
I want to refresh 1. after doing POST on 2. This is straightforward, but what if I want to keep results I got after using Search Panel?
I can do this in 2 ways but both seems bad (correct me if I am wrong).
First (the one I chose and works) is to store viewmodel used in 3. in TempData. I do Search (POST) and save passed viewmodel in TempData. Then whenever I do POST on different partialview I can refresh 1. using data(search parametrs) from TempData.
private const string SearchDataKey = "SearchData";
[HttpGet]
public PartialViewResult RefreshData()
{
if (TempData[SearchDataKey] != null)
return PartialView("AccountListView", PrepareAccountListViewModelForSearchData(TempData[SearchDataKey] as AccountSearchViewModel));
else
return PartialView("AccountListView", PrepareAccountListViewModel());
}
and saving ViewModel:
public PartialViewResult Search(AccountSearchViewModel searchParameters)
{
...
TempData[SearchDataKey] = searchParameters;
return PartialView("AccountListView", databaseAccountListViewModel);}
Second approach is to always POST "big" viewmodel with all 3 viewmodels. This way I will have data from Search's viewmodel but I will send many not needed information instead just Modal Popup's viewmodel which I need to call procedure.
I asked few MVC folks with better experience and they said they never had to store viewmodel in TempData but it still seems more reasonable than having 1 Big form and passing everything in every POST.
Do you know any better ways to handle this or which one is correct?
PS. Topic had "Best Practice" but was removed cause of warning message. I hope asking about opinion is still allowed on SO.
PS2. Most of my POSTs & GETs after initial load are through Ajax.
I do Search (POST)
This seems semantically incorrect to me. Searching is an action that shouldn't modify any state on the server. So using GET seems more appropriate. And when you use GET you have the benefit that all parameters are already present in the query string and thus preserved upon successive POST actions (like modifying an account in your case). So your RefreshData action could take the AccountSearchViewModel as parameter and the model binder will take care of the rest.

ASP.NET MVC 3 POST ModelState and ViewModel

In my ASP.NET MVC 3 app I have a page where, after its form is submitted I need to change a value from the form. If I do it in the ViewModel it has no effect, I have to do it use ModelState["Field"].Value.
The thing is that I actually have a lot of work I have to do on the ViewModel when the pages loads AND after the POST. So I have a method which receives the ViewModel and do all that work. But, as I said, after the POST, modifying the ViewModel object is useless. Why is that? The method on the controller is returning View(viewModel);. Shouldn't the view use the ViewModel values?
I'd like to understand why is useless to modify the ViewModel and also know if there is some method in the ModelState which "refresh" the fields values throw a ViewModel object.
Here is my controllers code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(MyViewModel viewModel)
{
try
{
if (ModelState.IsValid)
//Do stuff and redirect
}
catch(Exception ex)
{
//Log and add error to the ModelState
}
someMethodWhichDoesALotOfThingsInTheViewModel(viewModel);
return View(viewModel);
}
I think the rest of the code is unnecessary, if anyone think it would help let me know!
Update
I don't want to lose any errors, not even those of the fields changed in the ViewModel. A good example would be a captcha, if the users makes any error in the form (only with the captcha field or only with any other fields and not with the captcha) I want to show him all his errors and also update the captcha. It makes no sense to render the form with the old captcha value inserted so I want to blank that field.
Update 2
I've opted to put #Value = Model.PropertyInViewModel in the HTML Attributes of each Html.TextBoxFor. But I'd prefer to avoid that nasty work so if someone comes out with any better solution please let me know.
The following will work:
ModelState.Remove("MyProperty");
viewModel.MyProperty = "new value";
You need to remove it from the model state because HTML helpers first look in there when binding their value.
All I could came out with is to add #Value = Model.PropertyInViewModel to each Html.TextBoxFor that is going to be modified in the ViewModel.
Another way, as #Darin Dimitrov said, would be to make my own helpers.
If you decide to remove modelstate values to prevent round-tripping take a look at this RemoveFor() extension method I made to remove ModelState errors without magic strings.

ASP.NET MVC auto-binds a refreshed model when ModelState is invalid on HttpPost

I'm working on an ASP.NET MVC2 app. I've come to realize a very surprising, yet amazing thing that MVC does behind the scenes having to do with the ModelState and model binding. I have a ViewModel which has a whole bunch of data - some fields being part of a form while others are simply part of the UI. On HttpPost, my Action method uses the DefaultModelBinder which attempts to bind the whole model, but only fields which were part of the form are successfully deserialized - all others remain null. That's fine and understandable. If the ModelState is invalid, I need to refresh the model from the db and bind those particular form fields before returning to the same edit view to display those associated ModelState validation errors.
Here's where my amazement and curiosity comes. It was my assumption that in order for me to bind the form fields with the refreshed model, I needed to make a call to either UpdateModel() or TryUpdateModel<>(), passing in the newly refreshed model. For example:
[HttpPost]
public ActionResult EditDetail(EditDetailItemModel model)
{
if (model.IsValid)
{
// Save the results to the db
return RedirectToAction(...)
}
// Can't simply "return View(model)". Not all fields in EditDetailItemModel
// were part of the form - thus they returned null. Have to refresh
// model from the db.
var refreshedModel = RefreshModelFromDB();
// Is this line necessary?????
TryUpdateModel<EditDetailItemModel>(refreshedModel);
return View(refreshedModel);
}
But, what I found was that if I simply returned refreshedModel to the view WITHOUT making a call to TryUpdateModel<>(), the refreshed model was automatically bound with the form field values posted!! Hence, the TryUpdateModel<>() is not needed here!
The only way I can make any sense of it is that since the ModelState is in an invalid state, once I returned the view with the refreshed model, the "MVC rendering engine" looped through the ModelState errors and bound those property values with my refreshed model. That is simply AWESOME! But, I want proof as to this assumption. I can't find documentation regarding this anywhere on the web. Can anyone either confirm my hypothesis of WHY/HOW this AWESOME auto binding behavior is occuring and/or educate me as to why/how it's happening, hopefully backed up with some online documentation links so I understand more fully what's going on under the covers?
public ActionResult EditDetail(EditDetailItemModel model)
That line will perform model binding. Think of ActionMethod parameters as always being populated by a call to UpdateModel.
You are not seeing refreshedModel's values in the view, you are seeing the ModelState entries and values from EditDetailItemModel.

ASP.NET MVC Unbind Action Parameter

Is it possible to disable a certain action parameter from retaining its value across requests?
[HttpPost]
public ActionResult MyAction(string value1, string value2)
{
if(value1=="hi")
ModelState.AddModelError("value1", "Can't have hi");
//do stuff
if(ModelState.IsValid)
return RedirectToAction("Finish");
else
return View()
}
[HttpGet]
public ActionResult MyAction()
{
return View()
}
The view consists of a simple form with two input boxes (value1 and value2). Once submitted and validation fails, the view is returned. I want to always have the value of the textbox in the view to be empty.
The value for the textbox "value1" is retained if the the model is invalidated.
I tried to declare the textbox as <%= Html.TextBox("value1", null) %> but the value is still retained. I also tried to use [Bind(Exclude="value1")] but that dosen't work on a single variable.
Update 2:
I'm doing this for a textbox that is used for Captcha (custom solution) input. I want the textbox to be cleared any time the page is loaded, but I want validation to remain.
Try calling
ModelState["value1"].Value
= new ValueProviderResult(null, string.Empty, CultureInfo.InvariantCulture);
before you return the view from within your controller action.
What this does is keep all the errors associated with the key "value1", but replaces the value with an empty value.
What are you doing that's causing it to be retained? There isn't anything like ViewState in MVC that will persist a value over multiple requests unless you're writing code or using form fields to make it do so.
What does the view look like? Is this action method being called via GET or POST? What's the "do stuff" contained in your method?
Edit: You're still showing //do stuff in your example code. Does that stuff contain any references to ViewData? Your question is about binding, but I don't see any binding happening. Maybe this is beyond my understanding.
Edit 2: Glad Phil saw this one! The original question didn't mention the ModelState.

Resources