Html.HiddenFor handles string and int differently - asp.net-mvc

My model:
public class VerifyModel
{
public string PIN { get; set; }
public int Attempts { get; set; }
}
My view:
#Html.HiddenFor(m => m.PIN)
#Html.HiddenFor(m => m.Attempts)
On entry into the view, I inspect Model.PIN and Model.Attempts and they contain the correct values passed from the controller, where Attempts is non-zero. The Html rendered is however:
<input id="PIN" name="PIN" type="hidden" value="xxxx" />
<input data-val="true" value="0" data-val-number="The field Attempts must be a number." data-val-required="The Attempts field is required." id="Attempts" name="Attempts" type="hidden"/>
The value of Attempts is always 0! And I did not specify anywhere that the Attempts field is mandatory.
How do I solve the problem of int properties in the model?

If I've understood your question correctly, you're having problems with Attempts not incrementing after the form is posted back with an incorrect PIN. If that assumption is correct then you're experiencing this problem because of the way ModelState works.
The short answer to the problem is simply to call ModelState.Remove from your action:
[HttpPost]
public ActionResult YourAction(VerifyModel model)
{
ModelState.Remove("Attempts");
model.Attempts++;
return View(model);
}
If you'd like a full explanation of why this is the case, see ASP.NET MVC’s Html Helpers Render the Wrong Value!. Excerpt:
Why?
ASP.NET MVC assumes that if you’re rendering a View in response to an HTTP POST, and you’re using the Html Helpers, then you are most likely to be redisplaying a form that has failed validation. Therefore, the Html Helpers actually check in ModelState for the value to display in a field before they look in the Model. This enables them to redisplay erroneous data that was entered by the user, and a matching error message if needed.

Related

ASP.NET MVC Encoding Issue

I have an ASP.NET MVC app. My app is passing a name to/from the database. I've recently discovered a bug associated with ampersands (&).
In my database, I see the name "A & W".
I am displaying this value in my UI using the following:
<input id="Name" name="Name" value="#Html.Raw(Model.Name)" />
When I view the source, I can see that the following HTML gets rendered in the browser.
<input id="Name" name="Name" value="A & W" />
So far, so good. However, when I click save, and I set a breakpoint in my controller action, I can see the Name property on my Model is now "A & W". What's worse is, everytime I save it, additional amp values get added.
How do I remedy this?
Thanks!
I had a similar problem, so I used the AllowHtml attribute on my property in my model.
[AllowHtml]
public string Name { get; set; }
If you aren't using Code First, you can apply this attribute on top of your action also:
[HttpPost]
[AllowHtml]
[ValidateAntiForgeryToken]
public ActionResult Modify(ModelClass model) {}

MVC #Html.CheckboxFor submits true,false on form submission

I am using MVC 5 with EF Code First and have a View model that contains a bool:
public bool MyCheckbox { get; set; }
I initialize this in my View's get:
model.MyCheckbox = true;
In the View:
#Html.CheckBoxFor(m => m.MyCheckbox)
Which get rendered as:
<input checked="checked" data-val="true" data-val-required="The field is required." id="MyCheckbox" name="MyCheckbox" type="checkbox" value="true" />
<input name="MyCheckbox" type="hidden" value="false" />
One of my Buttons on the View triggers an Ajax POST to the Controller where I want to look at the checkbox value:
bool bValue = Request["MyCheckbox"] == "true";
But the value of Request["MyCheckbox"] is "true,false" due to the extra hidden field with name="MyCheckbox".
How do I view the value of this checkbox in the controller with Request["..."] and make sense of it (either true or false)?
I also have another bool member in the View model and I use it in a hidden field intentionally. In the model:
bool MyHiddenBool { get; set; }
In the Controller Get:
model.MyHiddenBool = true;
In the View:
#Html.HiddenFor(x => x.MyHiddenBool)
In the Controller (via Ajax POST):
bool AnotherBool = Request["MyHiddenBool"] == "true";
But the value of Request["MyHiddenBool"] is either "True" or "False" instead of "true" and "false".
What gives with this inconsistency and how can I reliably see the values of these two methods of bools in my Views?
The problem is how you are consuming the form request variable.
In ASP.NET MVC there's probably never a good reason to use Request.Form or it's variants to consume your request data. You need to make a model or put in an argument for the action.
[HttpPost]
public ActionResult PostedForm(bool myHiddenBool)
{
//Frameworks model binder will extract the form field into your variable based on the name
}
The following copied from this answer.
This isn't a bug, and is in fact the same approach that both Ruby on
Rails and MonoRail use.
When you submit a form with a checkbox, the value is only posted if
the checkbox is checked. So, if you leave the checkbox unchecked then
nothing will be sent to the server when in many situations you would
want false to be sent instead. As the hidden input has the same name
as the checkbox, then if the checkbox is unchecked you'll still get a
'false' sent to the server.
When the checkbox is checked, the ModelBinder will automatically take
care of extracting the 'true' from the 'true,false'

How to specify that a Search Input field is required

I am working with an asp.net mvc web application and i have a text input field to enter a search criteria, but my question is how i can define that this field is required incase the user click on the search button. i was thinking of manually adding the following data dash attributes, to simulate how the [Required] model data annotation works .
<input name="selectedUserNames" type="text" data-val="true" data-val-required= "Please enter a value." data-autocomplete-source= "#Url.Action("AutoComplete", "SecurityGroup")" />
<span class="field-validation-valid" data-valmsg-for="selectedUserNames" data-valmsg-replace="true"></span>
<input type="submit" value="Seach" />
What you are doing is not a clean solution, and it only works on the client side. You should create a SearchViewModel like below and pass it to your View:
public class SearchViewModel
{
[Required]
public string Search { get; set; }
}
And, in your View:
#Html.TextBoxFor(model => model.Search)
#Html.ValidationMessageFor(model => model.Search)
as noted in previous answer, enabling only client side validation is not a complete solution. what if the client has disable javascript on their browser? then your validation want fire.
best option you have is to use DataAnnotation [Required] attribute. In your view enable client side validation.
If the client has disable javascript on browser server side validation will fire.

Html.HiddenFor sporadically not getting set w/ model information

We're having an issue with Html.HiddenFor in MVC3 occasionally not getting bound properly. We can't reproduce it at all, but we're seeing nullrefs come through in our logging and it's driving us absolutely nuts.
We have the following model and controller structure:
public class DummyController
{
[HttpGet]
public ActionResult ReturnAPage(int NumericID)
{
//NumericID should never be 0 or negative, but let's check to make sure
if (NumericID < 1)
{
return RedirectToAction("TracyJordanStabbingRobot");
}
return View("DummyView", new DummyViewModel(NumericID));
}
[HttpPost]
public ActionResult TakePageSubmission(DummyViewModel model)
{
//AnObject relies on having a non-zero ID
ComplexObject AnObject = new ComplexObject(model.NumericID);
AnObject.UseMe();
}
}
public class DummyViewModel
{
public DummyViewModel() {}
public DummyViewModel(int ID)
{
NumericID = ID;
}
public int NumericID { get; set; }
}
... and the following view structure:
DummyView.cshtml
#model DummyViewModel
<html>
<head></head>
<body>
<p>THIS IS A VIEW!</p>
<form id="DummyViewForm" action="/RouteTo/TakePageSubmission" method="post">
#Html.Partial("_PartialDummyView", Model)
<input type="submit" value="Submit This!" />
</form>
</body>
</html>
_PartialDummyView.cshtml
#model DummyViewModel
<p>Heard you like views...</p>
#Html.HiddenFor(model => model.NumericID)
Considering we're checking for less-than-zero values in the initial controller action, it stands to reason that #Html.HiddenFor(model => model.NumericID) should never have a less-than-zero value.
That being said, when we get to using AnObject in the TakePageSubmission action, we're getting null reference errors.
When we dug into logging the model.NumericID value, we're seeing it come through as zero, which shouldn't be possible considering the DummyView can only be accessed with a non-zero value.
We're a little stumped and since we can't reliably reproduce the issue, we have no idea what could possibly be causing it. Has anyone run into something like this before?
Edit: We are doing ModelState validation on the form post, but we're not checking to see if the NumericID coming through is 0. When we did check for that, the model came through as invalid, which just proves that the HiddenFor is getting set improperly. Furthermore, the route to the page actually includes the NumericID, so for example, we've seen this happen on:
http://our.site.com/RouteToReturnAPage/1736/
...where the parameter for the action is clearly set, the model is constructed correctly, but for some unknown reason the HiddenFor NumericID value is 0. It's really baffling.
Your default 0 value bindings are from MVC View'ing to the same page after post, thinking it is reloading the same view due to an error during the post. The correct binding will occur on a load/action call to a different Action call.
There is a hack workaround, to ModelState.Clear(); before you reload the View.
Also, not using the Helpers to create the hidden fields at all, something like:
<input type="hidden" value="#Model.NumericID" id="NumericID" name="NumericID" />
Reference:
http://blogs.msdn.com/b/simonince/archive/2010/05/05/asp-net-mvc-s-html-helpers-render-the-wrong-value.aspx
First you are missing default constructor in your model. Without it applicaiton throws exception when binding.
You can reproduce the error by editing the hidden field on client side. So user can change id to 0 or any other value. If you aren't running you application on distributed enviroment then use TempData to pass the id between actions. This way you will keep id safe from data tampering.
TempData["NumericID"] = NumericID;

HTML.CheckBox Behaviour

I am using a model where a check box is there . where i am posting the form i always get more than one boolean value, Code is as follow
//controller code
// GET: /Home/
// GET: /Home/Test
public ActionResult HomeTest()
{
HomeTest ht = new HomeTest();
return View(ht);
}
[AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
public ActionResult HomeTest(FormCollection collection, HomeTest model)
{
string str = collection["test"].ToString();
return View(model);
}
//View Html
<%= Html.CheckBox("test") %>
I am getting following value in str while debugging "true,false". Am i do anything wrong?
This is how Html.CheckBox was designed!
It always renders
<input name="test" type="checkbox" value="true" />
followed by a
<input name="test" type="hidden" value="false" />.
When you submit the form with the checkbox checked, you'll get test=true,false and when the checkbox is unchecked, you get test=false.
This is how it supports binding to a boolean value, because the ,false part is ignored. However, if you're binding to something else (such as string), that's when you'll see the "true,false" value.
If you want different behavior, you'll have to roll-your-own Html.CheckBoxAlt method. Here's a similar question, along with some code, that I wrote a while back: Passing checkbox selection through to an action
MVC does things this way so it can tell the difference between "There is no checkbox called 'test'" and "The checkbox called 'test' is unchecked." Since HTML doesn't provide any built-in way to tell the difference, MVC makes it always send a "false" value, which will get overridden by a "true" value if you check the box.
The easiest solution is to make better use of MVC's approach. Rather than using the FormCollection, just use a parameter that the model binder can bind to:
public ActionResult HomeTest(bool test, HomeTest model)

Resources