惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 李国宝

2206年最佳边缘计算集群方案:Tailscale + k3s 谁不想要自己的Tailscale内网呢~ 腾讯云API网关废了?集群开源方案平替 来一打自建IP Proxy玩玩之Majora Github Copilot 比在座各位更会写代码。jpg .NET Core + React Antd Pro脚手架 【爬虫系列】2. 打开App逆向“潘多拉魔盒” Ratel:一直站在Android逆向巅峰的平头哥 【爬虫系列】1. 无事,Python验证码识别入门 【爬虫系列】0. 无内鬼,破解前端JS参数签名 利用容器逃逸实现远程登录k8s集群节点 边缘计算k8s集群SuperEdge初体验 能动手绝不多说:开源评论系统remark42上手指南 一次依赖注入不慎引发的一连串事故 反手来个K8S入门到跑路 MySQL Online DDL导致全局锁表案例分析 任务队列和异步接口的正确打开方式(.NET Core版本) .NET Core中使用RabbitMQ正确方式 - 李国宝 - 博客园 .NET Core单元测试之搞死开发的覆盖率统计(coverlet + ReportGenerator )
.NET Core教程--给API加一个服务端缓存啦
李国宝 · 2019-05-05 · via 博客园 - 李国宝

以前给API接口写缓存基本都是这样写代码:

// redis key 
var bookRedisKey = ConstRedisKey.RecommendationBooks.CopyOne(bookId);
// 获取缓存数据         
var cacheBookIds = _redisService.ReadCache<List<string>>(bookRedisKey);
if (cacheBookIds != null)
{
    // return
}
else
{
   // 执行另外的逻辑获取数据, 然后写入缓存
}

然后把这一坨坨代码都散落在每个地方。

某一天,突然想起我这边的缓存基本时间都差不多,而且都是给Web API用的,

直接在API层支持缓存不就完事了。

所以, 这里用什么来做呢。

在.NET Core Web API这里的话, 两种思路:Middleware 或者ActionFilter.

不了解的同学可以看下面的文档:

ASP.NET Core 中文文档 第四章 MVC(4.3)过滤器

ASP.NET Core 中文文档 第三章 原理(2)中间件

基于我这边只是部分接口支持缓存的话, 直接还是用ActionFilter实现就可以.

没撒说的, 直接上代码.

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json.Linq;

namespace XXXAPI.Filters
{
    public class DefaultCacheFilterAttribute : ActionFilterAttribute
    {
        // 这个时间用于给子类重写,实现不同时间级别的缓存
        protected TimeSpan _expireTime;
     
        // redis读写的类,没撒看的
        private readonly RedisService _redisService;

        public DefaultCacheFilterAttribute(RedisService redisService)
        {
            _redisService = redisService;

        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (context.HttpContext.Request.Query.ContainsKey("refresh"))
            {
                return;
            }
            KeyConfig redisKey = GetRequestRedisKey(context.HttpContext);
            var redisCache = _redisService.ReadCache<JToken>(redisKey);
            if (redisCache != null)
            {
                context.Result = new ObjectResult(redisCache);
            }
            return;
        }

        public override void OnActionExecuted(ActionExecutedContext context)
        {
            KeyConfig redisKey = GetRequestRedisKey(context.HttpContext);
            var objResult = (ObjectResult)context.Result;
            if (objResult == null)
            {
                return;
            }
            var jToken = JToken.FromObject(objResult.Value);
            _redisService.WriteCache(redisKey, jToken);
        }

        private KeyConfig GetRequestRedisKey(HttpContext httpContext)
        {
            var requestPath = httpContext.Request.Path.Value;
            if (!string.IsNullOrEmpty(httpContext.Request.QueryString.Value))
            {
                requestPath = requestPath + httpContext.Request.QueryString.Value;
            }
            if (httpContext.Request.Query.ContainsKey("refresh"))
            {
                if (httpContext.Request.Query.Count == 1)
                {
                    requestPath = requestPath.Replace("?refresh=true", "");
                }
                else
                {
                    requestPath = requestPath.Replace("refresh=true", "");
                }
            }
            // 这里也就一个redis key的类
            var redisKey = ConstRedisKey.HTTPRequest.CopyOne(requestPath);
            if (_expireTime != default(TimeSpan))
            {
                redisKey.ExpireTime = _expireTime;
            }
            return redisKey;
        }
    }

    public static class ConstRedisKey
    {
        public readonly static KeyConfig HTTPRequest = new KeyConfig()
        {
            Key = "lemon_req_",
            ExpireTime = new TimeSpan(TimeSpan.TicksPerMinute * 30),
            DBName = 5
        };
    }

    public class KeyConfig
    {
        public string Key { get; set; }

        public TimeSpan ExpireTime { get; set; }

        public int DBName { get; set; }


        public KeyConfig CopyOne(string state)
        {
            var one = new KeyConfig();
            one.DBName = this.DBName;
            one.Key = !string.IsNullOrEmpty(this.Key) ? this.Key + state : state;
            one.ExpireTime = this.ExpireTime;
            return one;
        }

    }
}

然后使用的地方, 直接给Controller的Action方法加上注解即可.

如:

        [HttpGet("v1/xxx/latest")]
        [ServiceFilter(typeof(DefaultCacheFilterAttribute))]
        public IActionResult GetLatestList([FromQuery] int page = 0, [FromQuery]int pageSize = 30)
        {
            return Ok(new
            {
                data = _service.LoadLatest(page, pageSize),
                code = 0
            });
        }

完事...

哦, 记得在Startup.cs注入 DefaultCacheFilterAttribute.

这个注入就不用我来写的吧.

美中不足的地方在于暂时还不知道怎么直接在注解上面支持自定义缓存时间,

凑合先用了.

完结, 拜.....