这是以下问题的后续内容:
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返回错误的数据:
[请注意,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”。
结果,我只是认为这里有一些缓存,但我没有设置,所以没有任何意义。
答案 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
,模型和所需属性的表达式,并将其删除。
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
后,它完美无缺。