ASPを深く分析する.NET Mvc 1.0 – 2. Controller.Execute(Request)-TempDataDictionaryのLoadとSave操作

8494 ワード

Controllerは最終的にControllerBaseクラスのExecute(RequestContext)メソッドを呼び出すことでアクションの作成と実行を完了します.コードは次のとおりです.
protected virtual void Execute(RequestContext requestContext) {
            if (requestContext == null) {
                throw new ArgumentNullException("requestContext");
            }

            Initialize(requestContext);
            ExecuteCore();
        }

コードは2つのステップに分かれています.
  • Initialize(requestContext):ControllerContextクラスのインスタンスを作成します.
  • ExecuteCore():TempDataをロードし、Actionを作成および実行し、Actionから返されるActionResultを処理し、TempDataデータを保存します.

  • ExecuteCore()のコードは次のとおりです.
    protected override void ExecuteCore() {
                TempData.Load(ControllerContext, TempDataProvider);
    
                try {
                    string actionName = RouteData.GetRequiredString("action");
                    if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
                        HandleUnknownAction(actionName);
                    }
                }
                finally {
                    TempData.Save(ControllerContext, TempDataProvider);
                }
            }

    コードは、次の3つのセクションに分かれています.
  • TempData.Load(ControllerContext,TempDataProvider):HttpContextBase.SessionでのTempDataデータのロード
  • ActionInvoker.InvokeAction(ControllerContext,actionName):Actionを作成、実行し、Actionが返すActionResult
  • を処理します.
  • TempData.Save(ControllerContext,TempDataProvider):TempData
  • を保存する
    第1,第3部はいずれもTempDataに対する操作であり,以下の2つのステップについて詳細に説明する.
     
    1. TempData.Load(ControllerContext, TempDataProvider)
    TempDataProvider:SessionStateTempDataProviderです.ITempDataProviderインタフェースを継承したSession補助クラスです.
    TempDataProvider.Loadのソース:
    public void Load(ControllerContext controllerContext, ITempDataProvider tempDataProvider) {
                IDictionary<string, object> providerDictionary = tempDataProvider.LoadTempData(controllerContext);
                _data = (providerDictionary != null) ? new Dictionary<string, object>(providerDictionary, StringComparer.OrdinalIgnoreCase) : 
                    new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                _initialKeys = new HashSet<string>(_data.Keys);
                _modifiedKeys.Clear();
            }

    ここでは、TempDataをロードするすべてのプロセスです.
  • SessionStateTempDataProviderのLoadTempData(...)メソッドを呼び出し、IDictionaryオブジェクト
  • に戻る.
  • 初期化_Dataオブジェクト、providerDictionaryがnullでない場合、providerDictionaryのデータを_に格納します.dataオブジェクトでは、実はこの_DataはTempDataがデータを保存するためのコンテナであり、
  • 初期化_initialKeysオブジェクトと_DataのすべてのKey値が挿入され、ロードされたKey値をキャッシュするために使用されます.TempDataに新しいデータを挿入すると、initialKeysオブジェクトのデータにはタスクの変更はありません
  • クリア_modifiedKeysの値は、TempDataの新しいKey値を保存するために使用され、新しいキー値ペアがTempDataに挿入されると、このkey値は_に保存されます.modifiedKeysオブジェクトの
  • さらにtempDataProvider.LoadTempData(controllerContext)メソッドは、S e ssionStateTempDataProviderクラスのLoadTempData(...)メソッドです.
    public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext) {
                HttpContextBase httpContext = controllerContext.HttpContext;
                
                if (httpContext.Session == null) {
                    throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
                }
    
                Dictionary<string, object> tempDataDictionary = httpContext.Session[TempDataSessionStateKey] as Dictionary<string, object>;
    
                if (tempDataDictionary != null) {
                    // If we got it from Session, remove it so that no other request gets it
                    httpContext.Session.Remove(TempDataSessionStateKey);
                    return tempDataDictionary;
                }
                else {
                    return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                }
            }

    SessionStateTempData Providerクラスには、Sessionに保存されているTempDataオブジェクトのKeyとして使用する定数が定義されています.
    internal const string TempDataSessionStateKey = "__ControllerTempData";

    LoadTempData(…)メソッドでは、まず、keyに対応するDictionaryオブジェクトをSessionで検索し、Sessionにこのオブジェクトが存在する場合は、Sessionのこのキー値ペアをクリアして見つかったDictionaryオブジェクトを返します.Noは、新しいDictionaryオブジェクトを作成して返します.
    ここのポイントはhttpContextです.Session.Remove(TempDataSessionStateKey)メソッドは、同じTempDataが1回しか伝達されないというTempDataの特徴でもあります.SessionでTempDataを見つけたらすぐにそれをSessionから消去し、次にLoadTempData()メソッドを実行すると、同じTempDataは二度と見つかりません.
    再度説明:1つのキー値ペアをTempDataに入れると、同じControllerの異なるActionでも異なるControllerの異なるActionでもこのTempDataを受信できますが、一度だけ、プログラムが再びサービス側にコミットされると、同じ値を取得できないTempDataオブジェクトになります.これは、Sessionで消去されているためです.
     
    2. TempData.Save(ControllerContext, TempDataProvider)
    これはコントローラ全体です.Execute(...)ライフサイクルの最後の操作は、新しいTempDataをHttpContext.に保存することです.Base.セッション中です.セーブメソッドの具体的なコード:
    public void Save(ControllerContext controllerContext, ITempDataProvider tempDataProvider) {
                if (_modifiedKeys.Count > 0) {
    
                    // Apply change tracking.
                    foreach (string x in _initialKeys) {
                        if (!_modifiedKeys.Contains(x)) {
                            _data.Remove(x);
                        }
                    }
    
                    // Store the dictionary
                    tempDataProvider.SaveTempData(controllerContext, _data);
                }
            }

    上に述べたようにinitialKeysと_modifiedKeysの重要性、それらの役割はここで体現されます.
  • _InitialKeys:Action実行前のTempDataのすべてのKey値を保存します.action実行中に新しいキー値ペアがTempDataに挿入された場合、_InitialKeysオブジェクトの値は影響しません.
  • _modifiedKeys:Action実行中に新しいキー値ペアがTempDataに挿入された場合、この新しいキーは_に挿入されます.modifiedKeysオブジェクト.

  • セーブメソッドではまず判断_modifiedKeysオブジェクトの要素の数、新しいキー値ペアがTempDataに挿入されているかどうか、foreachと次のif文はTempDataから不要なキー値ペアデータを削除し、最後にtempData Providerを呼び出す.SaveTempData(controllerContext,_data)メソッドは、TempDataをHttpContextBaseに保存する.セッション中です.
    注意:最後に定義したTempDataのデータは、TempDataのロード中に_に格納されます.Dataでは、ここでforeach,if文は、渡す必要のないキー値ペアを削除し、TempDataに今回のAction実行中に生成されたキー値ペアデータのみが保持されていることを確認します.