これは次の質問の続きです。
MVC 3 + $ .ajax-応答は部分的なビューからの出力をキャッシュしているようです
そこに問題の詳細な説明があります。しかし、私は今や問題を絞り込むことができました。それはHtml.EditorForヘルパーにあると思われるため、新しい質問です。
問題:
$ .ajaxを使用してサーバーにデータを投稿し、入力コントロールを保持する部分ビューのHTMLを返します。問題は、新しく作成されたオブジェクトをパーシャルビューモデルに渡しても、さまざまな@ Html.EditorForヘルパーと@ Html.DropDownListForヘルパーが古いデータを返すということです。
Htmlヘルパーの横に値を出力することで、モデルがヘルパーに新しいオブジェクトを正しく渡したことを証明できます。すなわち:
@Html.EditorFor(model => model.Transaction.TransactionDate)
@Model.Transaction.TransactionDate.ToString()
次の画像が示すように、@ Html.EditorForは間違ったデータを返します。
[Comentarioテキストボックスの横の値は日付時刻です。デフォルトの値を、投稿ごとに変化する値、つまりDateTimeで置き換えることをテストしていたためです。]
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に到達すると、応答には古い日付が表示されます。たとえば、上の画像では "2011/09/2011"です。
結果として、ここではキャッシングが行われていると思いますが、何も設定していないので、何も意味がありません。
ここにはcachingは含まれていません。これは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);
}
キャッシュを指定しない場合でも、キャッシュが発生することがあります。 AJAXおよびJSONリクエストを処理するコントローラーの場合、次のように装飾します。
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
これは、キャッシングが発生しないことを明確に宣言しています。
[〜#〜]更新[〜#〜]
Darin Dimitrovの回答 here に基づいて、コントローラーアクションに次の行を追加してみてください。
ModelState.Clear();
私はこれを見たことはありませんが、基本的にajaxを使用してこのデータを要求している場合は、nochacheを設定する必要があります。
$.ajax({
url: "somecontroller/someAction,
cache: false, // this is key to make sure JQUERY does not cache your request
success: function( data ) {
alert( data );
}
});
ちょうど暗闇の中で刺す、あなたはおそらくすでにこれをすでにカバーしていると思います。最初に新しいモデルを作成してから、そのモデルの新しいインスタンスにデータを入力してから、ビューに送信しようとしましたか?
最後に、どのDBサーバーを使用しているかわからないが、DBの結果がキャッシュされておらず、DBキャッシュからSQL結果を要求しているだけではないことを確認しました... MsSQLを使用していませんが、何かが出力されるまでoutputCaching DBサーバー自体の変更??とにかくいくつかの考え
これは予期しない動作であり、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プロパティの名前を取得します。キー名が明確でないため、これは「ネストされた」モデルがある場合に特に役立ちます。
これを実行していないことを確認してください:
@Html.EditorFor(model => model.Transaction.TransactionDate.Date)
私はこれを行い、モデルは決して価値を取り戻しませんでした。 .Date
を削除すると、問題なく動作しました。