Search code examples
razorhiddenasp.net-mvc-5

MVC 5 Razor changes bool value in HiddenFor helper


The problem is Razor (MVC 5) renders out HiddenFor and Hidden helper incorrectly.

I have a view model like this:

public class MyViewModel
{
    public bool BoolValueInsideViewModel { get; set; }

    public MyViewModel()
    {
        BoolValueInsideViewModel = false;
    }
}

and controller is simple as:

model = new MyViewModel();
        model.BoolValueInsideViewModel = false;
        return PartialView("_MyView", model);

Second line is just to be sure value is set to false. View looks like this:

@model MyViewModel
@Html.Hidden("BoolValueInsideViewModel", false)
@Html.Hidden("BoolValueNotInViewModel", false)

But on browser I get this:

<input data-val="true" data-val-required="The BoolValueInsideViewModel field is required." id="BoolValueInsideViewModel" name="BoolValueInsideViewModel" type="hidden" value="true">
<input id="BoolValueNotInViewModel" name="BoolValueNotInViewModel" type="hidden" value="False">

Note that I have like 15 other view models and controller methods in same controller works fine with same code (I use HiddenFor with strongly typed values normaly, here I changed to Hidden to show that it does not work even with hard coded value in view).

Putting a break point on view, shows model is actually has BoolValueInsideViewModel equal to false, but result on browser is different. Also I get the result via JQuery post callback, so I checked raw string returning from AJAX function and the value there is also "True" instead of false.

What I tried:

  1. Clean up project and rebuild!
  2. Renaming property
  3. Renaming view model, even renaming file containing view model
  4. Renaming view

I know! It looks stupid and the most simplest thing on ASP.NET MVC, but I spent half a day on it. Other view models and partial views render correctly.

The weird thing is I don't have any data annotation on view model, but why it includes data validation attributes on the HTML element?


Solution

  • For me, it was because my url had a query parameter with the same name as the viewmodel property. It seems the model binder is overriding the model value with that in the query string.

    I've confirmed this by changing and removing the query string parameter and values, and get consistent results.

    For example,

    1. let's say the query string param is: showMore=False
    2. you have a model property of the same name, set to True.
    3. check the value of Model.showMore will be True
    4. check the value of the @HiddenFor(m => m.showMore), it will be False
    5. change the query string param to showMore=True, check the value of @HiddenFor(m => m.showMore), it will be True
    6. remove the query string param showMore, check the value of @HiddenFor(m => m.showMore), it will be True

    Conclusion: the query string parameter value overrides the model value. Not sure if that is by design or a bug.