redis在asp.net 中的应用

 

1.redis介绍  

  Nosql数据库作为关系型数据库的补充,在互联网公司已经得到广泛的运用。redis便是其中的代表之一,redis是一种(key,value)基于内存的数据库,并支持多种数据结构,如List,HashSet,string等,并能够支持的数据的持久化存储,redis如何做内存数据到磁盘的同步将分单独的章节讲解。既然redis是基于内存的数据库,那么它将应用在对性能要求高的场合,如做数据缓存,可以减少数据库访问的压力。同时redis可以应用在统计分析类的Web应用,统计分析类Web应用,一般情况下会从数据库中读取大量的数据并进行相关计算,因此,可以通过数据预处理的方式将数据提前计算,并以(key,value)的形式保存在redis中,从而能够极大的改善查询性能。 

2.redis 在windows下的使用。

  redis在linux下广泛使用。官方网站为:http://redis.io/,window下redis官方并不提供支持,但是可以在http://redis.io/download下载windows64版redis,是由microsoft open tech 组开发和维护,开源代码以发布在GitHub上:https://github.com/MSOpenTech/redis。另外在提供一个.exe可执行文件下载地址,支持32bit和64bit:https://github.com/rgl/redis/downloads

     下载redis.exe文件后,安装redis后,会在对应的Redis根目录中出现:redis-cli.exe,redis-server.exe,redis-service.exe,分别对应redis客户端,服务端和redis服务启动程序。打开分别redis-server.exe和redis-cli.exe后,在redis-cli命令行中输入相关命令向redis服务器发送读写命令,可以看到redis-server命令行中显示客户端的连接情况。如下图所示:

  

           图1.redis-server运行图

      

         图2.redis-cli运行图

 

 接下来我们通过简单的c# console程序来读写redis server数据库。

3.c# 连接redis server数据库。

目前比较常用的redis client c#类库主要有:StackExchange.Redis和ServiceStack.Redis,本文主要使用的是StackExchange.Redis,StackExchange是一个高性能客户端类库,同时提供同步和异步操作。通过nuget来安装StackExchange后,可以通过其连接redis server。

StackExchange中提供了一个ConnectionMultiplexer类,该对象屏蔽了底层多Redis服务器连接的细节,该对象的连接建立被设计成可以被客户端多个调用者之间共享及复用。因此,不必在每次对redis操作时建立新的ConnectionMultiplexer对象。与此同时,该对象的操作被设计成线程安全的。为了建立到Redis server的连接,我们可以使用如下的方式:

ConnectionMultiplexer con = ConnectionMultiplexer.Connect("localhost:6379"),redis server默认端口为6379.

为了复用ConnectionMultiplexer对象,我们可以通过定义静态的属性,通过返回ConnectionMultiplexer的实例来使用该对象。接下来我们写个简单的单例模式来获取ConnectionMultiplexer对象。代码如下:

  
    public class RedisConnection
    {

        private static readonly Lazy<ConnectionMultiplexer> _connection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect("localhost:6379"));

        public static ConnectionMultiplexer Connection { get { return _connection.Value; } }
    }

通过堕式加载的方式来创建ConnectionMultiplexer实例,该实例的初始化的创建是线程安全的。

接下来我们通过定义个简单的client来测试对redis 服务器的读写操作。

 class Program
    {
        static void Main(string[] args)
        {
            ConnectionMultiplexer con = RedisConnection.Connection;
            IDatabase db = con.GetDatabase();//默认是连接到数据库0
            db.StringSet("name", "tom");
            string value = db.StringGet("name");
            Console.WriteLine("name:"+value);
        }
    }

程序的执行结果为:name:tom.

接下来我们写一个简单的对象在redis中的存储。

首先我们定义一个Student类:

    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string School { get; set; }
    }

