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吧

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

自从使用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吧

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

猜你喜欢

转载自www.cnblogs.com/LiChen19951127/p/10036890.html