新普京网站-澳门新普京 > 前端 > 开篇示例介绍,客户端Redis服务器的分布式缓存

开篇示例介绍,客户端Redis服务器的分布式缓存

2019/12/29 18:01

用C#代码应用Redis缓存

用C#代码应用Redis运维Manage NuGet包插件,找到ServiceStack.Redis包,并张开安装。

图片 1

一贯从实例化客商端选取Set/Get办法现身说法:

string host = "localhost";
string elementKey = "testKeyRedis";

using (RedisClient redisClient = new RedisClient(host))
{
      if (redisClient.Get<string>(elementKey) == null)
      {
           // adding delay to see the difference
           Thread.Sleep(5000); 
           // save value in cache
           redisClient.Set(elementKey, "some cached value");
      }
      // get value from the cache by key
      message = "Item value is: " + redisClient.Get<string>("some cached value");
 }

类型化实体集更有意思和更实用,那是因为它们操作的是适度可止品种的目的。在底下的代码示例中,有八个类分别定义为Phone和Person——phone的主人。每一种phone实例援引它的全数者。上面包车型大巴代码演示大家如何通过典型增进、删除和意识缓存项:

public class Phone
{
   public int Id { get; set; }
   public string Model { get; set; }
   public string Manufacturer { get; set; }
   public Person Owner { get; set; }
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
    public string Profession { get; set; }
}

using (RedisClient redisClient = new RedisClient(host))
{
     IRedisTypedClient<phone> phones = redisClient.As<phone>();
     Phone phoneFive = phones.GetValue("5");
     if (phoneFive == null)
     {
          // make a small delay
          Thread.Sleep(5000);
          // creating a new Phone entry
          phoneFive = new Phone
          {
               Id = 5,
               Manufacturer = "Motorolla",
               Model = "xxxxx",
               Owner = new Person
               {
                    Id = 1,
                    Age = 90,
                    Name = "OldOne",
                    Profession = "sportsmen",
                    Surname = "OldManSurname"
               }
          };
          // adding Entry to the typed entity set
          phones.SetEntry(phoneFive.Id.ToString(), phoneFive);
     }
     message = "Phone model is " + phoneFive.Manufacturer;
     message += "Phone Owner Name is: " + phoneFive.Owner.Name;
}

在上头的例子中,大家实例化了输入端IRedisTypedClient,它与缓存对象的一定项目——Phone类型一同专门的学业。

ASP.NET Web API

对此本身那么些初读书人的话ASP.NET Web API那个框架很不熟悉又熟谙着。

不谙的是ASP.NET Web API是一个簇新的框架,对于这么些框架在一个品类中起到的效应作者目前还不是很明亮这里也就不妄下定论了,说真的不是自笔者不想而是笔者一点办法也未有,只好和煦去寻觅试着去询问它。

熟稔的是ASP.NET Web API跟ASP.NET MVC的框构造造大器晚成最早看起来有点经常的地点。

话就超少说了,我们就和本身一齐来学习ASP.NET Web API那一个全新的框架吧。

链接

什么运行Redis服务:

文档:

.NET / C#示例:

关于怎么着用C#在Windows上利用Redis的好提议:

http://maxivak.com/getting-started-with-redis-and-asp-net-mvc-under-windows/:

关于Redis:

Azure缓存

ASP.NET Web API演示示例

条件根底配置

率先大家新建三个类库项目命名称为Common,况兼定义个商品消息项目,示例代码如下:

代码1-1

namespace Common{    public class Product    {        public string ProductID { get; set; }        public string ProductName { get; set; }        public string ProductCategory { get; set; }    }}

树立WebHost宿主情况

接下来大家随后创设三个空的ASP.NET WEB应用程序命名字为WebHost,这里说美素佳儿下ASP.NET Web API框架只是个独立框架,它并不可能独立运维,所以它须求宿主情形,刚刚我们新建的WEB应用程序则会在底下的演示中一时半刻的承先启后着ASP.NET Web API框架来运营。

