web-dev-qa-db-ja.com

複合オブジェクトをTempDataに保存する

私は次のようにTempDataを使用して、リダイレクト後にアクションにデータを渡そうとしました:

if (!ModelState.IsValid)
{
    TempData["ErrorMessages"] = ModelState;
    return RedirectToAction("Product", "ProductDetails", new { code = model.ProductCode });
}

ただし、残念ながら次のメッセージが表示されて失敗します。

'System.InvalidOperationExceptionMicrosoft.AspNet.Mvc.SessionStateTempDataProvider''ModelStateDictionary'型のオブジェクトをセッション状態にシリアル化できません。

GithubのMVCプロジェクト で問題を発見しましたが、このエラーが発生する理由は説明していますが、実行可能な代替案はわかりません。

1つのオプションは、オブジェクトをJSON文字列にシリアル化してから、逆シリアル化してModelStateを再構築することです。これが最善のアプローチですか?考慮する必要がある潜在的なパフォーマンスの問題はありますか?

最後に、複雑なオブジェクトのシリアル化、またはTempDataの使用を伴わない他のパターンの使用に代わるものはありますか?

47
elolos

次のような拡張メソッドを作成できます。

_public static class TempDataExtensions
{
    public static void Put<T>(this ITempDataDictionary tempData, string key, T value) where T : class
    {
        tempData[key] = JsonConvert.SerializeObject(value);
    }

    public static T Get<T>(this ITempDataDictionary tempData, string key) where T : class
    {
        object o;
        tempData.TryGetValue(key, out o);
        return o == null ? null : JsonConvert.DeserializeObject<T>((string)o);
    }
}
_

また、次のように使用できます。

objectAClassA型であるとしましょう。次のような上記の拡張メソッドを使用して、これを一時データディクショナリに追加できます。

TempData.Put("key", objectA);

そしてそれを取得するには、これを行うことができます:

var value = TempData.Get<ClassA>("key")ここで、取得されるvalueClassA型になります

100
hem

コメントすることはできませんが、PEEKを追加しました。これは、次のGETのために削除するのではなく、読み取るかどうかを確認するのに便利です。

public static T Peek<T>(this ITempDataDictionary tempData, string key) where T : class
{
    object o = tempData.Peek(key);
    return o == null ? null : JsonConvert.DeserializeObject<T>((string)o);
}

var value = TempData.Peek<ClassA>("key") where value retrieved will be of type ClassA
6
Chris Go