首页 > 其他分享 >用NetCore + ReactJS 实现一个前后端分离的网站 (6) 缓存机制

用NetCore + ReactJS 实现一个前后端分离的网站 (6) 缓存机制

时间:2022-12-08 14:14:35浏览次数:50  
标签:缓存 NetCore ReactJS cache context var using public

1. 前言

对于实时性要求不高的资源,我们一般可以利用缓存机制来降低数据库的请求压力。
轻量级的应用可以用自带的MemoryCache,如果对缓存的高并发、持久化有要求的可以用Redis。
本节用MemoryCache来实现缓存机制。

2. 自定义属性

先创建一个ApiCacheAttribute,接受一个缓存时间。
给方法添加属性,这里传了一个参数60,意思是返回值会在缓存里存在60秒。

ApiCacheAttribute.cs
using Microsoft.AspNetCore.Mvc.Filters;

namespace NovelTogether.Core.API.Attributes
{
    // IFilterMetadata 是为了在过滤器中能够获取到这个自定义属性
    public class ApiCacheAttribute: Attribute, IFilterMetadata
    {
        public int DurationSeconds { get; set; }

        public ApiCacheAttribute(int durationSeconds)
        {
            DurationSeconds = durationSeconds;
        }
    }
}

NovelController.cs
[HttpGet("{id}")]
[ApiAuthorize]
[ApiCache(60)]
public async Task<ResponseModel<Novel>> Get(int id)
{
    var novel = await _novelService.SelectAsync(x => x.ID == id);
    return new ResponseModel<Novel>().Ok(novel);
}

3. 缓存的存取实现

ICacheHelper.cs
namespace NovelTogether.Core.API.Helpers.Cache
{
    public interface ICacheHelper
    {
        public object? Get(object key);
        public void Set(object key, object value, TimeSpan relativeTimeToNow);
    }
}

MemoryCacheHelper
using Microsoft.Extensions.Caching.Memory;

namespace NovelTogether.Core.API.Helpers.Cache
{
    public class MemoryCacheHelper : ICacheHelper
    {
        private readonly IMemoryCache _cache;
        public MemoryCacheHelper(IMemoryCache cache)
        {
            _cache = cache;
        }

        public object? Get(object key)
        {
            return _cache.Get(key);
        }

        public void Set(object key, object value, TimeSpan relativeTimeToNow)
        {
            _cache.Set(key, value, relativeTimeToNow);
        }
    }
}

3. 过滤器(MemoryCache)

通过过滤器过滤请求,把方法名和参数值作为key,返回值作为value存入缓存中。
当过滤器收到相同请求,并且缓存没有超时,那么就直接返回缓存中的value,并且记log。

CacheFilter.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using NovelTogether.Core.API.Attributes;
using NovelTogether.Core.API.Helpers.Cache;
using NovelTogether.Core.API.Utils;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;

namespace NovelTogether.Core.API.Filters
{
    public class CacheFilter : IActionFilter
    {
        private readonly ICacheHelper _cache;
        private readonly ILogger<CacheFilter> _logger;
        
