MVC 3 – Html.EditorFor parece armazenar em cache valores antigos após a chamada $ .ajax

Esta é uma continuação da seguinte pergunta:

MVC 3 + $ .ajax – resposta parece ser saída de cache da vista parcial

Há uma descrição detalhada do problema por lá. No entanto, agora consegui refinar o problema, que parece estar com os ajudantes Html.EditorFor, daí a nova pergunta.

O problema:

Eu posto os dados no servidor usando $ .ajax e, em seguida, retorno o html da visão parcial que contém os controles de input. O problema é que, apesar de passar um object recém-criado para o modelo de Visualizações Parciais, os vários helpers @ Html.EditorFor e @Html.DropDownListFor retornam o OLD DATA !.

Eu posso provar que o modelo passou corretamente um novo object para os auxiliares, imprimindo o valor ao lado do ajudante Html. Ou seja:

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

Como mostra a imagem a seguir, o @ Html.EditorFor está retornando os dados errados:

Resposta em cache ...

[Observe que o valor ao lado da checkbox de texto Comentario é uma data, porque eu estava testando a substituição dos valores padrão por um valor que mudaria com cada postagem, ou seja, um DateTime.]

Se eu replace o @ Html.EditorFor for TransactionDate por um simples antigo @ Html.TextBox ():

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

Em seguida, ele renderiza o valor TransactionDate correto para um novo object Transaction, ou seja, DateTime.MinValue (01/01/0001 …).

Assim sendo…

O problema é com os ajudantes @ Html.EditorFor. O problema também acontece com TextBoxFor e DropDownListFor.

O problema é que esses ajudantes parecem armazenar em cache o valor antigo.

O que estou fazendo de errado??!

EDITAR:

Acabei de tentar debugging no modelo do Editor personalizado para datas e, lá, ViewData.TemplateInfo.FormattedModelValue mostra o valor correto, ou seja, “01/01/0001”. No entanto, quando chegar ao Fiddler, a resposta mostrará a data anterior, por exemplo, “01/09/2011” na imagem acima.

Como resultado, eu só acho que há algum cache acontecendo aqui, mas eu não tenho nenhum configurado, então nada faz sentido.

Não há cache envolvido aqui. É exatamente como o ajudante HTML funciona. Primeiro, eles observam o ModelState ao vincular seus valores e, em seguida, no modelo. Portanto, se você pretende modificar qualquer um dos valores POSTed dentro de sua ação do controlador, certifique-se de removê-los do estado do modelo primeiro:

 [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); } 

Mesmo se você não especificar o armazenamento em cache, às vezes isso pode ocorrer. Para os meus controladores que lidam com pedidos AJAX e JSON, eu os decorei da seguinte forma:

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

Isso especificamente declara que nenhum cache deve ocorrer.

ATUALIZAR

Com base em uma resposta dada por Darin Dimitrov, tente adicionar a seguinte linha à sua ação do controlador:

 ModelState.Clear(); 

Eu nunca vi isso, mas basicamente se você estiver usando ajax para solicitar esses dados, você precisa definir nochache: estou assumindo que você está usando jQuery.ajax aqui, então mostrarei o 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 ); } }); 

apenas uma facada no escuro, eu suponho que você já tenha coberto isso já. Você tentou criar um novo modelo primeiro e, em seguida, preencher essa nova instância do modelo com seus dados e enviá-lo para a sua exibição!

Finalmente, não tenho certeza de qual servidor DB está usando, mas verifique se os resultados do database não estão armazenados em cache e se você está apenas solicitando resultados SQL do cache do database … Eu não uso o MsSQL, mas ouvi dizer que tem outputCaching até que algo esteja mudar no próprio servidor DB? de qualquer maneira apenas alguns pensamentos

Este foi um comportamento inesperado para mim, e embora eu entenda a razão pela qual é necessário dar precedência ModelState , eu precisava de uma maneira de remover essa input para que o valor do modelo é usado em seu lugar.

Aqui estão alguns methods que eu criei para ajudar nisso. O RemoveStateFor método terá um ModelStateDictionary , um modelo e uma expressão para a propriedade desejada e removê-lo.

HiddenForModel pode ser usado em seu View para criar um campo de input oculto usando apenas o valor do Model, primeiro removendo sua input ModelState. (Isso pode ser facilmente expandido para os outros methods de extensão auxiliar).

 ///  /// 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); } 

Ligue de um controlador como este:

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

ou de uma visão como esta:

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

Ele usa System.Web.Mvc.ExpressionHelper para obter o nome da propriedade ModelState. Isso é especialmente útil quando você tem modelos “nesteds”, pois o nome da chave não é óbvio.

Certifique-se de não estar fazendo isso:

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

Eu fiz isso e o modelo nunca recuperou o valor. Funcionou perfeitamente uma vez que eu .Date o .Date .