因为redis在存储对象前需要首先将对象进行序列化,读取对象时需要进行反序列话,接下来,我们将定义两个IDatabase的扩展方法。

 public static class RedisExtension
    {
        public static TResult Get<TResult>(this IDatabase cache, string key)
        {
            return Deserialize<TResult>(cache.StringGet(key));
        }

        public static void Set<TIn>(this IDatabase cache, string key, TIn value)
        {
            cache.StringSet(key, Serialize(value));
        }

        static byte[] Serialize(object o)
        {
            if (o == null)
                return null;
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            using (MemoryStream mStream = new MemoryStream())
            {
                binaryFormatter.Serialize(mStream,o);
                byte[] objectDataAsStream = mStream.ToArray();
                return objectDataAsStream;
            }
        }

        static TResult Deserialize<TResult>(byte[] stream)
        {
            if (stream == null)
                return default(TResult);
            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream memStream = new MemoryStream(stream))
            {
                TResult result = (TResult)formatter.Deserialize(memStream);
                return result;
            }

        }
        

    }

接下来我们在定义一个Client来测试redis对象的读写的使用:

 class Program
    {
        static void Main(string[] args)
        {
            ConnectionMultiplexer con = RedisConnection.Connection;

           
            IDatabase db = con.GetDatabase();
            Student st = new Student { Age = 12, Name = "tom", School = "mit" };
            db.Set("student", st);
            Console.WriteLine("name:" + st.Name + " Age:" + st.Age);
        }
    }

运行程序后,程序抛出异常,提示Student没有表示Serializable,在Student类上加上[Serializable]属性后,运行程序后,结果输出:name:tom Age:12。

 

接下来我们在写个简单的web api 的例子来演示redis作为缓存在web api中的使用,基本上与c# console中使用redis相同,除了在对象的返回上需要做些额外的处理。

在VS中新建一个web api项目后,我们简单的建一个StudentController。

在该例子中使用的类方法的调用与前面的例子是一样的。并且为了方便,我将所有的操作都写在了Controller中。

namespace MvcApplication3.Controllers
{
    public class StudentController :ApiController
    {
        public Student Get(int id)
        {
            string cacheKey = "GetStudent:" + id;
           
            ConnectionMultiplexer con = RedisConnection.Connection;
            IDatabase db = con.GetDatabase(1);
            Student stObj = db.Get<Student>(cacheKey);
            if (stObj != null)
            {
                return stObj;

            }
            Student st = new Student { Id = 1, Age = 12, Name = "tom", School = "ustc" };
            db.Set(cacheKey,st);
            return st;
        }
    }
}

  我们通过fiddler来查看服务器端返回的对象结果。在url框中输入:http://localhost:8536/api/Student/1,查看服务器端返回的JSON数据结果:

我们可以看到了返回的字段的信息,这其实并不是我们期望的信息,因为我们在定义Sudent类的时候使用的是自动的set get属性,在c#编译器编译成il代码时会生成对应属性的字段的信息,这些生成的字段名字就是上图对应的信息。默认情况下,web api会在对象返回前对对象字段及自动属性进行序列化,当我们为类表示[Serializable]属性时,只会序列化字段信息,为了序列化对应的属性,返回我们需要的信息我们需要定义如下的Student类:

[Serializable]
    [DataContract]
    public class Student
    {
        [DataMember]
        public int Id { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
        [DataMember]
        public string School { get; set; }
    }

这时,我们在运行应用,输入url:http://localhost:8536/api/Student/1,返回的Json数据如下:

得到了我们需要的结果,当然,在web api中我们也可以通过如下的方式。是默认的json序列化器忽略[Serializable]属性:

通过在Global.aspx的App_start方法中进行如下设置:

var serializerSettings =
  GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
var contractResolver =
  (DefaultContractResolver)serializerSettings.ContractResolver;
contractResolver.IgnoreSerializableAttribute = true;

至此,redis的在c#中的简单运用就介绍到这!

 

 

 

posted @ 2014-11-16 23:43  charili  阅读(3339)  评论(0编辑  收藏  举报