ASP.NET MVC Unbind Action Parameter - asp.net-mvc

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.

Related

Strange Form behavior with Submit ActionResult

Doesn't seem like this should work so I have no idea why it does. I LIKE the result, but worried I can't depend on it because I have no idea how it is working.
[HttpGet]
public ActionResult Modify(System.Guid id)
{
return View("Modify", LoadFromDatabase(id));
}
[HttpPost]
public ActionResult Modify(CaseModel myModel)
{
//So odd behavior. If I redirect to the actual GET Modify,
//I loose any changes on the form. however if I perform the
//same actions but here in the Post... all my unsaved changes
//stick..why?
//This one wipes any edits
return RedirectToAction("Modify", new { id = myModel.ID});
//This one actually leaves all my changes, even though
//I am re-creating the model from the database just like
//the other ActionResult
return View("Modify", LoadFromDatabase(myModel.ID));
}
As Stephen Muecke mentions in the two comments above,
You can depend on it. RedirectToAction() is redirecting to a new page which initializes a new instance of CaseModel based on ID property (i.e. reads the values from your repository. return View() is returning the current instance of CaseModel and if you using the HtmlHelper methods to generate form controls, it will use the values from ModelState which are added by the DefaultModelBinder when you submit the form. Refer this answer for more explanation of the behavior). #Html.TextBoxFor(m => m.someProperty) will display the value you posted, whereas #Model.someProperty will display the 'updated' value you set in the post method
works perfectly. The HTML helpers overwrite my Model values with the ModelState (aka ViewState).

Clear All Fields on MVC4 Razor View on both: Loading and after Back to Page

What is the most effective method in order to make all the fields on an MVC4 Razor empty when loading it (for example first loading or after backing to the page again)? If it is possible could you please suggest me a way with the help of Razor properties instead of using Javascript/jQuery.
It's a little difficult to make out what you're trying to do, but let's see if I can help.
Firstly, if you simply wanted to clear out a form's values after it's been posted, you can do that like so:
[HttpPost]
public ActionResult Index(ViewModel model)
{
ModelState.Clear();
model = new ViewModel();
return View(model);
}
Simply creating a new ViewModel isn't enough, as the ModelState dictionary will try to repopulate the form with the old values. This does what you want, but isn't really leveraging MVC to do what you want.
The better way to do it would be to redirect back to the action you use to display your form. Something like this:
public ActionResult Create()
{
var model = new ViewModel();
return View(model);
}
This is simply passing in an empty model to your form. Once the user fills out the form, and it's posted back to the server, you can handle it like so:
[HttpPost]
public ActionResult Create(ViewModel model)
{
if (ModelState.IsValid)
{
// Form data is valid so redirect back to display the form again
return RedirectToAction("Create");
}
// If we get here, redisplay the form with the fields filled in
// and errors shown
return View(model);
}
Simply calling a ModelState.Clear() will do the trick. You shouldn't have to instantiate the view model again.
A view displays (or collect) information about a Model.
So, if you pass an Empty model (that is: properties in null or blank or default values) it will "clear all fields".
All you have to do is invoking again the Action that displays the view, now passing an empty model.
EDIT:
You can do it in javascript, but then you have to duplicate and maintain the logic of what are default values.

How can ViewBag data be saved after a form post?

