ASP.NET:在MVC中如何使用Session?


ASP.NET:在MVC中如何使用Session?

2011年12月16日11:30 來源: 博客 作者:Fish Li 編輯: 蘇巧紅 我要評論(0)
標簽: ASP.NET , .NET , web開發

  【IT168技術】本文將介紹Asp.net MVC 中的Session及基於現有代碼的處理方法。

  相關閱讀:

  ASP.NET:Session的缺點總結及解決方法

  ASP.NET:Session對並發訪問的影響

  ASP.NET:session的來龍去脈解析

  Asp.net平台作為底層的框架,它提供了HttpContext.Session這個成員屬性讓我們可以方便地使用Session,但是在MVC中,Controller抽象類為也提供了這樣一個屬性,我們只要訪問它就可以了(支持更好的測試性)。

   回想一下,前面我們看到SessionStateModule是根據當前HttpHandler來決定是不是啟用Session。但是現在 Controller和Page是分開的, Controller又是如何使用Session的呢?要回答這個問題就要扯到路由了,簡單地說:現在在MVC處理請求的時候,當前 HttpHandler是 MvcHandler類的實例,它有如下定義:

public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState {

    因此,在Controller.Session中,它是訪問的HttpContext.Session,而MvcHandler實現了 IRequiresSessionState接口,所以,訪問HttpContext.Session就可以獲取到Session 。注意哦,我上面的代碼取自MVC 2.0,從類型實現的接口可以看出,Session將一直有效,不能關閉,而且屬於影響並發的那種模式。所以,此時你只能從web.config中全局關 閉它。

  說明,在MVC 3.0 和Asp.net 4.0中,才可以支持Controller訂制Session的訪問性。

  在這種使用方式下,如果您不想繼續使用Session,可以使用上面我列出的替代方法。

  在MVC中,還有一個地方也在使用Session,那就是Controller.TempData這個成員屬性。通常我們可能會這樣使用它:

TempData[ " mydata " ] = " aaaaaaaaaa " ; // or other object
return RedirectToAction( " Index " );

    在這種地方,這些保存到TempData的數據其實也是存放在Session中的。你可以從web.config中關閉Session,你就能看到異常 了。對於這種使用方法,你仍然可以前面的替代方法,但是,還有另一種方法也能做為替代Session的方法。我們看一下Controller的一段代碼:

protected virtual ITempDataProvider CreateTempDataProvider() {
    
return new SessionStateTempDataProvider();
}

    TempData就是通過這種Provider的方式來支持其它的保存途徑。而且在MvcFutures中,還有一個 CookieTempDataProvider類可供使用。使用也很簡單,獲取MVC源碼,編譯項目MvcFutures,然后引用它,重寫以上虛方法就 可以了:

protected override ITempDataProvider CreateTempDataProvider()
{
    
return new Microsoft.Web.Mvc.CookieTempDataProvider(this.HttpContext);
}

   注意哦,這里有2個陷阱:MVC 2的MvcFutures的CookieTempDataProvider並不能正常工作。至於我在嘗試時,發現它是這樣寫的(注釋部分是我加的):

public static IDictionary < string , object > DeserializeTempData( string base64EncodedSerializedTempData)
{
    
byte [] bytes = Convert.FromBase64String(base64EncodedSerializedTempData);
    var memStream
= new MemoryStream(bytes);
    var binFormatter
= new BinaryFormatter();
    
return binFormatter.Deserialize(memStream, null) as TempDataDictionary;     // 這里會導致一直返回null
    
// return binFormatter.Deserialize(memStream, null) as IDictionary < string , object > ;     // 這樣寫才對嘛。
}
 
就算能運行,這樣做會導致生成的Cookie的長度較大,因此容易導致瀏覽器不支持。最終我重寫了以上代碼(以及另一個序列化的代碼):
public static IDictionary < string , object > DeserializeTempData( string base64EncodedSerializedTempData)
{
    
try {
        
return ( new JavaScriptSerializer()).Deserialize < IDictionary < string , object >> (
                HttpUtility.UrlDecode(base64EncodedSerializedTempData));
    }
    
catch {
        
return null;
    }
}

public static string SerializeToBase64EncodedString(IDictionary < string , object > values)
{
    
if ( values == null || values.Count == 0 )
        
return null;

    
return HttpUtility.UrlEncode(
        (
new JavaScriptSerializer()).Serialize(values));
}

   上面的方法雖然解決了序列化結果過長的問題,但它也引入了新的問題:由於使用IDictionary類型,造成復雜類型在序列化時就丟失了它們的類型信息,因此,在反序列化時,就不能還原正原的類型。也正是因為此原因,這種方法將只適合保存簡單基元類型數據。

  現有的代碼怎么辦

   本來,這篇博客到這里就沒有了。是啊,批也批過了,解決辦法也給了,還有什么好說的,不過,突然想到一個很現實的問題,要是有人問我:Fish,我的代 碼很多的地方在使用Session,如果按你前面的方法,雖可行,但是要改動的代碼比較多,而且需要測試,還要重新部署,這個工作量太大了,有沒有更好的 辦法?

  是啊,這個還真是個現實的問題。怎么辦呢?

  針對這個問題,我也認真的思考過,也回憶過曾經如何使用 Session,以及用Session都做過些什么。一般說來,用Session基本上也就是保存一些與用戶相關的臨時信息,而且不同的頁面使用的 Session沖突的可能性也是極小的,使用方式以 mode="InProc" 為主。其實也就是Cache,只是方便了與“當前用戶”的關聯而已。

  於是針對這個前提,繼續想:現在要克服的最大障礙是並發的鎖定問題。至於這個問題嘛,我們可以參考一下前面MSND中的說明,就是因為GetItemExclusive這些方法搞出來的嘛。想到這里,似乎辦法也就有了:我也來實現一個使用Cache的Provider,並且在具體實現時,故意不搞鎖定,不就行了嘛。

   最終,我提供二個Provider,它們都是去掉了鎖定相關的操作,試了一下,並發問題不存了。但有個問題需要說明一 下,ProcCacheSessionStateStore采用Cache保存Session的內容,與 mode="InProc" 類似, CookieSessionStateStore則采用Cookie保存Session對象,但它有個限制,只適合保存簡單基元類型數據(且不包含敏感信 息),原因與CookieTempDataProvider一樣。所以,請根據您的使用場景來選擇合適的Provider

  以下是使用方法:很簡單,只要在web.config中加一段以下配置就好了:

< sessionState mode = " Custom " customProvider = " CookieSessionStateStore " >
    
< providers >
        
< add name = " ProcCacheSessionStateStore " type = " Fish.SampleCode.ProcCacheSessionStateStore " />
        
< add name = " CookieSessionStateStore " type = " Fish.SampleCode.CookieSessionStateStore " />
    
</ providers >
</ sessionState >

   好了,這次不用改代碼了,在部署環境中,也只需要修改了一下配置就完事了。

  警告:我提供的這二個Provider只是做了簡單的測試,並沒經過實際的項目檢驗,如果您需要使用,請自行測試它的可用性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM