一、说明
作为WebApi接口,性能效率是必不可少的,每次的访问请求,数据库读取、业务逻辑处理都会或多或少的花费时间,特别是一些共用的公有数据,频繁访问且大量重复;针对这样的情况我们就可以考虑通过缓存放置到内存存储中,以空间换取时间的提升,可以提高应用程序的效率;关于缓存的方法有【Cache、Session、Cookie等】,还有功能比较强大的缓存方法,如:Redis等。
本文主要讲述MemoryCache、Session、Cookie这三种缓存方法。
二、缓存方法
2.0、建立一个独立的类库用来编写通用的工具方法
2.0.1、建立独立库的介绍
建立一个独立的类库编写通用的工具方法内容:优点是:
①一处编写多处复用;
②方便管理维护和更新;
③职责分明,实现工具与业务解耦;
2.1、建立一个独立类库的操作
2.1、Cache【MemoryCache】
2.1.1、Cache介绍
.Net Core中虽然没有现成的Cache方法;但微软官方提供了内存缓存(MemoryCache)的工具包。Cache的应用范围:
①Cache用于在Http请求期间保存页面或者数据。
②Cache的使用可以大大的提高整个应用程序的效率。
③它允许将频繁访问的服务器资源存储在内存中,当用户发出相同的请求后,服务器不是再次处理而是将Cache中保存的数据直接返回给用户。
④可以看出Cache节省的是时间—服务器处理时间。
⑤Cache实例是每一个应用程序专有的,其生命周期==该应用程序周期。
Cache:它存储于 服务器的内存中,允许您自定义如何缓存项以及将它们缓存多长时间。例如,当缺乏系统内存时,缓存会自动移除很少使用的或优先级较低的项以释放内存。该技术 也称为清理,这是缓存确保过期数据不使用宝贵的服务器资源的方式之一。它不与会话相关,所以它是多会话共享的,因此使用它可以提高网站性能,但是可能泄露 用户的安全信息,还由于在服务器缺乏内存时可能会自动移除Cache因此需要在每次获取数据时检测该Cache项是否还存在。
Cache的关键特性有:存储于服务器内存中,与会话无关,根据服务器内存资源的状况随时可能被丢弃,不被序列化,不发生服务器-客户端数据传输。
2.1.2、Cache实现
①安装【Microsoft.Extensions.Caching.Memory】的Nuget资源包
②编写CacheHelper类
/***
* Title:".NET Core WebApi" 项目
* 主题:内存缓存帮助类
* Description:
* 功能:
* 1、验证缓存项是否存在
* 2、添加缓存
* 3、删除缓存(删除指定缓存、批量删除缓存、删除所有缓存)
* 4、获取缓存(获取指定缓存、获取所有的缓存键、获取缓存集合)
* Date:2021
* Version:0.1版本
* Author:Coffee
* Modify Recoder:
*/
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace WebApiUtils
{
public class CacheHelper
{
#region 基础参数
//内存缓存
private static readonly MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
#endregion
/// <summary>
/// 验证缓存项是否存在
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns>返回结果(true:存在)</returns>
public static bool Exists(string key)
{
if (key == null)
throw new ArgumentNullException(nameof(key));
return _cache.TryGetValue(key, out _);
}
/// <summary>
/// 添加缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">缓存Value</param>
/// <returns>返回结果(true:存在)</returns>
public static bool Set(string key, object value)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
if (value == null)
throw new ArgumentNullException(nameof(value));
_cache.Set(key, value);
return Exists(key);
}
/// <summary>
/// 添加缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">缓存Value</param>
/// <param name="expiresIn">缓存时长</param>
/// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
/// <returns>返回结果(true:存在)</returns>
public static bool Set(string key, object value, TimeSpan expiresIn, bool isSliding = false)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
if (value == null)
throw new ArgumentNullException(nameof(value));
_cache.Set(key, value,
isSliding
? new MemoryCacheEntryOptions().SetSlidingExpiration(expiresIn)
: new MemoryCacheEntryOptions().SetAbsoluteExpiration(expiresIn));
return Exists(key);
}
#region 删除缓存
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
public static void Remove(string key)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
_cache.Remove(key);
}
/// <summary>
/// 删除匹配到的缓存
/// </summary>
/// <param name="key">缓存key</param>
/// <returns></returns>
public static void RemoveCacheRegex(string key)
{
IList<string> list = SearchCacheRegex(key);
foreach (var s in list)
{
Remove(s);
}
}
/// <summary>
/// 批量删除缓存
/// </summary>
/// <returns></returns>
public static void RemoveAll(IEnumerable<string> keys)
{
if (keys == null)
throw new ArgumentNullException(nameof(keys));
keys.ToList().ForEach(item => _cache.Remove(item));
}
/// <summary>
/// 删除所有缓存
/// </summary>
/// <returns></returns>
public static void RemoveCacheAll()
{
var tmp = GetCacheKeys();
foreach (var s in tmp)
{
Remove(s);
}
}
#endregion
#region 获取缓存
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns>返回对应类型</returns>
public static T Get<T>(string key) where T : class
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
return _cache.Get(key) as T;
}
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns>返回object</returns>
public static object Get(string key)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
return _cache.Get(key);
}
/// <summary>
/// 搜索匹配到的缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static IList<string> SearchCacheRegex(string key)
{
var cacheKeys = GetCacheKeys();
var tmp = cacheKeys.Where(k => Regex.IsMatch(k, key)).ToList();
return tmp.AsReadOnly();
}
/// <summary>
/// 获取所有缓存键
/// </summary>
/// <returns>返回所有的缓存键列表</returns>
public static List<string> GetCacheKeys()
{
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
var entries = _cache.GetType().GetField("_entries", flags).GetValue(_cache);
var cacheItems = entries as IDictionary;
var keys = new List<string>();
if (cacheItems == null) return keys;
foreach (DictionaryEntry cacheItem in cacheItems)
{
keys.Add(cacheItem.Key.ToString());
}
return keys;
}
/// <summary>
/// 获取缓存集合
/// </summary>
/// <param name="keys">缓存Key集合</param>
/// <returns>返回字典</returns>
public static IDictionary<string, object> GetAll(IEnumerable<string> keys)
{
if (keys == null)
throw new ArgumentNullException(nameof(keys));
var dict = new Dictionary<string, object>();
keys.ToList().ForEach(item => dict.Add(item, _cache.Get(item)));
return dict;
}
#endregion
}//Class_end
}
③在Controllers文件夹下新建一个Test文件夹提供做测试【编写CacheHelper测试类】
/***
* Title:".NET Core WebApi" 项目
* 主题:测试内存缓存
* Description:
* 功能:
* Date:2021
* Version:0.1版本
* Author:Coffee
* Modify Recoder:
*/
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApiUtils;
namespace WebApi_Learn.Controllers.Test
{
[Route("api/[controller]/[action]")]
[ApiController]
public class Test_MermoryCache
{
/// <summary>
/// 键是否存在
/// </summary>
/// <param name="key">键</param>
/// <returns>返回结果(true:表示成功)</returns>
[HttpGet]
public bool IsExistCache(string key)
{
return CacheHelper.Exists(key);
}
/// <summary>
/// 添加缓存没有时间周期
/// </summary>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <returns>返回结果(true:表示成功)</returns>
[HttpGet,Route("AddMemeryCache")]
public bool AddCacheNoTime(string key, string value)
{
return CacheHelper.Set(key,value);
}
/// <summary>
/// 添加缓存有时间周期
/// </summary>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <param name="secondNumber">缓存秒数</param>
/// <returns>返回结果(true:表示成功)</returns>
[HttpGet, Route("AddMemeryCache")]
public bool AddCacheHasTime(string key, string value, int secondNumber)
{
return CacheHelper.Set(key, value, new TimeSpan(0,0,secondNumber), false);
}
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key">键</param>
/// <returns></returns>
[HttpGet]
public void DeleteCache(string key)
{
CacheHelper.Remove(key);
}
/// <summary>
/// 删除所有缓存
/// </summary>
[HttpGet]
public void DeleteAllCache()
{
CacheHelper.RemoveCacheAll();
}
/// <summary>
/// 获取到缓存
/// </summary>
/// <param name="key">键</param>
/// <returns>返回结果(true:表示成功)</returns>
[HttpGet]
public string GetCache(string key)
{
try
{
return CacheHelper.Get(key).ToString();
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
/// <summary>
/// 获取到所有的缓存
/// </summary>
/// <returns></returns>
[HttpGet]
public List<string> GetAllCache()
{
return CacheHelper.GetCacheKeys();
}
}//Class_end
}
④运行验证
1、运行程序
2、选择添加有时间周期的缓存
3、过了一段时间后查看缓存是否存在
2.2、Session
2.2.1、Session介绍
Session的引用范围:
①Session用来保存每一个用户的专有信息。
②Session的生存期是用户持续请求时间加上一段时间(一般是20分钟左右)。
③Session信息是保存在Web服务器内存中的,保存数据量可大可小。
由于用户停止使用应用程序之后它仍在内存中存留一段时间,因此这种方法效率较低。
Session为当前用户会话提供信息。还提供对可用于存储信息的会话范围的缓存的访问,以及控制如何管理会话的方法。它存储在服务器的内存中,因此与在数据库中存储和检索信息相比,它的执行速度更快。与不特定于单个用户会话的应用程 序状态不同,会话状态应用于单个的用户和会话。因此,应用程序状态非常适合存储那些数量少、随用户的变化而变化的常用数据。而且由于其不发生服务器-客户 端数据传输,Session还适合存储关于用户的安全数据,如购物车信息。
Session的关键特性有:存储于服务器内存中,与会话相关,在会话的整个生存期中存在即不会被主动丢弃,不被序列化,不发生服务器-客户端数据传输。
2.2.2、Session实现
①安装【Microsoft.AspNetCore.Session】和【Microsoft.AspNetCore.Http.Extensions】的Nuget包
②编写SessionHelper类
1、注册Session
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
#region Session
//注册HttpContextAccessor对象,用以获取HttpContext信息
services.AddHttpContextAccessor();
//启用session之前必须先添加内存
services.AddDistributedMemoryCache();
//注册Session
services.AddSession(options =>
{
options.Cookie.Name = "WebApi_Learn.Session";//名称随便写(一般填写项目名称即可)
options.IdleTimeout = TimeSpan.FromSeconds(2000);//设置session的过期时间
options.Cookie.HttpOnly = true;//设置在浏览器不能通过js获得该cookie的值,实际场景根据自身需要
});
#endregion
}
2、使用Session
#region Session
//UseSession配置在UseMvc/UseEndpoints之前
app.UseSession();
#endregion
3、编写SessionHelper类
/***
* Title:".NET Core WebApi" 项目
* 主题:Session帮助类
* Description:
* 功能:
* 1、设置Session
* 2、获取Session
* 3、删除Session
* Date:2021
* Version:0.1版本
* Author:Coffee
* Modify Recoder:
*/
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Text;
namespace WebApiUtils
{
public class SessionHelper
{
/// <summary>
/// 设置Session
/// </summary>
/// <param name="httpContext">httpContext内容</param>
/// <param name="key">键</param>
/// <param name="value">值</param>
public static void SetSession(HttpContext httpContext, string key, string value)
{
httpContext.Session.SetString(key, value);
}
/// <summary>
/// 获取Session
/// </summary>
/// <param name="httpContext">httpContext内容</param>
/// <param name="key">键</param>
/// <param name="defaultValue">默认值</param>
/// <returns>返回对应的值</returns>
public static string GetSession(HttpContext httpContext, string key, string defaultValue = "")
{
string value = httpContext.Session.GetString(key);
if (string.IsNullOrEmpty(value))
{
value = defaultValue;
}
return value;
}
/// <summary>
/// 删除Session
/// </summary>
/// <param name="httpContext">httpContext内容</param>
/// <param name="key">键</param>
public static void DeleteSession(HttpContext httpContext, string key)
{
httpContext.Session.Remove(key);
}
}//Class_end
}
③在Controllers文件夹下新建一个Test文件夹提供做测试【编写SessionHelper测试类】
/***
* Title:".NET Core WebApi" 项目
* 主题:测试服务器缓存(Session)
* Description:
* 功能:XXX
* Date:2021
* Version:0.1版本
* Author:Coffee
* Modify Recoder:
*/
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApiUtils;
namespace WebApi_Learn.Controllers.Test
{
[Route("api/[controller]/[action]")]
[ApiController]
public class Test_Session
{
#region 基础参数
//HttpContext内容
private HttpContext _httpContext = ResponseHelper.HttpCurrent;
#endregion
/// <summary>
/// 设置Session
/// </summary>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <returns>返回当前设置的键值对</returns>
[HttpGet]
public ActionResult<IEnumerable<string>> SetSession(string key,string value)
{
SessionHelper.SetSession(_httpContext, key,value);
return new string[] { key, value };
}
/// <summary>
/// 根据键获取值
/// </summary>
/// <param name="key">键</param>
/// <returns>获取键对应的值</returns>
[HttpGet("key")]
public ActionResult<string> GetSession(string key)
{
string value = SessionHelper.GetSession(_httpContext, key,"当前数据不存在!!!");
return value;
}
/// <summary>
/// 删除Session
/// </summary>
/// <param name="key">键</param>
[HttpGet]
public void DeleteSession(string key)
{
SessionHelper.DeleteSession(_httpContext, key);
}
}//Class_end
}
④运行测试
1、运行程序
2、设置Session
3、查看缓存是否存在
2.3、Cookie
2.3.1、Cookie介绍
Cookie的应用范围:
①Cookie用来保存客户浏览器请求服务器页面的请求信息。
②我们可以存放非敏感的用户信息,保存时间可以根据需要设置。
③如果没有设置Cookie失效日期,它的生命周期保存到关闭浏览器为止。
④Cookie对象的Expires属性设置为MinValue表示永不过期。
⑤Cookie存储的数据量受限制,大多数的浏览器为4K因此不要存放大数据。
⑥由于并非所有的浏览器都支持Cookie,数据将以明文的形式保存在客户端。
Cookie:Cookie 提供了一种在 Web 应用程序中存储用户特定信息的方法。例如,当用户访问您的站点时,您可以使用 Cookie 存储用户首选项或其他信息。当该用户再次访问您的网站时,应用程序便可以检索以前存储的信息。在开发人员以编程方式设置Cookie时,需要将自己希望保 存的数据序列化为字符串(并且要注意,很多浏览器对Cookie有4096字节的限制)然后进行设置。
Cookie的关键特性有:存储于客户端硬盘上,与用户相关,在一定时间内持久化存储,可以跨浏览器共享数据,需要被序列化,发生服务器-客户端数据传输。
2.3.2、Cookie实现
①Cookie本身在.NET Core中已经支持,所以不需要引入啥NuGet包。
②编写CookieHelper类。
/***
* Title:".NET Core WebApi" 项目
* 主题:Cookie帮助类
* Description:
* 功能:
* 1、设置Cookie
* 2、删除Cookie
* 3、获取Cookie
* Date:2021
* Version:0.1版本
* Author:Coffee
* Modify Recoder:
*/
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Text;
namespace WebApiUtils
{
public class CookieHelper
{
/// <summary>
/// 设置Cookie
/// </summary>
/// <param name="httpContext">httpContext内容</param>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <param name="minutes">过期时长(单位:秒)</param>
public static void SetCookie(HttpContext httpContext, string key, string value, int seconds = 10)
{
httpContext.Response.Cookies.Append(key, value, new CookieOptions
{
Expires = DateTime.Now.AddSeconds(seconds)
});
}
/// <summary>
/// 获取Cookie
/// </summary>
/// <param name="httpContext">httpContext内容</param>
/// <param name="key">键</param>
/// <returns>返回键对应的值</returns>
public static string GetCookie(HttpContext httpContext, string key, string defaultValue = "")
{
string value = string.Empty;
httpContext.Request.Cookies.TryGetValue(key, out value);
if (string.IsNullOrEmpty(value))
{
value = defaultValue;
}
return value;
}
/// <summary>
/// 删除Cookie
/// </summary>
/// <param name="httpContext">httpContext内容</param>
/// <param name="key">键</param>
public static void DeleteCookie(HttpContext httpContext, string key)
{
httpContext.Response.Cookies.Delete(key);
}
}//Class_end
}
③在Controllers文件夹下新建一个Test文件夹提供做测试【编写CookieHelper测试类】
/***
* Title:".NET Core WebApi" 项目
* 主题:测试服务器缓存(Cookie)
* Description:
* 功能:XXX
* Date:2021
* Version:0.1版本
* Author:Coffee
* Modify Recoder:
*/
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApiUtils;
namespace WebApi_Learn.Controllers.Test
{
[Route("api/[controller]/[action]")]
[ApiController]
public class Test_Cookie
{
#region 基础参数
//HttpContext内容
private HttpContext _httpContext = ResponseHelper.HttpCurrent;
#endregion
/// <summary>
/// 设置Cookie
/// </summary>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <param name="timeIntervalSeconds">时间间隔(单位:秒)</param>
[HttpGet]
public void SetCookie(string key, string value,int timeIntervalSeconds)
{
CookieHelper.SetCookie(_httpContext,key,value, timeIntervalSeconds);
}
/// <summary>
/// 获取Cookie
/// </summary>
/// <param name="key">键</param>
/// <returns>返回键对应的值</returns>
[HttpGet]
public string GetCookie(string key)
{
return CookieHelper.GetCookie(_httpContext,key,$"当前:{key} 不存在");
}
/// <summary>
/// 删除Cookie
/// </summary>
/// <param name="key">键</param>
[HttpGet]
public void DeleteCookie(string key)
{
CookieHelper.DeleteCookie(_httpContext,key);
}
}//Class_end
}
④运行测试
1、运行程序
2、设置Cookie
3、过了一会查看Cookie是否存在
三、响应帮助类
3.1、编写响应帮助类
/***
* Title:".NET Core WebApi" 项目
* 主题:响应帮助类
* Description:
* 功能:
* 1、异常处理回调
* 2、统一请求页面实体
* Date:2021
* Version:0.1版本
* Author:Coffee
* Modify Recoder:
*/
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace WebApiUtils
{
public class ResponseHelper
{
#region 基础参数
//服务接口
public static IServiceProvider serviceProvider;
#endregion
/// <summary>
/// 异常处理回调
/// </summary>
/// <param name="statusCode">html状态码</param>
/// <param name="msg">消息</param>
/// <returns></returns>
public static Task HandleExceptionAsync(int statusCode, string msg)
{
var data = new { code = statusCode, msg = msg };
string text = JsonConvert.SerializeObject(data);
var response = HttpCurrent.Response;
if (string.IsNullOrEmpty(response.ContentType))
{
//跨域的时候注意,不带header没法接收回调
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Credentials", "true");
//因为这个是json
response.ContentType = "application/json;charset=utf-8";
response.StatusCode = 200;
response.ContentLength = text.Length;
return response.WriteAsync(text);
}
else
{
return response.WriteAsync(text);
}
}
/// <summary>
/// 统一请求页面实体
/// </summary>
public static HttpContext HttpCurrent
{
get
{
object factory = serviceProvider.GetService(typeof(IHttpContextAccessor));
HttpContext context = ((IHttpContextAccessor)factory).HttpContext;
return context;
}
}
}//Class_end
}
3.2、注册注册HttpContextAccessor对象
在Startup的ConfigureServices方法中注册HttpContextAccessor对象
//注册HttpContextAccessor对象,用以获取HttpContext信息
services.AddHttpContextAccessor();
3.3、使用程序服务
在Startup的Configure中使用程序服务
//使用服务
WebApiUtils.ResponseHelper.serviceProvider = app.ApplicationServices;
参考文章: