asp.net-mvc asp.net-mvc-3 hidden-fields html.hiddenfor

ASP.Net MVC Html.HiddenFor con valor incorrecto



asp.net-mvc asp.net-mvc-3 (4)

Estoy usando MVC 3 en mi proyecto, y veo un comportamiento muy extraño.

Intento crear un campo oculto para un valor particular en mi Modelo, el problema es que, por alguna razón, el valor establecido en el campo no se corresponde con el valor en el Modelo.

p.ej

Tengo este código, solo como una prueba:

<%:Html.Hidden("Step2", Model.Step) %> <%:Html.HiddenFor(m => m.Step) %>

Yo pensaría que ambos campos ocultos tendrían el mismo valor. Lo que hago es establecer el valor en 1 la primera vez que visualizo la Vista y luego, después del envío, aumento el valor del campo Modelo en 1.

Entonces, la primera vez que represento la página, ambos controles tienen el valor 1, pero la segunda vez que los valores son los siguientes son:

<input id="Step2" name="Step2" type="hidden" value="2" /> <input id="Step" name="Step" type="hidden" value="1" />

Como puede ver, el primer valor es correcto, pero el segundo valor parece ser el mismo que la primera vez que visualizo la Vista.

¿Qué me estoy perdiendo? ¿Los * For Html helpers almacenan en caché los valores de alguna manera? Si es así, ¿cómo puedo desactivar este almacenamiento en caché?

Gracias por tu ayuda.


Eso es normal y así es como funcionan los ayudantes de HTML. Primero usan el valor de la solicitud POST y luego el valor en el modelo. Esto significa que incluso si modifica el valor del modelo en la acción de su controlador si hay la misma variable en la solicitud POST, se ignorará su modificación y se usará el valor POSTed.

Una solución posible es eliminar este valor del estado del modelo en la acción del controlador que intenta modificar el valor:

// remove the Step variable from the model state // if you want the changes in the model to be // taken into account ModelState.Remove("Step"); model.Step = 2;

Otra posibilidad es escribir una ayuda HTML personalizada que siempre usará el valor del modelo e ignorará los valores POST.

Y aún otra posibilidad:

<input type="hidden" name="Step" value="<%: Model.Step %>" />


Este código no funcionará

// remove the Step variable from the model state // if you want the changes in the model to be // taken into account ModelState.Remove("Step"); model.Step = 2;

... porque HiddenFor always (!) lee de ModelState, no del modelo en sí. Y si no encuentra la tecla "Paso" generará el valor predeterminado para ese tipo de variable que será 0 en este caso

Aquí está la solución. Lo escribí para mí, pero no me importa compartirlo porque veo que muchas personas están luchando con este travieso Oculto Por ayuda.

public static class CustomExtensions { public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression); } public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression, htmlAttributes); } public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes) { ReplacePropertyState(htmlHelper, expression); return htmlHelper.HiddenFor(expression, htmlAttributes); } private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { string text = ExpressionHelper.GetExpressionText(expression); string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text); ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState; ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); if (modelState.ContainsKey(fullName)) { ValueProviderResult currentValue = modelState[fullName].Value; modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture); } else { modelState[fullName] = new ModelState { Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), CultureInfo.CurrentUICulture) }; } } }

Entonces solo lo usa como de costumbre desde su vista:

@Html.HiddenFor2(m => m.Id)

Vale la pena mencionar que también funciona con colecciones.


Estoy luchando demasiado con la misma situación, creo, donde uso el mismo modelo de estado entre llamadas, y cuando modifico una propiedad de modelo en back-end. Sin embargo, no me importa, si uso textboxfor o hiddenfor.

Simplemente puenteo la situación usando scripts de página para almacenar el valor del modelo como una variable js, porque necesito el campo oculto para ese propósito al principio.

No estoy seguro si esto ayuda, pero solo considere ...


Me encontré con el mismo problema al escribir un asistente que muestra diferentes partes de un modelo más grande en cada paso.
Los datos y / o errores del "Paso 1" se mezclarían con el "Paso 2", etc., hasta que finalmente me di cuenta de que ModelState debía ''culpar''.

Esta fue mi solución simple:

if (oldPageIndex != newPageIndex) ModelState.Clear(); // <-- solution return View(model[newPageIndex]);