征引程序集

Newtonsoft.Json.dll 路径: C:Program FilesMicrosoft ASP.NETASP.NET MVC 4PackagesNewtonsoft.Json.4.5.6libnet40Newtonsoft.Json.dll

System.Net.Http.dll 路径:C:Program FilesMicrosoft ASP.NETASP.NET MVC 4Assemblies System.Net.Http.dll

System.Net.Http.Formatting.dll路径:C:Program FilesMicrosoft ASP.NETASP.NET MVC 4Assemblies System.Net.Http.Formatting.dll

System.Web.Http.dll 路径:C:Program FilesMicrosoft ASP.NETASP.NET MVC 4Assemblies System.Web.Http.dll

System.Web.Http.WebHost.dll路径:C:Program FilesMicrosoft ASP.NETASP.NET MVC 4AssembliesSystem.Web.Http.WebHost.dll

Common.dll

抑或选拔这种征引形式:

图片 2

(假如上文中所述的目录地点并未有Newtonsoft.Json.dll的话能够文件寻觅一下,然后手动援用。)

继之大家再建构一个Web应用程序管理类Globl.asax ,并在其Application_Start(State of Qatar方法中注册路由,示例代码如下:

代码1-2

using System.Web.Http;namespace WebHost{    public class Global : System.Web.HttpApplication    {        protected void Application_Start(object sender, EventArgs e)        {            GlobalConfiguration.Configuration.Routes.MapHttpRoute(              "DefaultAPI", "api/{controller}/{id}", new { controller="product",id = RouteParameter.Optional });        }    }}

路由注册好了现在,我们还得新建个Web API调节器,命名称为ProductController,示例代码如下:

代码1-3

using System.Web.Http;using Common;namespace WebHost.Controllers{    public class ProductController:ApiController    {        private static List<Product> products;        static ProductController()        {            products = new List<Product>();            products.AddRange(                new Product[]                 {                    new Product(){ ProductID="001", ProductName="牙刷",ProductCategory="洗漱用品"},                    new Product(){ ProductID="002", ProductName="《.NET框架设计—大型企业级应用框架设计艺术》", ProductCategory="书籍"}                });        }        public IEnumerable<Product> Get(string id = null)        {            return from product in products where product.ProductID == id || string.IsNullOrEmpty select product;        }    }}

在代码1-3中大家看出ProductController调节器世襲自ApiController,这里的办法本人的估量应该是跟ASP.NET MVC框架对调整器的拍卖同样,在伸手到来之后还要经过路由拍卖今后,Web API框架会把最近项目中保有援引的次第集全部搜寻一下并且搜出世襲自ApiController的项目,而且缓存在三个xml文件,不理解推断的对不对在背后的字数我们再来验证,这里提一下。

稳重的意中人的只怕发今后路由注册的时候并不曾对应的Action的路由参数,其实这里就是Web API框架的一个差异之处,它是依据Http恳求方法来规定Action的情势的,然则浏览器私下认可的乞请方法正是Http-get,所以大家以当时候能够直接运转项目。

图2

图片 3

建立SelfHost

上边大家来看一下在SelfHost宿主情状中ASP.NET Web API框架的施用示例。

率先大家新建叁个调控台应用程序命名字为SelfHost,SelfHost意况项目的次序集援引和方面所说的WebHost项目援用独一分裂的正是把System.Web.Http.WebHost.dll程序集换到System.Web.Http.SelfHost.dll程序集,援用路线不改变,也足以运用援用里的恢弘栏来增加。

下边就让大家看一下在SelfHost中大家要求做什么样事,首先大家要求注册路由那是每趟最先做的政工,示例代码如下:

代码1-4

using System.Web.Http;using System.Web.Http.SelfHost;namespace SelfHost{    class Program    {        static void Main(string[] args)        {            HttpSelfHostConfiguration selfHostConfiguration =                new HttpSelfHostConfiguration("http://localhost/selfhost");            using (HttpSelfHostServer selfHostServer = new HttpSelfHostServer(selfHostConfiguration))            {                selfHostServer.Configuration.Routes.MapHttpRoute(                    "DefaultApi", "api/{controller}/{id}", new { id=RouteParameter.Optional});                selfHostServer.OpenAsync();                Console.WriteLine("服务器端服务监听已开启");                Console.Read();            }        }    }}

这里就总结的验证一下,在1-4代码中HttpSelfHostConfiguration对象示例中设置了营地址,对于HttpSelfHostConfiguration类型它是继续自HttpConfiguration类型,HttpConfiguration类型是比较根本的一个项目,WebAPI框架中山大学部分的布署音讯都在这里类型实例中展开设置。在三番四次的篇幅中会有聊到。

HttpSelfHostServer对象正是在SelfHost宿主意况中担当着很着重的剧中人物,它担任管理要求等一文山会海操作(因为它是WebAPI框架在SelfHost意况中的管道模型的“龙头”),在那只要稍作领会就能够了,会在前面的管道篇幅揭示它的机要面纱。

继续向下看大家会看见HttpSelfHostServer对象实例中的Configuration属性里的Routes属性提供了对路由的登记,那有的内容会在末端的路由篇幅讲授。

再之后正是大家看来的,张开服务监听,等待管理诉求。(这里的监听/管理央浼,并非对实在的乞求进行拍卖,而是对曾经呼吁棉被服装进好了的目的开展拍卖,管道篇幅中等教育授)

在路由登记之后我们要新建个Web API调节器,就有如上边WebHost部分内容相近,拷贝豆蔻梢头份过来,不过我们那边要对调整器的代码稍作修改,示例代码如下:

代码1-5

using System.Web.Http;using Common;namespace SelfHost.Controllers{    public class ProductController:ApiController    {        private static List<Product> products;        static ProductController()        {            products = new List<Product>();            products.AddRange(                new Product[]                 {                    new Product(){ ProductID="001", ProductName="牙刷",ProductCategory="洗漱用品"},                    new Product(){ ProductID="002", ProductName="《.NET框架设计—大型企业级应用框架设计艺术》", ProductCategory="书籍"}                });        }        public IEnumerable<Product> Get(string id = null)        {            return from product in products where product.ProductID == id || string.IsNullOrEmpty select product;        }        public void Delete(string id)        {            products.Remove(products.First(product => product.ProductID == id));        }        public void Post(Product product)        {            products.Add;        }        public void Put(Product product)        {            Delete(product.ProductID);            Post;        }    }}

对此在代码1-5中央调控制器新扩大的多少个Action方法,也是各自对应着Http央浼方法。这样也正是能促成增加和删除改查的幼功功效了。这我们还索要一个对它举行拜望的顾客端。

建立Clinet

大家再建二个调整台应用程序命名字为Clinet,并且拉长如下程序集援引:

Newtonsoft.Json.dll 路径: C:Program FilesMicrosoft ASP.NETASP.NET MVC 4PackagesNewtonsoft.Json.4.5.6libnet40Newtonsoft.Json.dll

System.Net.Http.dll 路径:C:Program FilesMicrosoft ASP.NETASP.NET MVC 4Assemblies System.Net.Http.dll

System.Net.Http.Formatting.dll路径:C:Program FilesMicrosoft ASP.NETASP.NET MVC 4Assemblies System.Net.Http.Formatting.dll

Common.dll

上边大家看一下在Client项目中对SelfHost境遇中的能源开展采访的演示,示例代码如下:

代码1-6

using Common;using System.Net.Http;namespace Client{    class Program    {        static void Main(string[] args)        {            AsyncProcess();            Console.Read();        }        private async static void AsyncProcess()        {            HttpClient httpClient = new HttpClient();            //获取货品信息列表            HttpResponseMessage responseMessage =                await httpClient.GetAsync("http://localhost/selfhost/api/product");            IEnumerable<Product> products = await responseMessage.Content.ReadAsAsync<IEnumerable<Product>>();            OutputProductInfo;            //添加货品            Product product = new Product()            {                ProductID = "003",                ProductName = "《ASP.NET Web API 2 框架揭秘》",                ProductCategory = "食品类"            };            await httpClient.PostAsJsonAsync<Product>("http://localhost/selfhost/api/product", product);            responseMessage = await httpClient.GetAsync("http://localhost/selfhost/api/product");            products = await responseMessage.Content.ReadAsAsync<IEnumerable<Product>>();            OutputProductInfo;            //修改指定货品信息            responseMessage = await httpClient.GetAsync("http://localhost/selfhost/api/product/003");            product = (await responseMessage.Content.ReadAsAsync<IEnumerable<Product>>.First();            product.ProductCategory = "书籍";            await httpClient.PutAsJsonAsync<Product>("http://localhost/selfhost/api/product", product);            responseMessage = await httpClient.GetAsync("http://localhost/selfhost/api/product");            products = await responseMessage.Content.ReadAsAsync<IEnumerable<Product>>();            OutputProductInfo;            //删除指定货品            await httpClient.DeleteAsync("http://localhost/selfhost/api/product/001");            responseMessage = await httpClient.GetAsync("http://localhost/selfhost/api/product");            products = await responseMessage.Content.ReadAsAsync<IEnumerable<Product>>();            OutputProductInfo;        }        private static void OutputProductInfo(IEnumerable<Product> products)        {            foreach (Product product in products)            {                Console.WriteLine(                    "ProductID:{0},ProductName:{1},ProductCategorm:{2}",                    product.ProductID, product.ProductName, product.ProductCategory);            }            Console.WriteLine("—————————————————————————");        }    }}

对此代码1-5中冒出多数的花色会在后面的字数中相继的上课,这里就不做讲演了,而是看一下大家最后的以身作则结果:

第风流洒脱大家要运转SelfHost项目,等待分界面和如下图3时,再行Client项目对SelfHost中的财富实行访谈。结果如图4

图3

图片 4

图4

图片 5

仿效资料:

不畏模仿蒋大书籍中的示例简化了弹指间做了一点调治,因为背后的篇幅中有用到这一个示例。

那边嘲谑一下最初国内对于Web API的书本资料差非常的少从未,当然国外的有是有,可是都以英语版的。对于毫无Lithuania语底蕴的本人非凡是判了生命刑,唯风流浪漫的活计正是用翻译工具一丝丝的去看。

图片 6

还好蒋大的新作出来了,不然想学Web API还真是入地无门。已看完前三章,收获颇多知识点很全面,在背后我读书到某个都会写出来跟我们享受。

图片 7

出处:

正文版权归笔者和博客园共有,招待转发,但未经小编同意必需保留此段注脚,且在篇章页面

Redis服务器复制(主—从配置)

Redis扶助中央同步,即,每趟主服务器纠正,从服务器得到照看,并机关同步。许多复制用于读取(但不可能写)扩张和数码冗余和服务器故障转移。设置多少个Redis实例(在同生机勃勃或差异服务器上的四个劳务),然后配置内部之意气风发作为从站。为了让Redis服务器实例是另风流倜傥台服务器的直属,能够如此改过配置文件:

找到以下代码:

# slaveof <masterip> <masterport>

替换为:

slaveof 192.168.1.1 6379

(能够自定义钦定主服务器的真人真事IP和端口)。借使主服务器配置为急需密码(验证),可以如下所示改造redis.conf,找到那黄金年代行代码:

# masterauth <master-password>

删去开端的#标志,用主服务器的密码替换<master-password>,即:

masterauth mastpassword

未来这几个Redis实例能够被用来作为主服务器的只读同步别本。

ASP.NET Web API 开篇示例介绍

Redis服务器敬服:密码,IP过滤

爱护Redis服务器的入眼措施是使用Windows防火墙或活跃的互联网连接属性设置IP过滤。其余,还足以应用Redis密码设置额外爱护。那供给用上边包车型客车章程立异Redis配置文件(redis.conf):

第生机勃勃,找到那行:

# requirepass foobared

除去带头的#标志,用新密码替换foobared:

requirepass foobared

接下来,重新启航Redis Windows服务!

当现实应用顾客端的时候,使用带密码的构造函数:

RedisClient client = new RedisClient(serverHost, port, redisPassword);

Redis Set(集合)和List(列表)

重大体育专科学园注的是,Redis列表达成IList<T>,而Redis集合实现ICollection<T>。上面包车型大巴话说什么样行使它们。

当须要区分肖似档期的顺序的比不上分类目的时,使用列表。举例,大家有“mostSelling(紧俏手提式有线话机)”和“oldCollection(回笼手提式有线电话机)”八个列表:

string host = "localhost";
using (var redisClient = new RedisClient(host))
{
    //Create a 'strongly-typed' API that makes all Redis Value operations to apply against Phones
    IRedisTypedClient<phone> redis = redisClient.As<phone>();

    IRedisList<phone> mostSelling = redis.Lists["urn:phones:mostselling"];
    IRedisList<phone> oldCollection = redis.Lists["urn:phones:oldcollection"];

    Person phonesOwner = new Person
        {
            Id = 7,
            Age = 90,
            Name = "OldOne",
            Profession = "sportsmen",
            Surname = "OldManSurname"
        };

    // adding new items to the list
    mostSelling.Add(new Phone
            {
                Id = 5,
                Manufacturer = "Sony",
                Model = "768564564566",
                Owner = phonesOwner
            });

    oldCollection.Add(new Phone
            {
                Id = 8,
                Manufacturer = "Motorolla",
                Model = "324557546754",
                Owner = phonesOwner
            });

    var upgradedPhone  = new Phone
    {
        Id = 3,
        Manufacturer = "LG",
        Model = "634563456",
        Owner = phonesOwner
    };

    mostSelling.Add(upgradedPhone);

    // remove item from the list
    oldCollection.Remove(upgradedPhone);

    // find objects in the cache
    IEnumerable<phone> LGPhones = mostSelling.Where(ph => ph.Manufacturer == "LG");

    // find specific
    Phone singleElement = mostSelling.FirstOrDefault(ph => ph.Id == 8);

    //reset sequence and delete all lists
    redis.SetSequence(0);
    redisClient.Remove("urn:phones:mostselling");
    redisClient.Remove("urn:phones:oldcollection");
}

当供给仓库储存相关的数据集和采撷总结音信,譬喻answer -> queustion给答案或主题素材投票时,Redis集结就那几个好使。纵然大家有超多的主题材料(queustion)和答案(answer ),需求将它们存款和储蓄在缓存中。使用Redis,咱们得以这么做:

/// <summary>
/// Gets or sets the Redis Manager. The built-in IoC used with ServiceStack autowires this property.
/// </summary>
IRedisClientsManager RedisManager { get; set; }
/// <summary>
/// Delete question by performing compensating actions to 
/// StoreQuestion() to keep the datastore in a consistent state
/// </summary>
/// <param name="questionId">
public void DeleteQuestion(long questionId)
{
    using (var redis = RedisManager.GetClient())
    {
        var redisQuestions = redis.As<question>();

        var question = redisQuestions.GetById(questionId);
        if (question == null) return;

        //decrement score in tags list
        question.Tags.ForEach(tag => redis.IncrementItemInSortedSet("urn:tags", tag, -1));

        //remove all related answers
        redisQuestions.DeleteRelatedEntities<answer>(questionId);

        //remove this question from user index
        redis.RemoveItemFromSet("urn:user>q:" + question.UserId, questionId.ToString());

        //remove tag => questions index for each tag
        question.Tags.ForEach("urn:tags>q:" + tag.ToLower(), questionId.ToString()));

        redisQuestions.DeleteById(questionId);
    }
}

public void StoreQuestion(Question question)
{
    using (var redis = RedisManager.GetClient())
    {
        var redisQuestions = redis.As<question>();

        if (question.Tags == null) question.Tags = new List<string>();
        if (question.Id == default(long))
        {
            question.Id = redisQuestions.GetNextSequence();
            question.CreatedDate = DateTime.UtcNow;

            //Increment the popularity for each new question tag
            question.Tags.ForEach(tag => redis.IncrementItemInSortedSet("urn:tags", tag, 1));
        }

        redisQuestions.Store(question);
        redisQuestions.AddToRecentsList(question);
        redis.AddItemToSet("urn:user>q:" + question.UserId, question.Id.ToString());

        //Usage of tags - Populate tag => questions index for each tag
        question.Tags.ForEach(tag => redis.AddItemToSet
        ("urn:tags>q:" + tag.ToLower(), question.Id.ToString()));
    }
}

/// <summary>
/// Delete Answer by performing compensating actions to 
/// StoreAnswer() to keep the datastore in a consistent state
/// </summary>
/// <param name="questionId">
/// <param name="answerId">
public void DeleteAnswer(long questionId, long answerId)
{
    using (var redis = RedisManager.GetClient())
    {
        var answer = redis.As<question>().GetRelatedEntities<answer>
        (questionId).FirstOrDefault(x => x.Id == answerId);
        if (answer == null) return;

        redis.As<question>().DeleteRelatedEntity<answer>(questionId, answerId);

        //remove user => answer index
        redis.RemoveItemFromSet("urn:user>a:" + answer.UserId, answerId.ToString());
    }
}

public void StoreAnswer(Answer answer)
{
    using (var redis = RedisManager.GetClient())
    {
        if (answer.Id == default(long))
        {
            answer.Id = redis.As<answer>().GetNextSequence();
            answer.CreatedDate = DateTime.UtcNow;
        }

        //Store as a 'Related Answer' to the parent Question
        redis.As<question>().StoreRelatedEntities(answer.QuestionId, answer);
        //Populate user => answer index
        redis.AddItemToSet("urn:user>a:" + answer.UserId, answer.Id.ToString());
    }
}

public List<answer> GetAnswersForQuestion(long questionId)
{
    using (var redis = RedisManager.GetClient())
    {
        return redis.As<question>().GetRelatedEntities<answer>(questionId);
    }
}

public void VoteQuestionUp(long userId, long questionId)
{
    //Populate Question => User and User => Question set indexes in a single transaction
    RedisManager.ExecTrans(trans =>
    {
        //Register upvote against question and remove any downvotes if any
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:q>user+:" + questionId, userId.ToString()));
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:q>user-:" + questionId, userId.ToString()));

        //Register upvote against user and remove any downvotes if any
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:user>q+:" + userId, questionId.ToString()));
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:user>q-:" + userId, questionId.ToString()));
    });
}

public void VoteQuestionDown(long userId, long questionId)
{
    //Populate Question => User and User => Question set indexes in a single transaction
    RedisManager.ExecTrans(trans =>
    {
        //Register downvote against question and remove any upvotes if any
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:q>user-:" + questionId, userId.ToString()));
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:q>user+:" + questionId, userId.ToString()));

        //Register downvote against user and remove any upvotes if any
        trans.QueueCommand(redis => 
        redis.AddItemToSet"urn:user>q-:" + userId, questionId.ToString()));
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:user>q+:" + userId, questionId.ToString()));
    });
}

public void VoteAnswerUp(long userId, long answerId)
{
    //Populate Question => User and User => Question set indexes in a single transaction
    RedisManager.ExecTrans(trans =>
    {
        //Register upvote against answer and remove any downvotes if any
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:a>user+:" + answerId, userId.ToString()));
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:a>user-:" + answerId, userId.ToString()));

        //Register upvote against user and remove any downvotes if any
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:user>a+:" + userId, answerId.ToString()));
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:user>a-:" + userId, answerId.ToString()));
    });
}

public void VoteAnswerDown(long userId, long answerId)
{
    //Populate Question => User and User => Question set indexes in a single transaction
    RedisManager.ExecTrans(trans =>
    {
        //Register downvote against answer and remove any upvotes if any
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:a>user-:" + answerId, userId.ToString()));
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:a>user+:" + answerId, userId.ToString()));

        //Register downvote against user and remove any upvotes if any
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:user>a-:" + userId, answerId.ToString()));
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:user>a+:" + userId, answerId.ToString()));
    });
}

public QuestionResult GetQuestion(long questionId)
{
    var question = RedisManager.ExecAs<question>
    (redisQuestions => redisQuestions.GetById(questionId));
    if (question == null) return null;

    var result = ToQuestionResults(new[] { question })[0];
    var answers = GetAnswersForQuestion(questionId);
    var uniqueUserIds = answers.ConvertAll(x => x.UserId).ToHashSet();
    var usersMap = GetUsersByIds(uniqueUserIds).ToDictionary(x => x.Id);

    result.Answers = answers.ConvertAll(answer =>
        new AnswerResult { Answer = answer, User = usersMap[answer.UserId] });

    return result;
}

public List<user> GetUsersByIds(IEnumerable<long> userIds)
{
    return RedisManager.ExecAs<user>(redisUsers => redisUsers.GetByIds(userIds)).ToList();
}

public QuestionStat GetQuestionStats(long questionId)
{
    using (var redis = RedisManager.GetReadOnlyClient())
    {
        var result = new QuestionStat
        {
            VotesUpCount = redis.GetSetCount("urn:q>user+:" +questionId),
            VotesDownCount = redis.GetSetCount("urn:q>user-:" + questionId)
        };
        result.VotesTotal = result.VotesUpCount - result.VotesDownCount;
        return result;
    }
}

public List<tag> GetTagsByPopularity(int skip, int take)
{
    using (var redis = RedisManager.GetReadOnlyClient())
    {
        var tagEntries = redis.GetRangeWithScoresFromSortedSetDesc("urn:tags", skip, take);
        var tags = tagEntries.ConvertAll(kvp => new Tag { Name = kvp.Key, Score = (int)kvp.Value });
        return tags;
    }
}

public SiteStats GetSiteStats()
{
    using (var redis = RedisManager.GetClient())
    {
        return new SiteStats
        {
            QuestionsCount = redis.As<question>().TypeIdsSet.Count,
            AnswersCount = redis.As<answer>().TypeIdsSet.Count,
            TopTags = GetTagsByPopularity(0, 10)
        };
    }
}

许可证

那篇小说,以致任何相关的源代码和文件,依赖The Code Project Open License (CPOL卡塔尔国。

缺点

  • 尚未本地数据缓存(如在Azure缓存同步本地数据缓存)
  • 从没完全集群化的支撑(然而,大概二零一两年年初会完成)

介绍

在此篇作品中,小编想介绍本身通晓的风度翩翩种最严密的装置和布局Redis服务器的章程。另外,作者想简短地概述一下在.NET / C#客户端下Redis hash(哈希类型)和list(链表)的行使。

在这里篇小说主要讲到:

  • 安装Redis服务器(附完整的应用程序文件设置)
  • Redis服务器珍重(配献身份验证)
  • 配置服务器复制
  • 从C#应用程序访谈缓存
  • 利用Redis ASP.NET会话状态
  • Redis 会集(Set)、列表(List)和事务管理用法示例
  • 注明附加的源(Redis Funq LoC MVC项目:举个例子)
  • 缓存的优化思路
上一篇:新特性之Class 下一篇:每天一个