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对象。代码如下:

publicclass RedisConnection

    {

        privatestaticreadonlyLazy _connection =newLazy(() => ConnectionMultiplexer.Connect("localhost:6379"));

        publicstaticConnectionMultiplexer Connection {get{return _connection.Value; } }

    }

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

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

class Program

    {

        staticvoidMain(string[] args)

        {

            ConnectionMultiplexer con = RedisConnection.Connection;

            IDatabase db = con.GetDatabase();//默认是连接到数据库0

            db.StringSet("name","tom");

            stringvalue = db.StringGet("name");

            Console.WriteLine("name:"+value);

        }

    }

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

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

首先我们定义一个Student类:

publicclass Student

    {

        publicintId {get;set; }

        publicstringName {get;set; }

        publicintAge {get;set; }

        publicstringSchool {get;set; }

    }

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

publicstaticclass RedisExtension

    {

        publicstaticTResult Get(thisIDatabase cache,string key)

        {

            returnDeserialize(cache.StringGet(key));

        }

        publicstaticvoidSet(thisIDatabase cache,string key, TIn value)

        {

            cache.StringSet(key, Serialize(value));

        }

        staticbyte[] Serialize(object o)

        {

            if(o ==null)

                returnnull;

            BinaryFormatter binaryFormatter =new BinaryFormatter();

            using(MemoryStream mStream =new MemoryStream())

            {

                binaryFormatter.Serialize(mStream,o);

                byte[] objectDataAsStream = mStream.ToArray();

                return objectDataAsStream;

            }

        }

        staticTResult Deserialize(byte[] stream)

        {

            if(stream ==null)

                returndefault(TResult);

            BinaryFormatter formatter =new BinaryFormatter();

            using(MemoryStream memStream =new MemoryStream(stream))

            {

                TResult result = (TResult)formatter.Deserialize(memStream);

                return result;

            }

        }

    }

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

class Program

    {

        staticvoidMain(string[] args)

        {

            ConnectionMultiplexer con = RedisConnection.Connection;


            IDatabase db = con.GetDatabase();

            Student st =newStudent { 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]

    publicclass Student

    {

        [DataMember]

        publicintId {get;set; }

        [DataMember]

        publicstringName {get;set; }

        [DataMember]

        publicintAge {get;set; }

        [DataMember]

        publicstringSchool {get;set; }

    }

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

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

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

varserializerSettings =  GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;varcontractResolver =  (DefaultContractResolver)serializerSettings.ContractResolver;

contractResolver.IgnoreSerializableAttribute =true;

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,313评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,369评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,916评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,333评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,425评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,481评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,491评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,268评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,719评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,004评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,179评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,832评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,510评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,153评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,402评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,045评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,071评论 2 352