【问题标题】:MVC 3 - Html.EditorFor seems to cache old values after $.ajax callMVC 3 - Html.EditorFor 似乎在 $.ajax 调用后缓存旧值
【发布时间】:2011-11-16 21:06:38
【问题描述】:

这是以下问题的后续:

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

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

问题:

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

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

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

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

[请注意,注释文本框旁边的值是日期时间,因为我正在测试将默认值替换为每个帖子都会更改的值,即日期时间。]

如果我将 TransactionDate 的 @Html.EditorFor 替换为普通的旧 @Html.TextBox():

@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”。

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

【问题讨论】:

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


【解决方案1】:

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

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

这明确声明不应发生缓存。

更新

根据 Darin Dimitrov 给 here 的回答,尝试将以下行添加到您的控制器操作中:

ModelState.Clear();

【讨论】:

  • 抱歉,不,问题仍然存在。感谢您的尝试。
  • 根据 Darin Dimitrov 的回答更新了我的回答。试一试。
  • 这确实有效,但公平地说,我认为饼干是给达林的。你同意吗?
  • 我同意,因为这是他的回答。呻吟。
【解决方案2】:

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

【讨论】:

  • 你是对的。我已经尝试了所有这些。无济于事。对不起!
【解决方案3】:

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

【讨论】:

  • 我必须为你的答案投票,因为我更新的答案主要是指向你另一个最近答案的链接。
  • @Darin Dimitrov:谢谢,我很开明,这总是最好的结果。我已经意识到问题出在 ModelState 上,但一直在寻找错误,没有意识到它保留了旧值。起作用的是 ModelState.Clear();,所以辅导员本得到了支持。我无法让删除位工作。
  • 不错的达林从来不知道这个hmmmmmmm
  • 达林,但为什么要调查 ModelState?如果我用我设置的值定义模型,那么我希望输入视图使用我传递的模型,并且只使用它。乳清为什么这样做?是什么原因?现在我总是要做这个 ModelState.Clear();返回视图(模型);这是一个安全问题。如果我没有清除 ModelState,黑客可以通过 GET 参数修改我的视图。
  • 这是设计使然。原因是通过回发来持久化信息。如果您使用正确的视图模型作为输入操作参数,黑客无法通过 GET 参数修改任何内容。只有输入视图模型的属性会修改视图状态。
【解决方案4】:

确保你没有这样做:

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

我这样做了,但模型再也没有收回价值。一旦我删除.Date,它就可以完美运行。

【讨论】:

    【解决方案5】:

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

    这是我想出的几种方法来帮助解决这个问题。 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 属性的名称。这在您有“嵌套”模型时特别有用,因为键名不明显。

    【讨论】:

      猜你喜欢
      • 2011-11-16
      • 1970-01-01
      • 2020-01-05
      • 2012-01-11
      • 1970-01-01
      • 1970-01-01
      • 2012-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多