你的位置:首页 > ASP.net教程

[ASP.net教程]我心中的核心组件(可插拔的AOP)~分布式Session组件


对于目前的网站来说,为了满足高可用,高并发,高负载,一台WEB服务器已经远远不够用了,以后的WEB应用服务器应该是一种集群的环境,它们之间使用一些工具进行数据的同步,在由1台变成多台服务器时,有一个问题是我们必须要考虑的,Session机制,我们都知道Session被用来存储用户的一些凭证信息,持久化到服务器上,这在安全性方面得到了保证(比存储到客户端的cookies),而当你的WEB应用服务器是多台时(多台之间做了负载均衡),这种Session机制就有问题了,因为你无法实现从一台服务器到别一台服务器的内存(缓存)共享,这也是不安全的,所以,在出现缓存中间件出现之后,就有了一种新的技术也跟着出现了,即Session中间件,比较成熟的组件是StackExchange.Redis+RedisSessionStateProvider,即使用Redis实现的Session机制,它将session数据存储到了一台(可以是redis集群)redis服务器上,这时,多台WEB应用服务器之间的数据就是唯一的了,不需要进行同步了。

下面介绍实现步骤

1 使用nuget安装redis缓存 StackExchange.Redis
2 使用nuget安装RedisSession服务  RedisSessionStateProvider
3 从nuget添加RedisSession之后,它会在你的config文件中写入以下内容,主要是对session进行持久化设置的
  

 <sessionState mode="Custom" customProvider="MySessionStateStore">   <providers>    <!-- Either use 'connectionString' and provide all parameters as string OR use 'host','port','accessKey','ssl','connectionTimeoutInMilliseconds' and 'operationTimeoutInMilliseconds'. -->    <!-- 'throwOnError','retryTimeoutInMilliseconds','databaseId' and 'applicationName' can be used with both options. -->    <!--     <add name="MySessionStateStore"      host = "127.0.0.1" [String]      port = "" [number]      accessKey = "" [String]      ssl = "false" [true|false]      throwOnError = "true" [true|false]      retryTimeoutInMilliseconds = "5000" [number]      databaseId = "0" [number]      applicationName = "" [String]      connectionTimeoutInMilliseconds = "5000" [number]      operationTimeoutInMilliseconds = "1000" [number]      connectionString = "<Valid StackExchange.Redis connection string>" [String]      loggingClassName = "<Assembly qualified class name that contains logging method specified below>" [String]      loggingMethodName = "<Logging method should be defined in loggingClass. It should be public, static, does not take any parameters and should have a return type of System.IO.TextWriter.>" [String]     />    -->    <add name="MySessionStateStore" type="Microsoft.Web.Redis.RedisSessionStateProvider" host="127.0.0.1" accessKey="" ssl="false" />   </providers>  </sessionState>

4 下载是新版本的redis服务端,可以是windows版的,我用的是2.6.13,低版本的redis会出现Eval命令无法识别的问题
5 处理完成,可以测试你的session了,默认过期时间为1200秒

前台使用Session时和原来没有任何分别

    public ActionResult TestSession()    {      Session["username"] = "zzl";      Session["test"] = "hello world!";      return Content("完成..." + Session["test"]);    }

这种不修改以有代码就可以实现不同功能策略的方式就是我们的IoC,控制反转技术(也是依赖注入DI的范畴),这也是编程语言发展到一定阶段的必然产物,即解决复杂的业务的应对之道!

下面是网友对rediscache进行的扩展,让它支持复杂类型,默认支持简单类型,如果希望支持复杂类型,需要为类型添加“可序列化”的特性,因为我们在redis里存储时,都是以二进制字节数组的形式存储的。

 /// <summary>  /// 对RedisCache的扩展,让它支持复杂类型、  /// RedisValue 类型可以直接使用字节数组,因此,  /// 调用 Get 帮助程序方法时,它会将对象序列化为字节流,然后再缓存该对象。  /// 检索项目时,项目会重新序列化为对象,然后返回给调用程序。  /// </summary>  public static class SampleStackExchangeRedisExtensions  {    public static T Get<T>(this IDatabase cache, string key)    {      return Deserialize<T>(cache.StringGet(key));    }    public static object Get(this IDatabase cache, string key)    {      return Deserialize<object>(cache.StringGet(key));    }    public static void Set(this IDatabase cache, string key, object value)    {      cache.StringSet(key, Serialize(value));    }    static byte[] Serialize(object o)    {      if (o == null)      {        return null;      }      BinaryFormatter binaryFormatter = new BinaryFormatter();      using (MemoryStream memoryStream = new MemoryStream())      {        binaryFormatter.Serialize(memoryStream, o);        byte[] objectDataAsStream = memoryStream.ToArray();        return objectDataAsStream;      }    }    static T Deserialize<T>(byte[] stream)    {      if (stream == null)      {        return default(T);      }      BinaryFormatter binaryFormatter = new BinaryFormatter();      using (MemoryStream memoryStream = new MemoryStream(stream))      {        T result = (T)binaryFormatter.Deserialize(memoryStream);        return result;      }    }  }

对复杂类型进行存储和读取的方法如下

  cache.Set("zzlList", new List<TestCache> { new TestCache { ID = 1, Name = "占占", AddTime = DateTime.Now } });  var o = cache.Get("zzlList");