MVC 3 - Html.EditorFor, похоже, кэширует старые значения после вызова $.ajax
Это следующий вопрос:
MVC 3 + $.ajax - ответ, кажется, кэширует вывод из частичного представления
Здесь есть подробное описание проблемы. Однако теперь мне удалось сузить проблему, которая, похоже, связана с помощником Html.EditorFor, поэтому новый вопрос.
Проблема:
Я отправляю данные на сервер с помощью $.ajax, затем возвращаю html частичного представления, содержащего элементы управления вводами. Проблема в том, что, несмотря на передачу вновь созданного объекта модели Partial Views, различные @Html.EditorFor и @Html.DropDownListFor помощники возвращают OLD DATA!.
Я могу доказать, что модель правильно передала новый объект хелперам, напечатав значение рядом с помощником Html. То есть:
@Html.EditorFor(model => model.Transaction.TransactionDate)
@Model.Transaction.TransactionDate.ToString()
Как показано на следующем рисунке, @Html.EditorFor возвращает неверные данные:
![Cached response...]()
[Обратите внимание, что значение рядом с текстовым полем Comentario является временем даты, потому что я тестировал замену значений по умолчанию на значение, которое будет меняться с каждым сообщением, то есть с DateTime.]
Если я заменил @Html.EditorFor для TransactionDate с простым старым @Html.TextBox():
@Html.TextBox("Transaction_TransactionDate", Model.Transaction.TransactionDate)
Затем он отображает правильное значение TransactionDate для нового объекта Transaction, то есть DateTime.MinValue(01/01/0001...).
Поэтому...
Проблема связана с помощниками @Html.EditorFor. Проблема также возникает с TextBoxFor и DropDownListFor.
Проблема заключается в том, что эти помощники, похоже, кэшируют старое значение.
Что я делаю неправильно?!
EDIT:
Я только что попробовал отладку в настраиваемом шаблоне редактора для дат, и там, ViewData.TemplateInfo.FormattedModelValue показывает правильное значение, то есть "01/01/0001". Однако, как только он попадает к Fiddler, в ответе отображается старая дата, например, "01/09/2011" на изображении выше.
В результате я просто думаю, что здесь происходит некоторое кеширование, но у меня нет настройки, поэтому ничего не имеет смысла.
Ответы
Ответ 1
Здесь нет кеширования. Это то, как работает HTML-помощник. Сначала они смотрят на ModelState при привязке их значений, а затем в модели. Поэтому, если вы намерены изменить любые POSTED-значения внутри вашего действия контроллера, убедитесь, что вы сначала удалили их из состояния модели:
[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);
}
Ответ 2
Даже если вы не укажете кеширование, оно иногда может возникнуть. Для моих контроллеров, которые обрабатывают запросы AJAX и JSON, я их украшаю следующим образом:
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
Это указывает, что кэширование не должно происходить.
UPDATE
На основе ответа Дарин Димитров дал здесь, попробуйте добавить следующую строку к действию вашего контроллера:
ModelState.Clear();
Ответ 3
Я никогда не видел этого, но в основном, если вы используете ajax для запроса этих данных, вам нужно установить nochache: я предполагаю, что вы используете jQuery.ajax здесь, так что вы увидите код:
$.ajax({
url: "somecontroller/someAction,
cache: false, // this is key to make sure JQUERY does not cache your request
success: function( data ) {
alert( data );
}
});
просто удар в темноте, я предполагаю, что вы уже уже накрыли это. вы сначала попытались создать новую модель, а затем заполнили этот новый экземпляр модели своими данными, а затем отправьте это на свое мнение!
Наконец, не уверен, какой сервер БД используется, но вы проверите, чтобы убедиться, что результаты БД не кэшированы и что вы не просто запрашиваете результаты SQL из кэша БД... я не использую MsSQL, но я слышал, что у него есть outputCaching пока что-то не изменится на самом сервере БД? во всяком случае, всего несколько мыслей
Ответ 4
Это было неожиданное поведение для меня, и хотя я понимаю причину, по которой необходимо предоставить приоритет ModelState
, мне нужен способ удалить эту запись, чтобы вместо этого использовать значение из модели.
Вот несколько методов, которые я придумал, чтобы помочь с этим. Метод RemoveStateFor
примет ModelStateDictionary
, модель и выражение для требуемого свойства и удалит его.
HiddenForModel
может использоваться в вашем представлении для создания скрытого поля ввода, используя только значение из Модели, сначала удалив его запись ModelState. (Это можно легко развернуть для других методов вспомогательного расширения).
/// <summary>
/// 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.
/// </summary>
public static MvcHtmlString HiddenForModel<TModel, TProperty>(this HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> expression)
{
RemoveStateFor(helper.ViewData.ModelState, helper.ViewData.Model, expression);
return helper.HiddenFor(expression);
}
/// <summary>
/// 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.
/// </summary>
public static void RemoveStateFor<TModel, TProperty>(this ModelStateDictionary modelState, TModel model,
Expression<Func<TModel, TProperty>> expression)
{
var key = ExpressionHelper.GetExpressionText(expression);
modelState.Remove(key);
}
Вызов от контроллера следующим образом:
ModelState.RemoveStateFor(model, m => m.MySubProperty.MySubValue);
или из вида:
@Html.HiddenForModel(m => m.MySubProperty.MySubValue)
Он использует System.Web.Mvc.ExpressionHelper
для получения имени свойства ModelState. Это особенно полезно, если у вас есть "вложенные" модели, поскольку имя ключа не является очевидным.
Ответ 5
Убедитесь, что вы этого не делаете:
@Html.EditorFor(model => model.Transaction.TransactionDate.Date)
Я сделал это, и модель никогда не получала значение обратно. Он отлично работал, когда я удаляю .Date
.