MVC 3 - Html.EditorFor似乎在$ .ajax调用后缓存旧值

时间:2011-09-14 09:51:30

标签: asp.net-mvc-3 jquery html-helper

这是以下问题的后续内容:

MVC 3 + $.ajax - response seems to be caching output from partial view

那里有问题的详细描述。但是,我现在已经设法缩小了问题范围,这似乎与Html.EditorFor助手有关,因此是新问题。

问题:

我使用$ .ajax将数据发布到服务器,然后返回包含输入控件的部分视图的html。问题在于,尽管将新创建的对象传递给部分视图模型,但各种@ Html.EditorFor和@Html.DropDownListFor帮助程序返回OLD DATA!。

我可以通过在Html助手旁边打印出值来证明模型已正确地将新对象传递给助手。即:

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

如下图所示,@ Html.EditorFor返回错误的数据:

Cached response...

[请注意,Comentario文本框旁边的值是一个日期时间,因为我正在测试用每个帖子改变的值替换默认值,即DateTime。]

如果我用普通的旧版@Html.TextBox()替换@ Html.EditorFor for TransactionDate:

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

然后它为新的Transaction对象呈现正确的TransactionDate值,即DateTime.MinValue(01/01/0001 ...)。

...因此

问题出在@ Html.EditorFor助手上。 TextBoxFor和DropDownListFor也会出现问题。

问题是这些助手似乎缓存旧值。

我做错了什么?!

编辑:

我刚尝试在自定义编辑器模板中调试日期,在那里,ViewData.TemplateInfo.FormattedModelValue显示正确的值,即“01/01/0001”。然而,一旦它到达Fiddler,响应显示旧日期,例如上图中的“01/09/2011”。

结果,我只是认为这里有一些缓存,但我没有设置,所以没有任何意义。

5 个答案:

答案 0 :(得分:103)

这里没有涉及缓存。这就是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);
}

答案 1 :(得分:18)

即使您没有指定缓存,有时也会发生缓存。对于处理AJAX和JSON请求的控制器,我按如下方式装饰它们:

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

这特别声明不应该发生缓存。

<强>更新

根据Darin Dimitrov给出here的答案,尝试在控制器操作中添加以下行:

ModelState.Clear();

答案 2 :(得分:1)

我从未见过这个,但基本上如果你使用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直到DB服务器本身发生了变化?无论如何只是一些想法

答案 3 :(得分:1)

这对我来说是出乎意料的行为,虽然我理解为什么必须给出ModelState优先权,但我需要一种方法来删除该条目,以便使用Model中的值。

我想出了几种方法来帮助解决这个问题。 RemoveStateFor方法将采用ModelStateDictionary,模型和所需属性的表达式,并将其删除。

通过首先删除其ModelState条目,可以在视图中使用

HiddenForModel仅使用模型中的值创建隐藏输入字段。 (这可以很容易地扩展到其他辅助扩展方法)。

/// <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属性的名称。当你拥有&#34;嵌套&#34;模型因为关键名称不明显。

答案 4 :(得分:0)

确保你没有这样做:

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

我做到了这一点,模特再也没有得到价值。删除.Date后,它完美无缺。