• ASP.Net Core -- 缓存


    缓存的优点有很多,比如:

       1:提高网站的访问速度

       2:适用于不易改变的数据

    当然也有缺点,比如:

       1:使用缓存之前需要仔细规划这个项目,不然容易引起一些奇怪的副作用

    缓存地点

    1:服务器

    比如是一个单服务器的web应用,缓存就可以放到这个服务器上,就是和web服务器放在一起

    2:缓存服务器

    如果web应用涉及到多个服务器的话,这个时候可以考虑单做做一个缓存服务器,然后其它的web服务器都可以访问这个缓存服务器

    3:客户端

    也就是本地

    In-Memory缓存

    1:这是最简单的,它实现了InMemoryCache这个接口

    2:它适用于Sticky session这样的会话,翻译成中文就是黏性的会话,比如web应用涉及到多个服务器,那么就要保证,你的请求之前是访问的那一台服务器,那么之后想访问缓存数据的话,就必须访问的还是那一台服务器

    3:最后,由于In-Memory使用的内存缓存,所以适用于任何类型的对象

    代码示例

    添加缓存服务,在startup.cs的ConfigureServices()方法中添加:

    services.AddMemoryCache();
    

    这样就可以使用In-Memory这个缓存了,比如要在HomeController里使用,只需要将InMemoryCache这个服务注入即可:

    private readonly ILogger<HomeController> _logger;
            private readonly IMemoryCache _memoryCache;
    
            public HomeController(ILogger<HomeController> logger,
                IMemoryCache memoryCache)
            {
                _logger = logger;
                _memoryCache = memoryCache;
            }
    

    另外,我们还需要给缓存设置一些东西,比如:

    1:缓存时间,

        绝对过期时间::Absolute expiration time,比如一天

        Sliding expiration time:这个不知道怎么翻译,比如当访问到某个缓存后,把该缓存的时间时间再往后调一个小时

    2:缓存的优先级

    3:PostEvictionDelegate:当缓存的数据被清除后将被调用

    再新建一个类,存放一个常量,因为缓存需要一个Key,如下:

    public class CacheEntryConstants
        {
            public const string AlbumsOfToday = nameof(AlbumsOfToday);
        }

    然后在控制器中在Index里,把用户列表数据进行缓存

    public IActionResult Index() 
            {
                if (!_memoryCache.TryGetValue(
                    CacheEntryConstants.AlbumsOfToday,
                    out IEnumerable<Student> cachedStudent))
                {
                    cachedStudent =  _repository.GetAll();
    
                    var cacheEntryOptions = new MemoryCacheEntryOptions()
                        // .SetAbsoluteExpiration(TimeSpan.FromSeconds(600))
                        .SetSlidingExpiration(TimeSpan.FromSeconds(30));
    
                    cacheEntryOptions.RegisterPostEvictionCallback(FillCache, this);
    
                    _memoryCache.Set(CacheEntryConstants.AlbumsOfToday, cachedStudent, cacheEntryOptions);
                }
    
    
                return View(cachedStudent);
            }
    

    然后写一个当缓存被清除后被调用的函数:

    private void FillCache(object key, object value, EvictionReason reason, object state)
            {
                
            }
    

    这里边就不写东西了,主要是用来测试,当缓存被清除后,会不会走这里边

    打断点调试:

    第一次,没有缓存,进入判断里边:

    第二次,直接返回视图:

     

    等待30秒,再刷新页面,进入回调函数:

    具体内容:

    1:先判断缓存里是否有数据,有的话直接用,没有的话就去数据库读取:

    2:然后设置缓存时间

    3:当缓存被清除后进入回调函数

    关于In-Memory就简单学习到这里,如果以后需要可以具体看官方文档

    Cache Tag Helper

    既然是Helper,就是用在Razor View里边,基本格式如下:

    <cache>@await Component.InvokeAsync("xxx")</cache>
    

    当然,里边也可以添加一些属性,所以它也是在服务器端进行操作的,实际上它使用的还是内存里的缓存

    Tag Helper的属性比较多,这里介绍一些相对重要的,如下:

    enabled:         是否启用
    expires-on:      绝对过期时间
    expires-after:   时间长度
    expires-sliding: 可调式过期时间
    vary-by-header
    vary-by-query
    vary-by-route
    vary-by-cookie
    vary-by-user
    vary-by priority

    具体可以看文档

    代码示例

     在layout.cshtml里写入:

    <cache expires-after="@TimeSpan.FromSeconds(30)">
             @await Component.InvokeAsync("InternetStatus")
     </cache>
    

    这没啥功能,就是测试网络是否连接正常,如下:

    public async Task<IViewComponentResult> InvokeAsync()
            {
                var httpClient = new HttpClient();
    
                var response = await httpClient.GetAsync("https://www.baidu.com");
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    return View(true);
                }
    
                return View(false);
            }

    可以在layout里对加入哪一行代码打断点

    1:第一次走进来,没问题

    2:然后把电脑网络连接关闭,再刷新,还是没问题

    3:等30秒后,就抛出异常了,因为缓存没了

    分布式 缓存

    以上的例子,因为用的是单个服务器,所以只对那一个服务器起作用,但是我们在实际企业项目开发时候,可能要做个集群什么的

    比如,当用户发出请求后有多个web服务器,这个时候请求不一定请求的是那一台web服务器,所以这个时候我们就要把缓存数据提出来,单独放在一台缓存服务器上,来供其它web服务器来访问,如下:

    分布式缓存的一些特点:

    1:无需Sticky Session

    2:可扩展

    3:服务器重启不会影响缓存

    4:性能更好

    分布式缓存接口名和一些方法:

    1:IDistributedCache

    2:Get,GetAsnyc

    3:Set,SetAsync

    4:Refresh,RefreshAsync

    5:Remove,RemoveAsync

    方法的参数类型都是byte数组类型

    分布式缓存默认使用一下几种:

    1:分布式 Memory Cache       这个只在开发时候使用,不太分布式

    2:分布式 SQL server Cache   可以在生产环境使用

    3:分布式 Redis Chche        可以在生产环境使用(使用最多)

    代码示例

     1:使用docker拉去Redis,打开cmd,执行:

    docker pull redis
    
    docker run --name second-redis -d -p 6379:6379 redis
    
    docker run -it --link my-redis:my-redis --rm redis redis-cli -h my-redis -p 6379
    

    2:在项目startup.cs添加服务:

    services.AddDistributedRedisCache(options =>
                {
                    options.Configuration = "localhost";
                    options.InstanceName = "redis-for-home";
                });
    

    3:在需要使用Redis缓存的控制器中注入IDistributedCache:

    public readonly IRepository<Student> _repository;
            private readonly HostingEnvironment _hostingEnvironment;
            private readonly ILogger<HomeController> _logger;
            private readonly IMemoryCache _memoryCache;
            private readonly IDistributedCache _distributedCache;
    
            public HomeController(IRepository<Student> repository,
                HostingEnvironment hostingEnvironment,
                ILogger<HomeController> logger, 
                IDistributedCache distributedCache,
                IMemoryCache memoryCache)
            {
                _repository = repository;
                _hostingEnvironment = hostingEnvironment;
                _logger = logger;
                _memoryCache = memoryCache;
                _distributedCache = distributedCache;
            }
    

    4:在index方法里使用缓存:

    IEnumerable<Student> cachedStudent = null;
    
                var cachedStudentString = _distributedCache.Get(CacheEntryConstants.AlbumsOfToday);
    
                if (cachedStudentString == null)
                {
                    cachedStudent = _repository.GetAll();
                    var serializedString = JsonConvert.SerializeObject(cachedStudent);
                    byte[] encodedAlbums = Encoding.UTF8.GetBytes(serializedString);
    
                    var cacheEntryOptions = new MemoryCacheEntryOptions()
                        .SetSlidingExpiration(TimeSpan.FromSeconds(30));
                    _distributedCache.Set(CacheEntryConstants.AlbumsOfToday, encodedAlbums);
                }
                else
                {
                    byte[] encodedAlbums = _distributedCache.Get(CacheEntryConstants.AlbumsOfToday);
                    string serializedString = Encoding.UTF8.GetString(encodedAlbums);
                    cachedStudent = JsonConvert.DeserializeObject<List<Student>>(serializedString);
                }
    

    可以断定调试一下,第一次进入if条件语句里边,第二次就进入else里边,说明已经成功使用到了Redis缓存。

    目前缓存实在本地Redis上边,当然,也可以将Redis安装到其它服务器上边,就是所谓的分布式缓存。

    Response缓存

    一:理解、就是把响应缓存一下,如下:

      1:基于Header

      2:客户端缓存

      3:使用responseCache这个attribute

    二:参数、它有一下几个参数:

      1:Location、设置缓存地点

      2:Duration、设置缓存时间

      3:NoStore、 设置不应该缓存

      4:VaryByHeader  、设置到底检查Header的值来决定是否使用缓存

    代码示例

     1:在startup.cs里的services.AddMvc()里添加:

    options.CacheProfiles.Add("Default", new CacheProfile
    {
        Duration = 60
    });
     options.CacheProfiles.Add("Never", new CacheProfile
     {
        Location = ResponseCacheLocation.None,
        NoStore = true
     });
    

    2:在控制器中,就像属性路由或者过滤器一样,在需要缓存的数据的方法上边添加:

    [ResponseCache(CacheProfileName = "Default")]

    这样就会使用到在startup的Default缓存了,当然,也可以直接这样:

    [ResponseCache(Duration = 30, Location = ResponseCacheLocation.Client)]
    

    这样的话,就不需要在startup添加缓存服务了。但是需要注意的是,这种缓存,只能针对对网页的后退或者前进,如果刷新的话缓存就没了

     

  • 相关阅读:
    Android Studio安装apk失败
    react-native获取屏幕尺寸
    Project Euler Problem 10
    Project Euler Problem9
    Project Euler Problem8
    Project Euler Problem7
    Project Euler Problem6
    《The One 团队》:第九次团队作业:BETA冲刺与团队项目验收
    《The One!团队》:BETA Scrum metting3
    《The One !团队》:BETA Scrum metting2
  • 原文地址:https://www.cnblogs.com/dcy521/p/13574943.html
Copyright © 2020-2023  润新知