2017-02-07 8 views
0

私のMVCアプリケーションでは、投稿されたモデルが無効な場合、モデル状態をTempDataに保存して、別のアクションにリダイレクトするときに表示されるようにします。ここでSQLServerセッションモードのViewData(ModelState)をシリアル化する方法は?

は私がやったことです:

if (!ModelState.IsValid) 
{ 
    TempData["ViewData"] = ViewData; 
    return RedirectToAction("Edit", new { id = model.Id }); 
} 

リダイレクトするには:

public ActionResult Edit(Guid id) 
{ 
    var model = Services.Get(id); 

    if (TempData["ViewData"] != null) 
    { 
     ViewData = (ViewDataDictionary)TempData["ViewData"]; 
    } 
    ViewBag.HasUpdated = TempData["HasUpdated"]; 
    return View(model); 
} 

これは、ローカルホストで正常に動作しますが、サーバー上で失敗しました。

エラーメッセージが語っている:

セッション状態をシリアル化することができませんが。 'StateServer'と 'SQLServer'モードでは、ASP.NETはセッション状態オブジェクトをシリアル化します。その結果、非直列化可能オブジェクトまたはMarshalByRefオブジェクトは許可されません。同様の逐次化がカスタムセッションステートストアによって「カスタム」モードで実行される場合、同じ制限が適用されます。

私たちのサーバーは、通常、モデルをセッションに保存するときに、モデルの冒頭に[Serializable]を追加します。しかし、ViewDataで何ができますか? ViewDataDictionaryを弊社セッションに保存するには?

答えて

0

ViewDataまたはViewDataDictionaryをSQL Serverのセッション状態に格納することはできません。これは、それらがシリアル化可能ではなく、それらに格納されたデータがシリアル化可能であるかどうか不安であるためです。

ローカルアプリケーションがSQL Serverをセッションステートストアとして使用するように構成されている場合は、同じエラーが発生するはずです。

ViewDataをセッション状態に直接格納する代わりに、実際のオブジェクトをビューデータから取得し、そのオブジェクトをセッション状態に格納する必要があります。この問題は、オブジェクトの型がシリアル化可能でない場合でも変わりません。

modelstateを保存する場合は、クラスを作成して保存することができます。

[Serializable] 
public class ModelStateStore 
{ 
    public List<ModelStateData> {get;set;} 
} 

[Serializable] 
public class ModelStateData 
{ 
    public string PropertyName {get;set;} 
    public bool IsValid {get;set;} 
    public string ErrorMessage {get;set;} 
} 

このデータ構造を使用してモデル状態情報を保存し、セッションに保存することができます。また、必要に応じてセッションから取得して新しいモデルステートを取得し、それを取得します。

つまり、Sql Serverのセッション状態には何も格納することはできません。そこに保存している値が条件を満たしていることを確認する必要があります。

+0

'ModelError'をこのシリアライズ可能な' ModelStateData'にマップすることをお勧めしますか? – Blaise

+0

これは、あなたの問題の声明を見て、私の心の中で一番簡単な解決策です。あなたはもっと考えることができ、それをあなたの要求に合ったものにすることができます。セッション値からモデル状態を構築する場合は、複雑になることがあります。それを証明する例はありませんが、それができると思います。それは非常に一般的な方法では役に立たないかもしれませんが、モデルステートを格納して取り出すためには、それは確かに便利です。 –

0

Chetan Ranpariyaの答えに触発された詳細な解説があります。

セッションで保存するシリアライズ可能なモデル。

[Serializable] 
public class ModelStateSummary 
{ 
    public string PropertyName { get; set; } 
    public string[] ErrorMessages { get; set; } 
} 

いくつかの拡張方法。

public static class ModelStateExtensions 
{ 
    public static IEnumerable<ModelStateSummary> ToSummary(this ModelStateDictionary modelState) 
    { 
     return modelState.Select(state => new ModelStateSummary 
     { 
      PropertyName = state.Key, 
      ErrorMessages = state.Value.Errors.Select(x => x.ErrorMessage).ToArray() 
     }); 
    } 

    public static ModelStateDictionary ToModelState(this IEnumerable<ModelStateSummary> summary) 
    { 
     var modelStates = new ModelStateDictionary(); 
     foreach (var modelState in summary) 
     { 
      var data = new ModelState(); 
      foreach (var errorMessage in modelState.ErrorMessages) 
      { 
       data.Errors.Add(new ModelError(errorMessage)); 
      } 
      modelStates.Add(modelState.PropertyName, data); 
     } 
     return modelStates; 
    } 
} 

は、セッション変数にモデルの状態を設定する:

if (!ModelState.IsValid) 
{ 
    Session["ModelStateSummary"] = ModelState.ToSummary(); 
    return RedirectToAction("Edit"); 
} 

をリダイレクトした後、ターゲット・アクションに、セッション変数をチェックしViewData.ModelStateに移します。

if (Session["ModelStateSummary"] != null) 
{ 
    var stateSummaries = (List<ModelStateSummary>)Session["ModelStateSummary"]; 
    ModelState.Merge(stateSummaries.ToModelState()); 
} 

このようにして、ModelStateをあるアクションから別のアクションに転送します。

関連する問題