.Net Redis实战——使用Redis构建Web应用
示例介绍
示例1:借助Redis实现购物车功能
示例2:Redis实现网页缓存和数据缓存
借助Redis实现购物车功能
每个用户的购物车都是一个散列,散列存储了商品ID与商品订购数量之间的映射。订购商品时,对购物车进行更新:如果用户订购某件商品的数量大于0,那么将这件商品的ID以及用户订购该商品的数量添加到散列里面,如果用户购买的商品已经存在散列里面,那么新的订购数量会覆盖已有的订购数量;相反,如果用户订购某件商品数量不大于0,那么程序将从散列里面移除该条目。
由于整个示例分Controller和WebApi两部分,在不考虑封装Redis操作的情况下提取Redis连接字符串到appSetting.json中
"ConnectionStrings": { "Redis": "localhost,abortConnect=false" },
保存用户购物查数据示例代码:
[HttpGet("UpdateCart")] public string UpdateCart(string token,string item,int count) { var key = $"cart:{token}"; using (var redis = ConnectionMultiplexer.Connect(redisConnectionStr)) { var db = redis.GetDatabase(); //更新购物车数据 if (count <= 0) { db.HashDeleteAsync(key, item); } else { db.HashSetAsync(key, item,count); } } return "更新购物车成功"; }
Redis实现网页缓存和数据缓存
针对不会频繁更新得动态网页或Ajax返回的数据可以缓存在Redis中,减少与数据库的交互提升系统效应效率。
该示例只是为了演示借助Reids实现页面缓存和数据缓存效果,实际使用中可通过ResponseCache特性实现缓存。
详细介绍:https://docs.microsoft.com/en-us/aspnet/core/performance/caching/response?view=aspnetcore-5.0
网页数据缓存
新建示例项目时为WebApi项目,修改Startup类添加Web Mvc支持。
ConfigureServices方法中修改services.AddControllers()为services.AddControllersWithViews()。
Configure方法中app.UseEndpoints修改为如下代码
app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); });
定义中间件类RedisCacheMiddleware,用来缓存网页页面
public class RedisCacheMiddleware { private readonly RequestDelegate _next; public IConfiguration Configuration { get; } public RedisCacheMiddleware(RequestDelegate next, IConfiguration configuration) { _next = next; Configuration = configuration; } public async Task InvokeAsync(HttpContext context) { var path = context.Request.Path.Value.ToLower(); if (path == "/home" || path == "/home/index") { var responseContent = ""; //Copy a pointer to the original response body stream var originalBodyStream = context.Response.Body; using (var redis = ConnectionMultiplexer.Connect(Configuration.GetConnectionString("Redis"))) { var db = redis.GetDatabase(); if (db.KeyExists(path)) { responseContent = db.StringGet(path); await RespondWithIndexHtml(context.Response, responseContent); return; } else { using (var responseBody = new MemoryStream()) { //...and use that for the temporary response body context.Response.Body = responseBody; //Continue down the Middleware pipeline, eventually returning to this class await _next(context); //Format the response from the server responseContent = await FormatResponse(context.Response); //Copy the contents of the new memory stream (which contains the response) to the original stream, which is then returned to the client. await responseBody.CopyToAsync(originalBodyStream); } db.StringSet(path, responseContent, expiry: TimeSpan.FromSeconds(30)); } } } // Call the next delegate/middleware in the pipeline await _next(context); } private async Task RespondWithIndexHtml(HttpResponse response,string html) { response.StatusCode = 200; response.ContentType = "text/html"; await response.WriteAsync(html, Encoding.UTF8); } private async Task<string> FormatResponse(HttpResponse response) { //We need to read the response stream from the beginning... response.Body.Seek(0, SeekOrigin.Begin); //...and copy it into a string string text = await new StreamReader(response.Body).ReadToEndAsync(); //We need to reset the reader for the response so that the client can read it. response.Body.Seek(0, SeekOrigin.Begin); //Return the string for the response return text; } }
添加中间件调用
app.UseMiddleware<RedisCacheMiddleware>();
运行效果如图:
网页上的时间会每30秒更新一次。
.Net Core提供的响应缓存中间件:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/middleware?view=aspnetcore-5.0
Ajax数据缓存
本例只是简单的数据存储,实际使用中可编写单独的服务,让这个服务将指定的数据缓存到Redis里面,并不定期地对这些缓存进行更新。
示例代码
[HttpGet("GetDateTime")] public string GetDateTime() { var dateTime = ""; var key = "data:datetime"; using (var redis = ConnectionMultiplexer.Connect(redisConnectionStr)) { var db = redis.GetDatabase(); if (db.KeyExists(key)) { dateTime = db.StringGet(key); } else { dateTime = DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss"); db.StringSet(key, dateTime,expiry:TimeSpan.FromSeconds(5)); } } return dateTime; }