So I have a ViewBag.Something and this data is randomly generated. In my view, I set this to a label like so #Html.LabelFor(m => m.Something, (string)ViewBag.Something). This works out well but when I submit the form there could be errors and if there are errors, I need this label to remain the same, I don't want dynamic/random data anymore so I wouldn't call the controller method that generated this ViewBag. Is there a way to retain this value without having some private variable in my controller? Some nice way that MVC/Razor does it?
Option 1:
Pass the value of "ViewBag.Something" to the Controller by using route Values:
#Html.ActionLink("ButtonText", "ActionName", new { Something = #ViewBag.Something })
Option 2:
You can use TempData.
public ActionResult Index()
{
var Something = "YOURVALUE";
TempData["Something"] = Something;
.......
}
public ActionResult OtherAction()
{
var Something = TempData["Something "];
...........
}
Passing State Between Action Methods
Action methods might have to pass data to another action, such as if an error occurs when a form is being posted, or if the method must redirect to additional methods, as might occur when the user is directed to a login view and then back to the original action method.
An action method can store data in the controller's TempDataDictionary object before it calls the controller's RedirectToAction method to invoke the next action. The TempData property value is stored in session state. Any action method that is called after the TempDataDictionary value is set can get values from the object and then process or display them. The value of TempData persists until it is read or until the session times out. Persisting TempData in this way enables scenarios such as redirection, because the values in TempData are available beyond a single request.
In the get, set up a model, set it dynamically and when return view() is being executed, do return view(model). Then in the view, set up a hidden field that can keep on passing the value needed. I chose to go this route because I don't have to worry about any server code to make this work on a post and I don't have to worry about any sessions.
Displaying message in viewbag after posting (I user this method)
ActionResult SubmitUser(){
ViewBag.Msg =TempData["Msg"];
return view();
}
[HtttpPost]
ActionResult SubmitUser(){
TempData["Msg"] ="Submitted Successfully"];
return view();
}
The Value is send to get method..

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 Form repopulation

I have a controller with two actions:
[AcceptVerbs("GET")]
public ActionResult Add()
{
PrepareViewDataForAddAction();
return View();
}
[AcceptVerbs("POST")]
public ActionResult Add([GigBinderAttribute]Gig gig, FormCollection formCollection)
{
if (ViewData.ModelState.IsValid)
{
GigManager.Save(gig);
return RedirectToAction("Index", gig.ID);
}
PrepareViewDataForAddAction();
return View(gig);
}
As you can see, when the form posts its data, the Add action uses a GigBinder (An implemenation of IModelBinder)
In this binder I have:
if (int.TryParse(bindingContext.HttpContext.Request.Form["StartDate.Hour"], out hour))
{
gig.StartDate.Hour = hour;
}
else
{
bindingContext.ModelState.AddModelError("Doors", "You need to tell us when the doors open");
}
The form contains a text box with id "StartDate.Hour".
As you can see above, the GigBinder tests to see that the user has typed in an integer into the textbox with id "StartDate.Hour". If not, a model error is added to the modelstate using AddModelError.
Since the gigs property gigs.StartDate.Hour is strongly typed, I cannot set its value to, for example, "TEST" if the user has typed this into the forms textbox.
Hence, I cant set the value of gigs.StartDate.Hour since the user has entered a string rather than an integer.
Since the Add Action returns the view and passes the model (return View(gig);) if the modelstate is invalid, when the form is re-displayed with validation mssages, the value "TEST" is not displayed in the textbox. Instead, it will be the default value of gig.StartDate.Hour.
How do I get round this problem? I really stuck!
I think the problem is that your ViewModel does not match closely enough with your View. It's really important in MVC that your ViewModel matches your View as closely as possible.
In your ViewModel you're assuming an integer, but in your View you're using a TextBox to render the property, which will allow any kind of text. There's a mismatch here and the difficulties you are experiencing trying to map them is a symptom of the mismatch.
I think you should either:
1. Change the type of the ViewModel property to string and then do validation in your controller to ensure the string entered is actually a number or:
2. Change the control that the View renders to a control that will only allow a number to be entered via a custom control or Javascript validation (as #Qun Wang recommends)
Personally, I'd recommend option 1. That way the ViewModel is not dependent on the View implementation.
Could you do this in your PrepareViewDataForAddAction method?..
if (!ViewData.ModelState.IsValid)
{
ViewData["StartDate.Hour"] = "Error";
}
The other fields on the form will still populate based on the properties of the Gig object.
I think you need to do some basic client side validation first.
don't allow it to post to the server.

Resources