        public  CacheFilter(ICacheHelper cache, ILogger<CacheFilter> logger)
        {
            _cache = cache;
            _logger = logger;
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            var cacheKey = context.HttpContext.Items[Consts.CACHE_KEY];
            if (cacheKey != null)
            {
                cacheKey = cacheKey.ObjToString();
                var duration = int.Parse(context.HttpContext.Items[Consts.CACHE_DURATION_SECONDS].ObjToString());
                _cache.Set(cacheKey, context.Result, new TimeSpan(0, 0, duration));
            }
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            // 如果方法声明了属性[ApiCache],就把资源加入缓存。
            var filters = context.ActionDescriptor.FilterDescriptors;
            foreach (var filter in filters)
            {
                if (filter.Filter is ApiCacheAttribute)
                {
                    var cacheAttribute = (ApiCacheAttribute)filter.Filter;

                    var action = (Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor;
                    var controllerName = action.ControllerTypeInfo.FullName;
                    var actionName = action.ActionName;

                    var option = new JsonSerializerOptions()
                    {
                        Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
                    };

                    var parameters = JsonSerializer.Serialize(context.ActionArguments, option);

                    var cacheKey = $"{controllerName}.{actionName}_{parameters}";

                    var result = _cache.Get(cacheKey);

                    if (result == null)
                    {
                        // 提取方法名和参数,给OnActionExecuted使用
                        context.HttpContext.Items.Add(Consts.CACHE_KEY, cacheKey);
                        context.HttpContext.Items.Add(Consts.CACHE_DURATION_SECONDS, cacheAttribute.DurationSeconds);
                    }
                    else
                    {
                        // 从缓存中取出数据,直接返回
                        context.Result = (IActionResult)result;
                        var uniqueId = context.HttpContext.Items[Consts.UNIQUE_ID].ObjToString();
                        _logger.LogInformation($"Action Executing\r\n唯一标识:{uniqueId}\r\n触发缓存,键值为: {cacheKey}");
                    }

                    return;
                }
            }
        }
    }
}

4. 添加服务

Program.cs
builder.Services.AddControllers(option =>
{
    // 添加日志过滤器
    option.Filters.Add(typeof(LogFilter));
    // 添加缓存过滤器
    option.Filters.Add(typeof(CacheFilter));
    // 添加全局异常过滤器
    option.Filters.Add(typeof(GlobalExceptionFilter));
});
// 添加缓存服务
builder.Services.AddMemoryCache();
// 其他代码
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory(containerBuilder =>
{
    // 其他代码

    // 注册自定义缓存服务
    containerBuilder.RegisterType<MemoryCacheHelper>().As<ICacheHelper>().SingleInstance();

    // 其他代码
}));

5. 执行方法

我执行三次方法,前两次参数一样,从图中可以看出,第二次是从缓存中获取的。第三次换了参数,就没有从缓存中取值。
image

标签:缓存,NetCore,ReactJS,cache,context,var,using,public
From: https://www.cnblogs.com/wang-yi-yi/p/16963133.html

相关文章

  • 用nginx缓存静态文件
      这篇教程说明你应该怎样配置nginx、设置HTTP头部过期时间,用Cache-Control中的max-age标记为静态文件(比如图片、CSS和Javascript文件)设置一个时间,这样用户的......
  • 十五、NHibernate之二级缓存
    什么是NHibernate二级缓存​NHibernate二级缓存由ISessionFactory创建,可以被所有的ISession共享。在NHibernate中,当我们启用NHibernate二级缓存。使用ISession进行数据操作......
  • 017.二级缓存(2)
    1.good.xml(flushCache="true"在sql执行完之后强制清空缓存)<!--flushCache="true"在sql执行完之后强制清空缓存--><selectid="selectGoodsMap"resultType="java......
  • 016.1MyBatis二级缓存(1)
    1.一级缓存和二级缓存  2.缓存的范围  3.二级缓存的运行规则  4.测试一级缓存/***测试一级缓存**@throwsException*/......
  • atguigu3 三级菜单/目录_分布式缓存/分布式锁(product/category)
    0.问题:使用分布式锁解决读模式缓存失效(缓存击穿)和写模式缓存一致性问题!!!公共代码:CategoryBrandRelationService.javapackagecom.atguigu.gulimall.product.service;import......
  • mybatis一级缓存和二级缓存使用详解
    文章目录​​一、概念说明​​​​1、一级缓存​​​​2、二级缓存​​​​3、比较​​​​二、mybatis缓存的生命周期​​​​三、一级缓存的使用​​​​四、二级缓存的使......
  • redis 缓存清除策略
    1.volitile-lru:使用LRU算法移除key,只对设置了过期时间的键2.allkeys-lru:使用LRU算法移除key3.volitile-random:对过期集合中移除随机的key,只对设置了过期时间的key4......
  • .NetCore3.1 配置Swagger
    1.nuget引入Swashbuckle.AspNetCore<ItemGroup><PackageReferenceInclude="Swashbuckle.AspNetCore"Version="6.4.0"/></ItemGroup>2.添加配置中间件Star......
  • Redis 缓存使用问题
    缓存与数据一致性操作缓存和数据库时有三个问题需要考虑1.删除缓存还是更新缓存?更新缓存:每次更新数据库都更新缓存,无效写操作较多删除缓存:更新数据库时让缓存失效,查......
  • 各开发语言DNS缓存配置建议
    作者:翟贺龙一、背景在计算机领域,涉及性能优化动作时首先应被考虑的原则之一便是使用缓存,合理的数据缓存机制能够带来以下收益:1.缩短数据获取路径,热点数据就近缓存以便后......