OPTEN, das einzige Umbraco-zertifizierte Unternehmen der Schweiz

DropDownListFor Html helper wrong selected value

TLDR:

Use ModelState.Clear() in your controller which you post to if you need MVC features and validation, or write your own plain html if MVC functionality is not required.

The code:

To understand what was happening I stepped into the Html.DropdownListFor helper. The key to what was happening was within the SelectExtensions.cs class, in the SelectInternal method the defaultValue is set from the modelState. Here is the code:

object defaultValue = (allowMultiple)
? htmlHelper.GetModelStateValue(fullName, typeof(string[]))
: htmlHelper.GetModelStateValue(fullName, typeof(string));

internal object GetModelStateValue(string key, Type destinationType)
{
    ModelState modelState;
    if (ViewData.ModelState.TryGetValue(key, out modelState))
    {
        if (modelState.Value != null)
        {
            return modelState.Value.ConvertTo(destinationType, null /* culture */);
        }
    }
    return null;
}

The reason:

This is the code behind this strange behaviour. Although the selected option in the view model is changed, the selected option which was selected by the customer is still in the ModelState, and this value takes precedence over the selected option in the SelectItemList. But why does it work this way, it seemed to me very unintuitive.

I found the answer in a very helpful blog post from Simon Ince of Microsoft. He explains that the reason for this is that using the MVC pattern, usually when a page is reloaded after a post, it is because there has been a validation failure. In this case it is helpful for the user to see what the original value they entered was, because maybe this is which caused the validation to fail.

The Fix:

So now I understood that there was a good reason for this behaviour, it was not a bug. There are several ways to solve this problem. One was is to remove this value from the ModelState in the controller which the Ajax posted to. This can be achieved with the following code:

ModelState.Remove("Transaction");

Or remove every key from the ModelState by calling the clear method:

ModelState.Clear();

The downside with these methods is that another line of code is needed in the controller, which makes it a fragile solution. Another option, if you do not need validation, is simply to write your own plain html, instead of relying on the html helper. Html helpers are specifically there to help with the MVC framework logic.


kommentieren


0 Kommentar(e):