MVC 3 - Html.EditorFor, кажется, кэширует старые значения после вызова $ .ajax - PullRequest
42 голосов
/ 14 сентября 2011

Это продолжение следующего вопроса:

MVC 3 + $ .ajax - ответ, кажется, кэширует выходные данные из частичного представления

Там есть подробное описание проблемы. Однако теперь мне удалось сузить проблему, которая, похоже, связана с помощниками Html.EditorFor, поэтому появился новый вопрос.

Выпуск:

Я отправляю данные на сервер, используя $ .ajax, затем возвращаю html частичного представления, которое содержит элементы управления вводом. Проблема в том, что, несмотря на передачу вновь созданного объекта в модель Partial Views, различные помощники @ Html.EditorFor и @ Html.DropDownListFor возвращают СТАРЫЕ ДАННЫЕ!.

Я могу доказать, что модель правильно передала помощникам новый объект, напечатав значение рядом с помощником 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» на изображении выше.

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

Ответы [ 5 ]

103 голосов
/ 16 сентября 2011

Здесь нет кэширования . Просто так работает HTML-помощник. Сначала они смотрят на ModelState при связывании их значений, а затем в модели. Поэтому, если вы намереваетесь изменить какие-либо значения POST внутри действия контроллера, сначала убедитесь, что вы удалили их из состояния модели:

[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);
}
19 голосов
/ 16 сентября 2011

Даже если вы не укажете кэширование, это иногда может произойти.Для моих контроллеров, которые обрабатывают запросы AJAX и JSON, я их декорирую следующим образом:

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

Это специально заявляет, что кэширование не должно выполняться.1009 * Основываясь на ответе, который Дарин Димитров дал здесь , попробуйте добавить следующую строку в действие вашего контроллера:

ModelState.Clear();
1 голос
/ 18 мая 2015

Это было неожиданное поведение для меня, и хотя я понимаю причину, по которой необходимо предоставить приоритет 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.Это особенно полезно, когда у вас есть «вложенные» модели, поскольку имя ключа не очевидно.

1 голос
/ 16 сентября 2011

Я никогда не видел этого, но в основном, если вы используете 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 пока что-то не поменяется на самом сервере БД ?? в любом случае, всего несколько мыслей

0 голосов
/ 09 мая 2012

Убедитесь, что вы этого не делаете:

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

Я сделал это, и модель так и не вернула значение. Это работало отлично, как только я удаляю .Date.

...