MVC 3 – Html.EditorFor parece almacenar en caché los valores antiguos después de la llamada $ .ajax

Esto es un seguimiento de la siguiente pregunta:

MVC 3 + $ .ajax – la respuesta parece ser la salida de almacenamiento en caché desde una vista parcial

Hay una descripción detallada del problema allí. Sin embargo, ahora he logrado reducir el problema, que parece ser con Html.EditorFor helpers, de ahí la nueva pregunta.

La cuestión:

Publico datos en el servidor usando $ .ajax, luego devuelvo el html de la vista parcial que contiene los controles de entrada. El problema es que, a pesar de pasar un objeto recién creado al modelo de Vistas Parciales, los diversos ayudantes @ Html.EditorFor y @ Html.DropDownListFor devuelven los DATOS VIEJOS.

Puedo probar que el modelo ha pasado correctamente en un nuevo objeto a los ayudantes, imprimiendo el valor junto al helper Html. Es decir:

@Html.EditorFor(model => model.Transaction.TransactionDate) @Model.Transaction.TransactionDate.ToString() 

Como muestra la siguiente imagen, @ Html.EditorFor está devolviendo los datos incorrectos:

Respuesta en caché ...

[Tenga en cuenta que el valor junto al cuadro de texto Comentario es una fecha, porque estaba probando el reemplazo de los valores predeterminados con un valor que cambiaría con cada publicación, es decir, un DateTime.]

Si reemplazo @ Html.EditorFor por TransactionDate con un antiguo simple @ Html.TextBox ():

 @Html.TextBox("Transaction_TransactionDate", Model.Transaction.TransactionDate) 

A continuación, representa el valor correcto de TransactionDate para un nuevo objeto Transaction, es decir, DateTime.MinValue (01/01/0001 …).

Por lo tanto…

El problema es con @ Html.EditorFor helpers. El problema también ocurre con TextBoxFor y DropDownListFor.

El problema es que estos ayudantes parecen almacenar en caché el valor anterior.

¡¿¿Qué estoy haciendo mal??!

EDITAR:

Acabo de probar la depuración en la plantilla del Editor personalizado para las fechas, y allí, ViewData.TemplateInfo.FormattedModelValue muestra el valor correcto, es decir, “01/01/0001”. Sin embargo, una vez que llega a Fiddler, la respuesta muestra la fecha anterior, por ejemplo, “01/09/2011” en la imagen de arriba.

Como resultado, creo que hay algo de almacenamiento en caché, pero no tengo ninguno configurado, así que nada tiene sentido.

No hay almacenamiento en caché involucrado aquí. Es solo cómo funciona HTML helper. Primero miran el ModelState cuando vinculan sus valores y luego en el modelo. Entonces, si tiene la intención de modificar cualquiera de los valores POSTed dentro de la acción de su controlador, asegúrese de eliminarlos del estado del modelo primero:

 [HttpPost] public virtual ActionResult AjaxCreate(Transaction transaction) { if (ModelState.IsValid) { service.InsertOrUpdate(transaction); service.Save(); } service.ChosenCostCentreId = transaction.IdCostCentre; TransactionViewModel viewModel = new TransactionViewModel(); ModelState.Remove("Transaction"); viewModel.Transaction = new Transaction(); ModelState.Remove("CostCentre"); viewModel.CostCentre = service.ChosenCostCentre; ... return PartialView("_Create", viewModel); } 

Incluso si no especifica el almacenamiento en caché, a veces puede ocurrir. Para mis controladores que manejan solicitudes AJAX y JSON, los decore de la siguiente manera:

 [OutputCache(Location = OutputCacheLocation.None, NoStore = true)] 

Esto declara específicamente que no debe producirse el almacenamiento en caché.

ACTUALIZAR

Según la respuesta que dio Darin Dimitrov aquí , intente agregar la siguiente línea a su acción de controlador:

 ModelState.Clear(); 

Nunca he visto esto, pero básicamente si estás usando ajax para solicitar estos datos, necesitas establecer el nochache: supongo que estás usando jQuery.ajax aquí, así que mostraré el código:

 $.ajax({ url: "somecontroller/someAction, cache: false, // this is key to make sure JQUERY does not cache your request success: function( data ) { alert( data ); } }); 

solo una puñalada en la oscuridad, supongo que probablemente ya hayas cubierto esto. ¿Has intentado crear primero un nuevo modelo y luego llenar esa nueva instancia del modelo con tus datos y luego enviar esto a tu vista?

Finalmente, no estoy seguro de qué servidor de bases de datos está usando, pero he comprobado que los resultados de las bases de datos no estén en caché y que no solo esté solicitando resultados SQL de la caché de la base de datos … no uso MsSQL, pero escuché que tiene outputCaching hasta que algo es cambiar en el servidor de DB en sí? de todos modos solo algunos pensamientos

Este fue un comportamiento inesperado para mí, y aunque entiendo la razón por la cual es necesario darle precedencia a ModelState , necesitaba una forma de eliminar esa entrada para que en su lugar se utilizara el valor de Model.

Aquí hay un par de métodos que ideé para ayudar con esto. El método RemoveStateFor tomará un ModelStateDictionary , un modelo y una expresión para la propiedad deseada, y lo eliminará.

HiddenForModel se puede usar en su vista para crear un campo de entrada oculto usando solo el valor del modelo, primero quitando su entrada de estado del modelo. (Esto podría expandirse fácilmente para los otros métodos de extensión de ayuda).

 ///  /// Returns a hidden input field for the specified property. The corresponding value will first be removed from /// the ModelState to ensure that the current Model value is shown. ///  public static MvcHtmlString HiddenForModel(this HtmlHelper helper, Expression> expression) { RemoveStateFor(helper.ViewData.ModelState, helper.ViewData.Model, expression); return helper.HiddenFor(expression); } ///  /// Removes the ModelState entry corresponding to the specified property on the model. Call this when changing /// Model values on the server after a postback, to prevent ModelState entries from taking precedence. ///  public static void RemoveStateFor(this ModelStateDictionary modelState, TModel model, Expression> expression) { var key = ExpressionHelper.GetExpressionText(expression); modelState.Remove(key); } 

Llamar desde un controlador como este:

 ModelState.RemoveStateFor(model, m => m.MySubProperty.MySubValue); 

o desde una vista como esta:

 @Html.HiddenForModel(m => m.MySubProperty.MySubValue) 

Utiliza System.Web.Mvc.ExpressionHelper para obtener el nombre de la propiedad ModelState. Esto es especialmente útil cuando tiene modelos “nesteds” ya que el nombre de la clave no es obvio.

Asegúrate de que no estás haciendo esto:

 @Html.EditorFor(model => model.Transaction.TransactionDate.Date) 

Hice esto, y el modelo nunca recuperó el valor. Funcionó perfectamente una vez que .Date el .Date .