50

I have an MVC application that displays a value. This is the controller:

public ActionResult Index(DataSites DataSiteList)
{
    if (DataSiteList.Latitude != null)
    {
        DataSites test = new DataSites();
        test.Latitude = "LATITUDE";

        return View(test);
    }
    return View(DataSiteList);
}
public ActionResult SomeInformation()
{
    DataSites test1 = new DataSites();
    test1.Latitude = "LATITUDE2";

     return RedirectToAction("Index", test1);
}

The View:

@model miniproj2.Models.DataSites

<p>
    @Html.TextBoxFor(x => x.Latitude)
</p>

And the Model:

public class DataSites
{
    public string Latitude { get; set; }
}

When I go to /Home/SomeInformation, the DataSites' Latitude property is set to "LATITUDE2". Then redirects to the Index() action in the controler, sets the property to "LATITUDE" and returns the view.

When it shows the view, it displays the value "LATITUDE2" as set in the redirect. Shouldn't "LATITUDE" be displayed?

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
Adrien Tancrez
  • 599
  • 1
  • 4
  • 8
  • Install fiddler and watch what actually happens when you call `RedirectToAction` - your answer is there. – asawyer Oct 30 '14 at 13:54
  • I never use Fiddler , can u give me an explanation ? – Adrien Tancrez Oct 30 '14 at 13:58
  • 1
    `DataSiteList.Altitude != null` is it a misspelling or the `altitude` property actually exist in your model `DataSites`? – Aymeric Oct 30 '14 at 13:58
  • a ''logical'' explanation because i give to right object to my view ... i dont understand – Adrien Tancrez Oct 30 '14 at 13:58
  • Sorry it was a misspelling i just removed it for the post .. – Adrien Tancrez Oct 30 '14 at 13:59
  • Inside SomeInformation you are setting test1.Latitude, but Index is checking test1.Altitude for a value. It does not find one so returns DataSiteList not test. – Nigel Ellis Oct 30 '14 at 13:59
  • 1
    Try this, replace the `return RedirectToAction("Index", test1);` to `return Index(text1);`. –  Oct 30 '14 at 13:59
  • 1
    @AdrienTancrez Maybe you should start, it's an invaluable debugging tool for web development. – asawyer Oct 30 '14 at 14:01
  • @AdrienTancrez - If thats a misspelling, I would correct considering that two of your answers so far are pointing this out - but it wouldn't solve your problem anyway. – JasCav Oct 30 '14 at 14:02
  • 1
    @TiagoSilva That's not a great solution as the url won't change. – asawyer Oct 30 '14 at 14:03
  • @asawyer, well, the solution is to use `TempData` it, as in response JasCav. –  Oct 30 '14 at 14:09
  • @JasCav I don't disagree I was just mentioning a drawback to the approach in your comment. I'd use a separate action entirely with a directive parameter on the route to accomplish this and keep the thing as stateless as possible. – asawyer Oct 30 '14 at 14:15
  • @asawyer - I think you pinged the wrong person. I'm not agreeing or disagreeing either way...just giving the response based on my knowledge. – JasCav Oct 30 '14 at 14:20
  • @JasCav Woops, you are correct. – asawyer Oct 30 '14 at 14:21

2 Answers2

100

Your problem is (step by step)

  1. Your SomeInformation() method sets the value of test1.Latitude to "LATITUDE2".
  2. You then pass that model to your Index() method using the overload of RedirectToAction that accepts an object. Internally this uses reflection to build a RouteValueDictionary based on the properties of your model (in this case its simply latitude="LATITUDE2").
  3. When you hit the Index method the model is bound by the DefaultModelBinder and now the value of DataSiteList.Latitude is "LATITUDE2" (which is why you enter the if block)
  4. In the process of binding, the DefaultModelBinder sets the ModelStatevalue of Latitude to "LATITUDE2". Any attempts to set the value of Latitude are now ignored because the view uses ModelState value to render the control.

It not clear what your trying to do here. You can make it work as you expect by adding ModelState.Clear(); as the first line of your Index() method. This clears all existing ModelState values an you can now set the value to "LATITUDE".

But your if block makes no sense. Perhaps you were just doing some kind of test, but you may as well remove the parameter from the Index() method and just initialize a new instance of DataSites in the method.

Edit

To give a bit more information as to why updating a model property has no affect once ModelState has been set.

Imagine you have a form to collect user information where the model contains int Age. The user is asked to enter their age and someone enters "I'm five next week!". Of course this wont bind to an int so the DefaultModelBinder adds the value (the attemptedValue) and adds a ModelStateError.

When the view is returned it will typically display an error message such as "The field Age must be a number". If the html helper rendering the control used the model value, then it would display "0" (the default value for int). It would be somewhat confusing for the user to see "0" in the textbox and next it a message saying it must be a number (What! but zero is a number and what the heck happened to what I entered?). So instead, the helper uses the value from ModelState and now the users sees "I'm five next week!" and an associated error message that makes sense for the value.

So even though you thoughts were that "its not logical", there is actually some logic to this behavior.

David Klempfner
  • 8,700
  • 20
  • 73
  • 153
-5

You are not setting Altitude. It will be null so the code will never go into this block and set Lattitude to "LATTITUDE"

    if (DataSiteList.Altitude != null)
    {
        DataSites test = new DataSites();
        test.Latitude = "LATITUDE";

        return View(test);
    }
Keith
  • 718
  • 8
  • 12
  • The value of `Altitude` **is** being set (in the `SomeInformation` method). If the `if` block was not hit then the view would display an empty string not "LATITUDE2" as OP has stated. –  Oct 30 '14 at 22:18
  • 1
    My answer was submitted before the OP fixed that section of the code. Before it was fixed, the code was setting Latitude and Checking Altitude. Now, the code sets Latitude checks Latitude... not altitude, like you have in your comment. – Keith Oct 31 '14 at 09:44
  • 2
    Altitude or Latitude makes no difference. This has absolutely nothing to do with OP's problem. –  Oct 31 '14 at 20:39
  • 1
    @StephenMuecke Actually I disagree. If he was setting one property (`Latitude`), then checking another for not being null (`Altitude`) when it was still null, it would never try to re-instantiate `DataSites` and fill that new property (`Latitude`) with anything, because the property being checked (`Altitude`) would've still been null, therefore not meeting that `if` condition. – vapcguy Oct 25 '18 at 13:48