深入分析 ASP.NET Mvc 1.0 – 2. Controller.Execute(Request)-TempDataDictionary的Load與Save操作

來源:互聯網
上載者:User

Controller最終是通過調用ControllerBase類的Execute(RequestContext)方法來完成一個Action的建立與執行操作, 代碼如下:

protected virtual void Execute(RequestContext requestContext) {            if (requestContext == null) {                throw new ArgumentNullException("requestContext");            }            Initialize(requestContext);            ExecuteCore();        }

代碼分為兩步:

  • 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);            }        }

代碼又分為三個部分:

  1. TempData.Load(ControllerContext, TempDataProvider): 從HttpContextBase.Session中載入TempData資料
  2. ActionInvoker.InvokeAction(ControllerContext, actionName): 建立,執行Action,並處理Action返回的ActionResult
  3. TempData.Save(ControllerContext, TempDataProvider): 儲存TempData

第1, 第3部分都是對TempData的操作,下面的文字將詳細介紹這兩個步驟。

 

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的全部過程:

  1. 調用SessionStateTempDataProvider中的LoadTempData(…)方法並近回一個IDictionary<string, object>對象
  2. 初始化_data對象,如果providerDictionary不是null那麼把providerDictionary中的資料存放到_data對象中,其實這個_data就是TempData用來儲存資料的容器,
  3. 初始化_initialKeys對象並將_data中的全部Key值放入其中,它用來緩衝已載入的Key值,如果對TempData中插入新資料時, _initialKeys對象中的資料不會有任務變化
  4. 清除_modifiedKeys中的值,用來儲存TempData新的Key值,當有一個新的索引值對插入到TempData中,這個key值會被儲存到_modifiedKeys對象中

再來深入tempDataProvider.LoadTempData(controllerContext)方法,其實就是SessionStateTempDataProvider類中的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);            }        }

SessionStateTempDataProvider類中定義了一個常量,用它來作為儲存在Session中TempData對象的Key。

internal const string TempDataSessionStateKey = "__ControllerTempData";

在LoadTempData(…)方法中, 首先在Session中尋找與key相對應的Dictionary<string, object>對象,如果Session中存在這個對象,那麼就清除Session中的這個索引值對並返回找到的Dictionary<string, object>對象, 否則建立一個新的Dictionary<string, object>對象並返回。

這裡的重點就是httpContext.Session.Remove(TempDataSessionStateKey) 方法,這也是TempData的特點,即同一個TempData只能被傳遞一次。當在Session中找到TempData後立即將它從Session中清除掉,下一次執行LoadTempData(…)方法時絕不會再找到同一個TempData。

再次說明:只要將一個索引值對放入到TempData中,不論是同一個Controller中的不同Action,還是不同Controller中的不同Action都可以接收到這個TempData,但是僅此一次,當程式再次提交回服務端後是絕不可能再獲得同樣的值的TempData對象, 因為它已經在Session中被清除掉。

 

2. TempData.Save(ControllerContext, TempDataProvider)

這是整個Controller.Execute(…)生命週期中最後一個操作, 它的作用是儲存新的TempData到HttpContext.Base.Session中。Save方法的具體代碼:

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中,這個新的Key會插入到_modifiedKeys對象中。

Save方法中首先判斷_modifiedKeys對象中元素的數量,是否有新的索引值對被插入到TempData中,foreach和下面的if語句是從TempData中刪除無用的索引值對資料,最後調用 tempDataProvider.SaveTempData(controllerContext, _data)方法,將TempData儲存在HttpContextBase.Session中。

注意:在載入TempData過程中會將上次定義的TempData中資料放入到_data中,這裡的foreach, if語句是去掉不再需要傳遞的索引值對,確保TempData中僅保留本次Action執行過程中產生的索引值對資料。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.