Подтвердить что ты не робот

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" на изображении выше.

В результате я просто думаю, что здесь происходит некоторое кеширование, но у меня нет настройки, поэтому ничего не имеет смысла.

4b9b3361

Ответ 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.