• Asp.net Core2.0 缓存 MemoryCache 和 Redis


     

     

    自从使用Asp.net Core2.0 以来,不停摸索,查阅资料,这方面的资料是真的少,因此,在前人的基础上,摸索出了Asp.net Core2.0 缓存 MemoryCache 和 Redis的用法,并实现了简单的封装

    那么,先给出几个参考资料吧

    关于两种缓存:https://www.cnblogs.com/yuangang/p/5800113.html

    关于redis持久化:https://blog.csdn.net/u010785685/article/details/52366977

    两个nuget包,不用多说

    接下来,贴出代码

    首先在startup,我读取了appstting.json的数据,作为redis的配置

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Application.Common;
    using Application.Common.CommonObject;
    using Application.CoreWork;
    using Application.DAL;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace Application.web
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                Connection.MySqlConnection = Configuration.GetConnectionString("MySqlConnection");
                Connection.SqlConnection = Configuration.GetConnectionString("SqlConnection");
                RedisConfig.Connection = Configuration.GetSection("RedisConfig")["Connection"];
                RedisConfig.DefaultDatabase =Convert.ToInt32( Configuration.GetSection("RedisConfig")["DefaultDatabase"]);
                RedisConfig.InstanceName = Configuration.GetSection("RedisConfig")["InstanceName"];
                CommonManager.CacheObj.GetMessage<RedisCacheHelper>();
                services.AddMvc();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseBrowserLink();
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                app.UseStaticFiles();
    
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
        }
    }
    复制代码

    再贴上配置

    1
    2
    3
    4
    5
    "RedisConfig": {
            "Connection""127.0.0.1:6379",
            "DefaultDatabase": 0,
            "InstanceName""Redis1"
        },

      

    用来放配置信息的静态类

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Application.Common
    {
        public static class RedisConfig
        {
            public static string configname { get; set; }
            public static string Connection { get; set; }
            public static int DefaultDatabase { get; set; }
            public static string InstanceName { get; set; }
        }
    }
    复制代码

    然后ICacheHelper.cs,这个类是两种缓存通用的接口,让使用更方便

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Text;
    
    namespace Application.Common.CommonObject
    {
        public interface ICacheHelper
        {
            bool Exists(string key);
    
    
            T GetCache<T>(string key) where T : class;
    
    
            void SetCache(string key, object value);
    
    
            void SetCache(string key, object value, DateTimeOffset expiressAbsoulte);//设置绝对时间过期
    
    
            void SetSlidingCache(string key, object value, TimeSpan t);  //设置滑动过期, 因redis暂未找到自带的滑动过期类的API,暂无需实现该接口
    
    
            void RemoveCache(string key);
    
            void KeyMigrate(string key, EndPoint endPoint,int database,int timeountseconds);
    
            void Dispose();
    
            void GetMssages();
    
            void Publish(string msg);
        }
    }
    复制代码

    然后,实现接口,首先是MemoryCacheHelper

    复制代码
    using Microsoft.Extensions.Caching.Memory;
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Text;
    
    namespace Application.Common.CommonObject
    {
        public class MemoryCacheHelper : ICacheHelper
        {
            //public MemoryCacheHelper(/*MemoryCacheOptions options*/)//这里可以做成依赖注入,但没打算做成通用类库,所以直接把选项直接封在帮助类里边
            //{
            //    //this._cache = new MemoryCache(options);
            //    //this._cache = new MemoryCache(new MemoryCacheOptions());
            //}
            //public MemoryCacheHelper(MemoryCacheOptions options)//这里可以做成依赖注入,但没打算做成通用类库,所以直接把选项直接封在帮助类里边
            //{
            //    this._cache = new MemoryCache(options);
            //}
    
            public static IMemoryCache _cache=new MemoryCache(new MemoryCacheOptions());
    
            /// <summary>
            /// 是否存在此缓存
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public bool Exists(string key)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                object v = null;
                return _cache.TryGetValue<object>(key, out v);
            }
            /// <summary>
            /// 取得缓存数据
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="key"></param>
            /// <returns></returns>
            public T GetCache<T>(string key) where T : class
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
    
    
                T v = null;
                _cache.TryGetValue<T>(key, out v);
    
    
                return v;
            }
            /// <summary>
            /// 设置缓存
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public void SetCache(string key, object value)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                if (value == null)
                    throw new ArgumentNullException(nameof(value));
    
    
                object v = null;
                if (_cache.TryGetValue(key, out v))
                    _cache.Remove(key);
                _cache.Set<object>(key, value);
            }
            /// <summary>
            /// 设置缓存,绝对过期
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="expirationMinute">间隔分钟</param>
            /// CommonManager.CacheObj.Save<RedisCacheHelper>("test", "RedisCache works!", 30);
            public void SetCache(string key, object value, double expirationMinute)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                if (value == null)
                    throw new ArgumentNullException(nameof(value));
    
                object v = null;
                if (_cache.TryGetValue(key, out v))
                    _cache.Remove(key);
                DateTime now = DateTime.Now;
                TimeSpan ts = now.AddMinutes(expirationMinute) - DateTime.Now;
                _cache.Set<object>(key, value, ts);
            }
            /// <summary>
            /// 设置缓存,绝对过期
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="expirationTime">DateTimeOffset 结束时间</param>
            /// CommonManager.CacheObj.Save<RedisCacheHelper>("test", "RedisCache works!", DateTimeOffset.Now.AddSeconds(30));
            public void SetCache(string key, object value, DateTimeOffset expirationTime)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                if (value == null)
                    throw new ArgumentNullException(nameof(value));
    
                object v = null;
                if (_cache.TryGetValue(key, out v))
                    _cache.Remove(key);
    
                _cache.Set<object>(key, value, expirationTime);
            }
            /// <summary>
            /// 设置缓存,相对过期时间
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="t"></param>
            /// CommonManager.CacheObj.SaveSlidingCache<MemoryCacheHelper>("test", "MemoryCache works!",TimeSpan.FromSeconds(30));
            public void SetSlidingCache(string key,object value,TimeSpan t)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                if (value == null)
                    throw new ArgumentNullException(nameof(value));
    
                object v = null;
                if (_cache.TryGetValue(key, out v))
                    _cache.Remove(key);
    
                _cache.Set(key, value, new MemoryCacheEntryOptions()
                {
                    SlidingExpiration=t
                });
            }
            /// <summary>
            /// 移除缓存
            /// </summary>
            /// <param name="key"></param>
            public void RemoveCache(string key)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
    
                _cache.Remove(key);
            }
    
            /// <summary>
            /// 释放
            /// </summary>
            public void Dispose()
            {
                if (_cache != null)
                    _cache.Dispose();
                GC.SuppressFinalize(this);
            }
    
            public void KeyMigrate(string key, EndPoint endPoint, int database, int timeountseconds)
            {
                throw new NotImplementedException();
            }
    
            public void GetMssages()
            {
                throw new NotImplementedException();
            }
    
            public void Publish(string msg)
            {
                throw new NotImplementedException();
            }
        }
    }
    复制代码

    然后是RedisCacheHelper

    复制代码
    using Microsoft.Extensions.Caching.Redis;
    using Newtonsoft.Json;
    using StackExchange.Redis;
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Text;
    
    namespace Application.Common.CommonObject
    {
        public class RedisCacheHelper : ICacheHelper
        {
            public RedisCacheHelper(/*RedisCacheOptions options, int database = 0*/)//这里可以做成依赖注入,但没打算做成通用类库,所以直接把连接信息直接写在帮助类里
            {
                options = new RedisCacheOptions();
                options.Configuration = "127.0.0.1:6379";//RedisConfig.Connection;
                options.InstanceName = RedisConfig.InstanceName;
                int database = RedisConfig.DefaultDatabase;
                _connection = ConnectionMultiplexer.Connect(options.Configuration);
                _cache = _connection.GetDatabase(database);
                _instanceName = options.InstanceName;
                _sub = _connection.GetSubscriber();
            }
    
            public static RedisCacheOptions options;
            public static IDatabase _cache;
    
            public static ConnectionMultiplexer _connection;
    
            public static string _instanceName;
    
            public static ISubscriber _sub;
    
            /// <summary>
            /// 取得redis的Key名称
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            private string GetKeyForRedis(string key)
            {
                return _instanceName + key;
            }
            /// <summary>
            /// 判断当前Key是否存在数据
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public bool Exists(string key)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                return _cache.KeyExists(GetKeyForRedis(key));
            }
    
            /// <summary>
            /// 取得缓存数据
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="key"></param>
            /// <returns></returns>
            public T GetCache<T>(string key) where T : class
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                var value = _cache.StringGet(GetKeyForRedis(key));
                if (!value.HasValue)
                    return default(T);
                return JsonConvert.DeserializeObject<T>(value);
            }
            /// <summary>
            /// 设置缓存数据
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public void SetCache(string key, object value)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                if (value == null)
                    throw new ArgumentNullException(nameof(value));
    
                if (Exists(GetKeyForRedis(key)))
                    RemoveCache(GetKeyForRedis(key));
    
                _cache.StringSet(GetKeyForRedis(key), JsonConvert.SerializeObject(value));
            }
            /// <summary>
            /// 设置绝对过期时间
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="expiressAbsoulte"></param>
            public void SetCache(string key, object value, DateTimeOffset expiressAbsoulte)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                if (value == null)
                    throw new ArgumentNullException(nameof(value));
    
                if (Exists(GetKeyForRedis(key)))
                    RemoveCache(GetKeyForRedis(key));
                TimeSpan t = expiressAbsoulte - DateTimeOffset.Now;
                _cache.StringSet(GetKeyForRedis(key), JsonConvert.SerializeObject(value), t);
            }
            /// <summary>
            /// 设置相对过期时间
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="expirationMinute"></param>
            public void SetCache(string key, object value, double expirationMinute)
            {
                if (Exists(GetKeyForRedis(key)))
                    RemoveCache(GetKeyForRedis(key));
    
                DateTime now = DateTime.Now;
                TimeSpan ts = now.AddMinutes(expirationMinute) - now;
                _cache.StringSet(GetKeyForRedis(key), JsonConvert.SerializeObject(value), ts);
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="key"></param>
            /// <param name="endPoint"></param>
            /// <param name="database"></param>
            /// <param name="timeountseconds"></param>
            public void KeyMigrate(string key, EndPoint endPoint, int database, int timeountseconds) {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
                _cache.KeyMigrate(GetKeyForRedis(key), endPoint, database, timeountseconds);
            }
            /// <summary>
            /// 移除redis
            /// </summary>
            /// <param name="key"></param>
            public void RemoveCache(string key)
            {
                if (string.IsNullOrWhiteSpace(key))
                    throw new ArgumentNullException(nameof(key));
    
                _cache.KeyDelete(GetKeyForRedis(key));
            }
    
            /// <summary>
            /// 销毁连接
            /// </summary>
            public void Dispose()
            {
                if (_connection != null)
                    _connection.Dispose();
                GC.SuppressFinalize(this);
            }
    
            public void SetSlidingCache(string key, object value, TimeSpan t)
            {
                throw new NotImplementedException();
            }
    
            public void GetMssages()
            {
                using (_connection = ConnectionMultiplexer.Connect(options.Configuration))
                    _sub.Subscribe("msg", (channel, message) =>
                    {
                        string result = message;
                    });
            }
    
            public void Publish(string msg)
            {
                using (_connection=ConnectionMultiplexer.Connect(options.Configuration))
                    _sub.Publish("msg", msg);
            }
        }
    }
    复制代码

    然后是Cache.cs,用来实例化,此处用单例模式,保证项目使用的是一个缓存实例,博主吃过亏,由于redis实例过多,构造函数运行太多次,导致client连接数过大,内存不够跑,速度卡慢

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Application.Common.CommonObject
    {
        public sealed class Cache
        {
            internal Cache() { }
            public static ICacheHelper cache;
            /// <summary>
            /// 判断缓存是否存在
            /// </summary>
            /// <typeparam name="CacheType">缓存类型</typeparam>
            /// <param name="key">键名</param>
            /// <returns></returns>
            public bool Exists<CacheType>(string key) where CacheType : ICacheHelper, new()
            {
                if (cache!=null&& typeof(CacheType).Equals(cache.GetType()))
                    return cache.Exists(key);
                else
                {
                    cache = new CacheType();
                    return cache.Exists(key);
                }
            }
    
            /// <summary>
            /// 获取缓存
            /// </summary>
            /// <typeparam name="T">转换的类</typeparam>
            /// <typeparam name="CacheType">缓存类型</typeparam>
            /// <param name="key">键名</param>
            /// <returns>转换为T类型的值</returns>
            public T GetCache<T,CacheType>(string key)
                where T:class
                where CacheType : ICacheHelper, new()
            {
                if (cache != null && typeof(CacheType).Equals(cache.GetType()))
                    return cache.GetCache<T>(key);
                else
                {
                    cache = new CacheType();
                    return cache.GetCache<T>(key);
                }
            }
    
            /// <summary>
            /// 保存缓存
            /// </summary>
            /// <typeparam name="CacheType">缓存类型</typeparam>
            /// <param name="key">键名</param>
            /// <param name="value">值</param>
            public void Save<CacheType>(string key,object value) where CacheType : ICacheHelper, new()
            {
                if (cache != null && typeof(CacheType).Equals(cache.GetType()))
                    cache.SetCache(key, value);
                else
                {
                    cache = new CacheType();
                    cache.SetCache(key, value);
                }
            }
    
            /// <summary>
            /// 保存缓存并设置绝对过期时间
            /// </summary>
            /// <typeparam name="CacheType">缓存类型</typeparam>
            /// <param name="key">键名</param>
            /// <param name="value">值</param>
            /// <param name="expiressAbsoulte">绝对过期时间</param>
            public void Save<CacheType>(string key, object value, DateTimeOffset expiressAbsoulte) where CacheType : ICacheHelper, new()
            {
                if (cache != null && typeof(CacheType).Equals(cache.GetType()))
                    cache.SetCache(key, value, expiressAbsoulte);
                else
                {
                    cache = new CacheType();
                    cache.SetCache(key, value, expiressAbsoulte);
                }
            }
    
            /// <summary>
            /// 保存滑动缓存
            /// </summary>
            /// <typeparam name="CacheType">只能用memorycache,redis暂不实现</typeparam>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="t">间隔时间</param>
            public void SaveSlidingCache<CacheType>(string key, object value,TimeSpan t) where CacheType : MemoryCacheHelper, new()
            {
                if (cache != null && typeof(CacheType).Equals(cache.GetType()))
                    cache.SetSlidingCache(key, value, t);
                else
                {
                    cache = new CacheType();
                    cache.SetSlidingCache(key, value, t);
                }
            }
    
            /// <summary>
            /// 删除一个缓存
            /// </summary>
            /// <typeparam name="CacheType">缓存类型</typeparam>
            /// <param name="key">要删除的key</param>
            public void Delete<CacheType>(string key)where CacheType : ICacheHelper, new()
            {
                if (cache != null && typeof(CacheType).Equals(cache.GetType()))
                    cache.RemoveCache(key);
                else
                {
                    cache = new CacheType();
                    cache.RemoveCache(key);
                }
            }
    
            /// <summary>
            /// 释放
            /// </summary>
            /// <typeparam name="CacheType"></typeparam>
            public void Dispose<CacheType>() where CacheType : ICacheHelper, new()
            {
                if (cache != null && typeof(CacheType).Equals(cache.GetType()))
                    cache.Dispose();
                else
                {
                    cache = new CacheType();
                    cache.Dispose();
                }
            }
    
            public void GetMessage<CacheType>() where CacheType:RedisCacheHelper,new()
            {
                if (cache != null && typeof(CacheType).Equals(cache.GetType()))
                    cache.GetMssages();
                else
                {
                    cache = new CacheType();
                    cache.GetMssages();
                }
            }
    
            public void Publish<CacheType>(string msg)where CacheType : RedisCacheHelper, new()
            {
                if (cache != null && typeof(CacheType).Equals(cache.GetType()))
                    cache.Publish(msg);
                else
                {
                    cache = new CacheType();
                    cache.Publish(msg);
                }
            }
        }
    }
    复制代码

    接下来,CommonManager.cs,该类主要是为了作为一个静态类调用缓存,由于Cache.cs并非静态类,方便调用

    复制代码
    using Application.Common.CommonObject;
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace Application.Common
    {
        public class CommonManager
        {
            private static readonly object lockobj = new object();
            private static volatile Cache _cache = null;
            /// <summary>
            /// Cache
            /// </summary>
            public static Cache CacheObj
            {
                get
                {
                    if (_cache == null)
                    {
                        lock (lockobj)
                        {
                            if (_cache == null)
                                _cache = new Cache();
                        }
                    }
                    return _cache;
                }
            }
        }
    }
    复制代码

    最后呢就是使用啦随便建的一个控制器

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;
    using Application.Common;
    using Application.Common.CommonObject;
    using Application.CoreWork;
    using Microsoft.AspNetCore.Mvc;
    
    namespace Application.web.Controllers
    {
        public class DefaultController : BaseController
        {
            public IActionResult Index()
            {
                for (int i = 0; i < 100000; i++)
                {
                    CommonManager.CacheObj.Save<RedisCacheHelper>("key" + i, "key" + i + " works!");
                }
                return View();
            }
    
            public IActionResult GetStrin(int index)
            {
                string res = "已经过期了";
                if (CommonManager.CacheObj.Exists<RedisCacheHelper>("key" + index))
                {
                    res = CommonManager.CacheObj.GetCache<String, RedisCacheHelper>("key" + index);
                }
                return Json(new ExtJson { success = true, code = 1000, msg = "成功", jsonresult = res });
            }
    
            public IActionResult Publish(string msg)
            {
                try
                {
                    CommonManager.CacheObj.Publish<RedisCacheHelper>(msg);
                    return Json(new ExtJson { success = true, code = 1000, msg = "成功", jsonresult = msg });
                }
                catch
                {
                    return Json(new ExtJson
                    {
                        success = true,
                        code = 1000,
                        msg = "失败",
                        jsonresult = msg
                    });
                }
            }
        }
    }
    复制代码

    那么,有的朋友在json处可能会报错,自己封装下,或者用原来的json吧

    如果有不懂的地方,可以在评论中提问,有更好的改进方式,也请联系我,共同进步,感谢阅读

  • 相关阅读:
    java提高篇(四)-----抽象类与接口
    hdu1004----用java链表实现
    jkfladsdjfkldsa
    Handler_1
    Handler实现线程间的通信2
    Handler实现线程间的通信1
    Handler基本运行机制
    Android线程
    Activity声明周期2
    Activity声明周期1
  • 原文地址:https://www.cnblogs.com/LiChen19951127/p/10036890.html
Copyright © 2020-2023  润新知