快捷搜索:

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类的实例,它有如下定义:

publicclass 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() {
    
returnnew SessionStateTempDataProvider();
}

  TempData就是通过这种Provider的方式来支持其它的保存途径。而且在MvcFutures中,还有一个CookieTempDataProvider类可供使用。使用也很简单,获取MVC源码,编译项目MvcFutures,然后引用它,重写以上虚方法就可以了:

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

  注意哦,这里有2个陷阱:MVC 2的MvcFutures的CookieTempDataProvider并不能正常工作。至于我在尝试时,发现它是这样写的(注释部分是我加的):

publicstatic 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的长度较大,因此容易导致浏览器不支持。最终我重写了以上代码(以及另一个序列化的代码):

publicstatic IDictionary<string, object> DeserializeTempData(string base64EncodedSerializedTempData)
{
    
try {
        
return (new JavaScriptSerializer()).Deserialize<IDictionary<string, object>>(
                HttpUtility.UrlDecode(base64EncodedSerializedTempData));
    }
    
catch {
        
return null;
    }
}

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

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

您可能还会对下面的文章感兴趣: