mirror of
https://github.com/anjoy8/Blog.Core.git
synced 2024-09-20 23:48:27 +08:00
✨🎨 缓存的完善优化
1.统一封装基于微软分布式缓存接口IDistributedCache使用 2.IDistributedCache只适合普通的缓存使用,如果要使用redis队列、订阅redis消息等,就要使用redis原生库 3.增加缓存管理接口[Systems/CacheManageController] 4.目前支持内存、redis缓存实现,理论可随意扩展甚至自定义实现 5.默认使用内存缓存,可在appsetting.json中配置Redis 切换到IDistributedCache好处如下 默认session使用IDistributedCache进行存储,如果你搭配使用IDistributedCache+外部缓存(如Redis),可实现应用程序重启session不丢失 更直观就是,调试的时候登录swagger后即使重启调试也无需在登陆
This commit is contained in:
parent
3f24902521
commit
7629527ee9
|
@ -106,7 +106,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Controllers\Systems\" />
|
||||
<Folder Include="wwwroot\BlogCore.Data.excel\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -1299,6 +1299,41 @@
|
|||
<param name="id"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:Blog.Core.Api.Controllers.Systems.CacheManageController">
|
||||
<summary>
|
||||
缓存管理
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Api.Controllers.Systems.CacheManageController.Get">
|
||||
<summary>
|
||||
获取全部缓存
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Api.Controllers.Systems.CacheManageController.Get(System.String)">
|
||||
<summary>
|
||||
获取缓存
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Api.Controllers.Systems.CacheManageController.Post(System.String,System.String,System.Nullable{System.Int32})">
|
||||
<summary>
|
||||
新增
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Api.Controllers.Systems.CacheManageController.Delete">
|
||||
<summary>
|
||||
删除全部缓存
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Blog.Core.Api.Controllers.Systems.CacheManageController.Delete(System.String)">
|
||||
<summary>
|
||||
删除缓存
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:Blog.Core.Api.Controllers.Systems.DataBaseController">
|
||||
<summary>
|
||||
数据库管理
|
||||
|
|
81
Blog.Core.Api/Controllers/Systems/CacheManageController.cs
Normal file
81
Blog.Core.Api/Controllers/Systems/CacheManageController.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using Blog.Core.Common.Caches;
|
||||
using Blog.Core.Controllers;
|
||||
using Blog.Core.Model;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Blog.Core.Api.Controllers.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存管理
|
||||
/// </summary>
|
||||
[Route("api/Systems/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(Permissions.Name)]
|
||||
public class CacheManageController : BaseApiController
|
||||
{
|
||||
private readonly ICaching _caching;
|
||||
|
||||
public CacheManageController(ICaching caching)
|
||||
{
|
||||
_caching = caching;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取全部缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<MessageModel<List<string>>> Get()
|
||||
{
|
||||
return Success(await _caching.GetAllCacheKeysAsync());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{key}")]
|
||||
public async Task<MessageModel<string>> Get(string key)
|
||||
{
|
||||
return Success<string>(await _caching.GetStringAsync(key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<MessageModel> Post([FromQuery] string key, [FromQuery] string value, [FromQuery] int? expire)
|
||||
{
|
||||
if (expire.HasValue)
|
||||
await _caching.SetStringAsync(key, value, TimeSpan.FromMilliseconds(expire.Value));
|
||||
else
|
||||
await _caching.SetStringAsync(key, value);
|
||||
|
||||
return Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除全部缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
public async Task<MessageModel> Delete()
|
||||
{
|
||||
await _caching.RemoveAllAsync();
|
||||
return Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Route("{key}")]
|
||||
[HttpDelete]
|
||||
public async Task<MessageModel> Delete(string key)
|
||||
{
|
||||
await _caching.RemoveAsync(key);
|
||||
return Success();
|
||||
}
|
||||
}
|
|
@ -57,8 +57,7 @@ RoutePrefix.Name = AppSettings.app(new string[] { "AppSettings", "SvcName" }).Ob
|
|||
|
||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||
|
||||
builder.Services.AddMemoryCacheSetup();
|
||||
builder.Services.AddRedisCacheSetup();
|
||||
builder.Services.AddCacheSetup();
|
||||
builder.Services.AddSqlsugarSetup();
|
||||
builder.Services.AddDbSetup();
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ using Blog.Core.Common.LogHelper;
|
|||
using Blog.Core.Common.Seed;
|
||||
using Blog.Core.Extensions;
|
||||
using Blog.Core.Extensions.Middlewares;
|
||||
using Blog.Core.Extensions.ServiceExtensions;
|
||||
using Blog.Core.Filter;
|
||||
using Blog.Core.Hubs;
|
||||
using Blog.Core.IServices;
|
||||
|
@ -49,9 +50,7 @@ namespace Blog.Core
|
|||
// 确保从认证中心返回的ClaimType不被更改,不使用Map映射
|
||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
|
||||
|
||||
services.AddMemoryCacheSetup();
|
||||
services.AddRedisCacheSetup();
|
||||
|
||||
services.AddCacheSetup();
|
||||
services.AddSqlsugarSetup();
|
||||
services.AddDbSetup();
|
||||
services.AddAutoMapperSetup();
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
},
|
||||
"AllowedHosts": "*",
|
||||
"Redis": {
|
||||
"ConnectionString": "127.0.0.1:6319,password=admin"
|
||||
"Enable": true,
|
||||
"ConnectionString": "127.0.0.1:6379",
|
||||
"InstanceName": "" //前缀
|
||||
},
|
||||
"RabbitMQ": {
|
||||
"Enabled": false,
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<Folder Include="Core\" />
|
||||
<Folder Include="Const\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
328
Blog.Core.Common/Caches/Caching.cs
Normal file
328
Blog.Core.Common/Caches/Caching.cs
Normal file
|
@ -0,0 +1,328 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Blog.Core.Common.Const;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Blog.Core.Common.Caches;
|
||||
|
||||
public class Caching : ICaching
|
||||
{
|
||||
private readonly IDistributedCache _cache;
|
||||
|
||||
public Caching(IDistributedCache cache)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
private byte[] GetBytes<T>(T source)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(source));
|
||||
}
|
||||
|
||||
public IDistributedCache Cache => _cache;
|
||||
|
||||
public void AddCacheKey(string cacheKey)
|
||||
{
|
||||
var res = _cache.GetString(CacheConst.KeyAll);
|
||||
var allkeys = string.IsNullOrWhiteSpace(res) ? new List<string>() : JsonConvert.DeserializeObject<List<string>>(res);
|
||||
if (!allkeys.Any(m => m == cacheKey))
|
||||
{
|
||||
allkeys.Add(cacheKey);
|
||||
_cache.SetString(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加缓存Key
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public async Task AddCacheKeyAsync(string cacheKey)
|
||||
{
|
||||
var res = await _cache.GetStringAsync(CacheConst.KeyAll);
|
||||
var allkeys = string.IsNullOrWhiteSpace(res) ? new List<string>() : JsonConvert.DeserializeObject<List<string>>(res);
|
||||
if (!allkeys.Any(m => m == cacheKey))
|
||||
{
|
||||
allkeys.Add(cacheKey);
|
||||
await _cache.SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
|
||||
}
|
||||
}
|
||||
|
||||
public void DelByPattern(string key)
|
||||
{
|
||||
var allkeys = GetAllCacheKeys();
|
||||
if (allkeys == null) return;
|
||||
|
||||
var delAllkeys = allkeys.Where(u => u.Contains(key)).ToList();
|
||||
delAllkeys.ForEach(u => { _cache.Remove(u); });
|
||||
|
||||
// 更新所有缓存键
|
||||
allkeys = allkeys.Where(u => !u.Contains(key)).ToList();
|
||||
_cache.SetString(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除某特征关键字缓存
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DelByPatternAsync(string key)
|
||||
{
|
||||
var allkeys = await GetAllCacheKeysAsync();
|
||||
if (allkeys == null) return;
|
||||
|
||||
var delAllkeys = allkeys.Where(u => u.Contains(key)).ToList();
|
||||
delAllkeys.ForEach(u => { _cache.Remove(u); });
|
||||
|
||||
// 更新所有缓存键
|
||||
allkeys = allkeys.Where(u => !u.Contains(key)).ToList();
|
||||
await _cache.SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
|
||||
}
|
||||
|
||||
public void DelCacheKey(string cacheKey)
|
||||
{
|
||||
var res = _cache.GetString(CacheConst.KeyAll);
|
||||
var allkeys = string.IsNullOrWhiteSpace(res) ? new List<string>() : JsonConvert.DeserializeObject<List<string>>(res);
|
||||
if (allkeys.Any(m => m == cacheKey))
|
||||
{
|
||||
allkeys.Remove(cacheKey);
|
||||
_cache.SetString(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除缓存
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DelCacheKeyAsync(string cacheKey)
|
||||
{
|
||||
var res = await _cache.GetStringAsync(CacheConst.KeyAll);
|
||||
var allkeys = string.IsNullOrWhiteSpace(res) ? new List<string>() : JsonConvert.DeserializeObject<List<string>>(res);
|
||||
if (allkeys.Any(m => m == cacheKey))
|
||||
{
|
||||
allkeys.Remove(cacheKey);
|
||||
await _cache.SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
|
||||
}
|
||||
}
|
||||
|
||||
public bool Exists(string cacheKey)
|
||||
{
|
||||
var res = _cache.Get(cacheKey);
|
||||
return res != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查给定 key 是否存在
|
||||
/// </summary>
|
||||
/// <param name="cacheKey">键</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ExistsAsync(string cacheKey)
|
||||
{
|
||||
var res = await _cache.GetAsync(cacheKey);
|
||||
return res != null;
|
||||
}
|
||||
|
||||
public List<string> GetAllCacheKeys()
|
||||
{
|
||||
var res = _cache.GetString(CacheConst.KeyAll);
|
||||
return string.IsNullOrWhiteSpace(res) ? null : JsonConvert.DeserializeObject<List<string>>(res);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有缓存列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<string>> GetAllCacheKeysAsync()
|
||||
{
|
||||
var res = await _cache.GetStringAsync(CacheConst.KeyAll);
|
||||
return string.IsNullOrWhiteSpace(res) ? null : JsonConvert.DeserializeObject<List<string>>(res);
|
||||
}
|
||||
|
||||
public T Get<T>(string cacheKey)
|
||||
{
|
||||
var res = _cache.Get(cacheKey);
|
||||
return res == null ? default : JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(res));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<T> GetAsync<T>(string cacheKey)
|
||||
{
|
||||
var res = await _cache.GetAsync(cacheKey);
|
||||
return res == null ? default : JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(res));
|
||||
}
|
||||
|
||||
public string GetString(string cacheKey)
|
||||
{
|
||||
return _cache.GetString(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GetStringAsync(string cacheKey)
|
||||
{
|
||||
return await _cache.GetStringAsync(cacheKey);
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
{
|
||||
_cache.Remove(key);
|
||||
DelCacheKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public async Task RemoveAsync(string key)
|
||||
{
|
||||
await _cache.RemoveAsync(key);
|
||||
await DelCacheKeyAsync(key);
|
||||
}
|
||||
|
||||
public void RemoveAll()
|
||||
{
|
||||
var catches = GetAllCacheKeys();
|
||||
foreach (var @catch in catches) Remove(@catch);
|
||||
|
||||
catches.Clear();
|
||||
_cache.SetString(CacheConst.KeyAll, JsonConvert.SerializeObject(catches));
|
||||
}
|
||||
|
||||
public async Task RemoveAllAsync()
|
||||
{
|
||||
var catches = await GetAllCacheKeysAsync();
|
||||
foreach (var @catch in catches) await RemoveAsync(@catch);
|
||||
|
||||
catches.Clear();
|
||||
await _cache.SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(catches));
|
||||
}
|
||||
|
||||
|
||||
public void Set<T>(string cacheKey, T value, TimeSpan? expire = null)
|
||||
{
|
||||
_cache.Set(cacheKey, GetBytes(value), expire == null ? new DistributedCacheEntryOptions() {AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6)} : new DistributedCacheEntryOptions() {AbsoluteExpirationRelativeToNow = expire});
|
||||
|
||||
AddCacheKey(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加对象缓存
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public async Task SetAsync<T>(string cacheKey, T value)
|
||||
{
|
||||
await _cache.SetAsync(cacheKey, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), new DistributedCacheEntryOptions() {AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6)});
|
||||
|
||||
await AddCacheKeyAsync(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加对象缓存,并设置过期时间
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="expire"></param>
|
||||
/// <returns></returns>
|
||||
public async Task SetAsync<T>(string cacheKey, T value, TimeSpan expire)
|
||||
{
|
||||
await _cache.SetAsync(cacheKey, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)), new DistributedCacheEntryOptions() {AbsoluteExpirationRelativeToNow = expire});
|
||||
|
||||
await AddCacheKeyAsync(cacheKey);
|
||||
}
|
||||
|
||||
public void SetPermanent<T>(string cacheKey, T value)
|
||||
{
|
||||
_cache.Set(cacheKey, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)));
|
||||
AddCacheKey(cacheKey);
|
||||
}
|
||||
public async Task SetPermanentAsync<T>(string cacheKey, T value)
|
||||
{
|
||||
await _cache.SetAsync(cacheKey, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)));
|
||||
await AddCacheKeyAsync(cacheKey);
|
||||
}
|
||||
|
||||
public void SetString(string cacheKey, string value, TimeSpan? expire = null)
|
||||
{
|
||||
if (expire == null)
|
||||
_cache.SetString(cacheKey, value, new DistributedCacheEntryOptions() {AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6)});
|
||||
else
|
||||
_cache.SetString(cacheKey, value, new DistributedCacheEntryOptions() {AbsoluteExpirationRelativeToNow = expire});
|
||||
|
||||
AddCacheKey(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加字符串缓存
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public async Task SetStringAsync(string cacheKey, string value)
|
||||
{
|
||||
await _cache.SetStringAsync(cacheKey, value, new DistributedCacheEntryOptions() {AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6)});
|
||||
|
||||
await AddCacheKeyAsync(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加字符串缓存,并设置过期时间
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="expire"></param>
|
||||
/// <returns></returns>
|
||||
public async Task SetStringAsync(string cacheKey, string value, TimeSpan expire)
|
||||
{
|
||||
await _cache.SetStringAsync(cacheKey, value, new DistributedCacheEntryOptions() {AbsoluteExpirationRelativeToNow = expire});
|
||||
|
||||
await AddCacheKeyAsync(cacheKey);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 缓存最大角色数据范围
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="dataScopeType"></param>
|
||||
/// <returns></returns>
|
||||
public async Task SetMaxDataScopeType(long userId, int dataScopeType)
|
||||
{
|
||||
var cacheKey = CacheConst.KeyMaxDataScopeType + userId;
|
||||
await SetStringAsync(cacheKey, dataScopeType.ToString());
|
||||
|
||||
await AddCacheKeyAsync(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据父键清空
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DelByParentKeyAsync(string key)
|
||||
{
|
||||
var allkeys = await GetAllCacheKeysAsync();
|
||||
if (allkeys == null) return;
|
||||
|
||||
var delAllkeys = allkeys.Where(u => u.StartsWith(key)).ToList();
|
||||
delAllkeys.ForEach(Remove);
|
||||
// 更新所有缓存键
|
||||
allkeys = allkeys.Where(u => !u.StartsWith(key)).ToList();
|
||||
await SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
|
||||
}
|
||||
}
|
53
Blog.Core.Common/Caches/ICaching.cs
Normal file
53
Blog.Core.Common/Caches/ICaching.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
|
||||
namespace Blog.Core.Common.Caches;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存抽象接口,基于IDistributedCache封装
|
||||
/// </summary>
|
||||
public interface ICaching
|
||||
{
|
||||
public IDistributedCache Cache { get; }
|
||||
void AddCacheKey(string cacheKey);
|
||||
Task AddCacheKeyAsync(string cacheKey);
|
||||
|
||||
void DelByPattern(string key);
|
||||
Task DelByPatternAsync(string key);
|
||||
|
||||
void DelCacheKey(string cacheKey);
|
||||
Task DelCacheKeyAsync(string cacheKey);
|
||||
|
||||
bool Exists(string cacheKey);
|
||||
Task<bool> ExistsAsync(string cacheKey);
|
||||
|
||||
List<string> GetAllCacheKeys();
|
||||
Task<List<string>> GetAllCacheKeysAsync();
|
||||
|
||||
T Get<T>(string cacheKey);
|
||||
Task<T> GetAsync<T>(string cacheKey);
|
||||
|
||||
string GetString(string cacheKey);
|
||||
Task<string> GetStringAsync(string cacheKey);
|
||||
|
||||
void Remove(string key);
|
||||
Task RemoveAsync(string key);
|
||||
|
||||
void RemoveAll();
|
||||
Task RemoveAllAsync();
|
||||
|
||||
void Set<T>(string cacheKey, T value, TimeSpan? expire = null);
|
||||
Task SetAsync<T>(string cacheKey, T value);
|
||||
Task SetAsync<T>(string cacheKey, T value, TimeSpan expire);
|
||||
|
||||
void SetPermanent<T>(string cacheKey, T value);
|
||||
Task SetPermanentAsync<T>(string cacheKey, T value);
|
||||
|
||||
void SetString(string cacheKey, string value, TimeSpan? expire = null);
|
||||
Task SetStringAsync(string cacheKey, string value);
|
||||
Task SetStringAsync(string cacheKey, string value, TimeSpan expire);
|
||||
|
||||
Task DelByParentKeyAsync(string key);
|
||||
}
|
62
Blog.Core.Common/Caches/SqlSugarCacheService.cs
Normal file
62
Blog.Core.Common/Caches/SqlSugarCacheService.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Blog.Core.Common.Caches;
|
||||
|
||||
/// <summary>
|
||||
/// 实现SqlSugar的ICacheService接口
|
||||
/// </summary>
|
||||
public class SqlSugarCacheService : ICacheService
|
||||
{
|
||||
private readonly Lazy<ICaching> _caching = new(() => App.GetService<ICaching>(false));
|
||||
private ICaching Caching => _caching.Value;
|
||||
|
||||
public void Add<V>(string key, V value)
|
||||
{
|
||||
Caching.Set(key, value);
|
||||
}
|
||||
|
||||
public void Add<V>(string key, V value, int cacheDurationInSeconds)
|
||||
{
|
||||
Caching.Set(key, value, TimeSpan.FromSeconds(cacheDurationInSeconds));
|
||||
}
|
||||
|
||||
public bool ContainsKey<V>(string key)
|
||||
{
|
||||
return Caching.Exists(key);
|
||||
}
|
||||
|
||||
public V Get<V>(string key)
|
||||
{
|
||||
return Caching.Get<V>(key);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetAllKey<V>()
|
||||
{
|
||||
return Caching.GetAllCacheKeys();
|
||||
}
|
||||
|
||||
public V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = int.MaxValue)
|
||||
{
|
||||
if (!ContainsKey<V>(cacheKey))
|
||||
{
|
||||
var value = create();
|
||||
Caching.Set(cacheKey, value, TimeSpan.FromSeconds(cacheDurationInSeconds));
|
||||
return value;
|
||||
}
|
||||
|
||||
return Caching.Get<V>(cacheKey);
|
||||
}
|
||||
|
||||
public void Remove<V>(string key)
|
||||
{
|
||||
Caching.Remove(key);
|
||||
}
|
||||
|
||||
public bool RemoveAll()
|
||||
{
|
||||
Caching.RemoveAll();
|
||||
return true;
|
||||
}
|
||||
}
|
87
Blog.Core.Common/Const/CacheConst.cs
Normal file
87
Blog.Core.Common/Const/CacheConst.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
namespace Blog.Core.Common.Const;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存相关常量
|
||||
/// </summary>
|
||||
public class CacheConst
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户缓存
|
||||
/// </summary>
|
||||
public const string KeyUser = "user:";
|
||||
|
||||
/// <summary>
|
||||
/// 用户部门缓存
|
||||
/// </summary>
|
||||
public const string KeyUserDepart = "userDepart:";
|
||||
|
||||
/// <summary>
|
||||
/// 菜单缓存
|
||||
/// </summary>
|
||||
public const string KeyMenu = "menu:";
|
||||
|
||||
/// <summary>
|
||||
/// 菜单
|
||||
/// </summary>
|
||||
public const string KeyPermissions = "permissions";
|
||||
|
||||
/// <summary>
|
||||
/// 权限缓存
|
||||
/// </summary>
|
||||
public const string KeyPermission = "permission:";
|
||||
|
||||
/// <summary>
|
||||
/// 接口路由
|
||||
/// </summary>
|
||||
public const string KeyModules = "modules";
|
||||
|
||||
/// <summary>
|
||||
/// 系统配置
|
||||
/// </summary>
|
||||
public const string KeySystemConfig = "sysConfig";
|
||||
|
||||
/// <summary>
|
||||
/// 查询过滤器缓存
|
||||
/// </summary>
|
||||
public const string KeyQueryFilter = "queryFilter:";
|
||||
|
||||
/// <summary>
|
||||
/// 机构Id集合缓存
|
||||
/// </summary>
|
||||
public const string KeyOrgIdList = "org:";
|
||||
|
||||
/// <summary>
|
||||
/// 最大角色数据范围缓存
|
||||
/// </summary>
|
||||
public const string KeyMaxDataScopeType = "maxDataScopeType:";
|
||||
|
||||
/// <summary>
|
||||
/// 验证码缓存
|
||||
/// </summary>
|
||||
public const string KeyVerCode = "verCode:";
|
||||
|
||||
/// <summary>
|
||||
/// 所有缓存关键字集合
|
||||
/// </summary>
|
||||
public const string KeyAll = "keys";
|
||||
|
||||
/// <summary>
|
||||
/// 定时任务缓存
|
||||
/// </summary>
|
||||
public const string KeyTimer = "timer:";
|
||||
|
||||
/// <summary>
|
||||
/// 在线用户缓存
|
||||
/// </summary>
|
||||
public const string KeyOnlineUser = "onlineuser:";
|
||||
|
||||
/// <summary>
|
||||
/// 常量下拉框
|
||||
/// </summary>
|
||||
public const string KeyConstSelector = "selector:";
|
||||
|
||||
/// <summary>
|
||||
/// swagger登录缓存
|
||||
/// </summary>
|
||||
public const string SwaggerLogin = "swaggerLogin:";
|
||||
}
|
|
@ -3,7 +3,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Blog.Core.Common.DB
|
||||
{
|
||||
|
|
|
@ -4,211 +4,213 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Blog.Core.Common.Caches;
|
||||
|
||||
namespace Blog.Core.Common.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Linq扩展
|
||||
/// </summary>
|
||||
public static class ExpressionExtensions
|
||||
{
|
||||
#region HttpContext
|
||||
/// <summary>
|
||||
/// Linq扩展
|
||||
/// </summary>
|
||||
public static class ExpressionExtensions
|
||||
{
|
||||
#region HttpContext
|
||||
|
||||
/// <summary>
|
||||
/// 返回请求上下文
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="ContentType"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task Cof_SendResponse(this HttpContext context, System.Net.HttpStatusCode code, string message, string ContentType = "text/html;charset=utf-8")
|
||||
{
|
||||
context.Response.StatusCode = (int)code;
|
||||
context.Response.ContentType = ContentType;
|
||||
await context.Response.WriteAsync(message);
|
||||
}
|
||||
/// <summary>
|
||||
/// 返回请求上下文
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="ContentType"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task Cof_SendResponse(this HttpContext context, System.Net.HttpStatusCode code, string message,
|
||||
string ContentType = "text/html;charset=utf-8")
|
||||
{
|
||||
context.Response.StatusCode = (int) code;
|
||||
context.Response.ContentType = ContentType;
|
||||
await context.Response.WriteAsync(message);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region ICaching
|
||||
#region ICaching
|
||||
|
||||
/// <summary>
|
||||
/// 从缓存里取数据,如果不存在则执行查询方法,
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="cache">ICaching </param>
|
||||
/// <param name="key">键值</param>
|
||||
/// <param name="GetFun">查询方法</param>
|
||||
/// <param name="timeSpanMin">有效期 单位分钟/param>
|
||||
/// <returns></returns>
|
||||
public static T Cof_GetICaching<T>(this ICaching cache, string key, Func<T> GetFun, int timeSpanMin) where T : class
|
||||
{
|
||||
var obj = cache.Get(key);
|
||||
obj = GetFun();
|
||||
if (obj == null)
|
||||
{
|
||||
obj = GetFun();
|
||||
cache.Set(key, obj, timeSpanMin);
|
||||
}
|
||||
/// <summary>
|
||||
/// 从缓存里取数据,如果不存在则执行查询方法,
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="cache">ICaching </param>
|
||||
/// <param name="key">键值</param>
|
||||
/// <param name="GetFun">查询方法</param>
|
||||
/// <param name="timeSpanMin">有效期 单位分钟/param>
|
||||
/// <returns></returns>
|
||||
public static T Cof_GetICaching<T>(this ICaching cache, string key, Func<T> GetFun, int timeSpanMin) where T : class
|
||||
{
|
||||
var obj = cache.Get<T>(key);
|
||||
if (obj == null)
|
||||
{
|
||||
obj = GetFun();
|
||||
cache.Set(key, obj, TimeSpan.FromMinutes(timeSpanMin));
|
||||
}
|
||||
|
||||
return obj as T;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步从缓存里取数据,如果不存在则执行查询方法
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="cache">ICaching </param>
|
||||
/// <param name="key">键值</param>
|
||||
/// <param name="GetFun">查询方法</param>
|
||||
/// <param name="timeSpanMin">有效期 单位分钟/param>
|
||||
/// <returns></returns>
|
||||
public static async Task<T> Cof_AsyncGetICaching<T>(this ICaching cache, string key, Func<Task<T>> GetFun, int timeSpanMin) where T : class
|
||||
{
|
||||
var obj = cache.Get(key);
|
||||
if (obj == null)
|
||||
{
|
||||
obj = await GetFun();
|
||||
cache.Set(key, obj, timeSpanMin);
|
||||
}
|
||||
/// <summary>
|
||||
/// 异步从缓存里取数据,如果不存在则执行查询方法
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="cache">ICaching </param>
|
||||
/// <param name="key">键值</param>
|
||||
/// <param name="GetFun">查询方法</param>
|
||||
/// <param name="timeSpanMin">有效期 单位分钟/param>
|
||||
/// <returns></returns>
|
||||
public static async Task<T> Cof_AsyncGetICaching<T>(this ICaching cache, string key, Func<Task<T>> GetFun, int timeSpanMin) where T : class
|
||||
{
|
||||
var obj = await cache.GetAsync<T>(key);
|
||||
if (obj == null)
|
||||
{
|
||||
obj = await GetFun();
|
||||
cache.Set(key, obj, TimeSpan.FromMinutes(timeSpanMin));
|
||||
}
|
||||
|
||||
return obj as T;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region 常用扩展方法
|
||||
#region 常用扩展方法
|
||||
|
||||
public static bool Cof_CheckAvailable<TSource>(this IEnumerable<TSource> Tlist)
|
||||
{
|
||||
return Tlist != null && Tlist.Count() > 0;
|
||||
}
|
||||
public static bool Cof_CheckAvailable<TSource>(this IEnumerable<TSource> Tlist)
|
||||
{
|
||||
return Tlist != null && Tlist.Count() > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用内部方法
|
||||
/// </summary>
|
||||
public static Expression Call(this Expression instance, string methodName, params Expression[] arguments)
|
||||
{
|
||||
if (instance.Type == typeof(string))
|
||||
return Expression.Call(instance, instance.Type.GetMethod(methodName, new Type[] { typeof(string) }), arguments); //修复string contains 出现的问题 Ambiguous match found.
|
||||
else
|
||||
return Expression.Call(instance, instance.Type.GetMethod(methodName), arguments);
|
||||
}
|
||||
/// <summary>
|
||||
/// 调用内部方法
|
||||
/// </summary>
|
||||
public static Expression Call(this Expression instance, string methodName, params Expression[] arguments)
|
||||
{
|
||||
if (instance.Type == typeof(string))
|
||||
return Expression.Call(instance, instance.Type.GetMethod(methodName, new Type[] {typeof(string)}),
|
||||
arguments); //修复string contains 出现的问题 Ambiguous match found.
|
||||
else
|
||||
return Expression.Call(instance, instance.Type.GetMethod(methodName), arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内部成员
|
||||
/// </summary>
|
||||
public static Expression Property(this Expression expression, string propertyName)
|
||||
{
|
||||
// Todo:左边条件如果是dynamic,
|
||||
// 则Expression.Property无法获取子内容
|
||||
// 报错在这里,由于expression内的对象为Object,所以无法解析到
|
||||
// var x = (expression as IQueryable).ElementType;
|
||||
var exp = Expression.Property(expression, propertyName);
|
||||
if (exp.Type.IsGenericType && exp.Type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
return Expression.Convert(exp, exp.Type.GetGenericArguments()[0]);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取内部成员
|
||||
/// </summary>
|
||||
public static Expression Property(this Expression expression, string propertyName)
|
||||
{
|
||||
// Todo:左边条件如果是dynamic,
|
||||
// 则Expression.Property无法获取子内容
|
||||
// 报错在这里,由于expression内的对象为Object,所以无法解析到
|
||||
// var x = (expression as IQueryable).ElementType;
|
||||
var exp = Expression.Property(expression, propertyName);
|
||||
if (exp.Type.IsGenericType && exp.Type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
return Expression.Convert(exp, exp.Type.GetGenericArguments()[0]);
|
||||
}
|
||||
|
||||
return exp;
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转Lambda
|
||||
/// </summary>
|
||||
public static Expression<TDelegate> ToLambda<TDelegate>(this Expression body,
|
||||
params ParameterExpression[] parameters)
|
||||
{
|
||||
return Expression.Lambda<TDelegate>(body, parameters);
|
||||
}
|
||||
/// <summary>
|
||||
/// 转Lambda
|
||||
/// </summary>
|
||||
public static Expression<TDelegate> ToLambda<TDelegate>(this Expression body,
|
||||
params ParameterExpression[] parameters)
|
||||
{
|
||||
return Expression.Lambda<TDelegate>(body, parameters);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region 常用运算符 [ > , >= , == , < , <= , != , || , && ]
|
||||
#region 常用运算符 [ > , >= , == , < , <= , != , || , && ]
|
||||
|
||||
/// <summary>
|
||||
/// &&
|
||||
/// </summary>
|
||||
public static Expression AndAlso(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.AndAlso(left, right);
|
||||
}
|
||||
/// <summary>
|
||||
/// &&
|
||||
/// </summary>
|
||||
public static Expression AndAlso(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.AndAlso(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ||
|
||||
/// </summary>
|
||||
public static Expression OrElse(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.OrElse(left, right);
|
||||
}
|
||||
/// <summary>
|
||||
/// ||
|
||||
/// </summary>
|
||||
public static Expression OrElse(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.OrElse(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains
|
||||
/// </summary>
|
||||
public static Expression Contains(this Expression left, Expression right)
|
||||
{
|
||||
return left.Call("Contains", right);
|
||||
}
|
||||
/// <summary>
|
||||
/// Contains
|
||||
/// </summary>
|
||||
public static Expression Contains(this Expression left, Expression right)
|
||||
{
|
||||
return left.Call("Contains", right);
|
||||
}
|
||||
|
||||
public static Expression StartContains(this Expression left, Expression right)
|
||||
{
|
||||
return left.Call("StartsWith", right);
|
||||
}
|
||||
public static Expression StartContains(this Expression left, Expression right)
|
||||
{
|
||||
return left.Call("StartsWith", right);
|
||||
}
|
||||
|
||||
public static Expression EndContains(this Expression left, Expression right)
|
||||
{
|
||||
return left.Call("EndsWith", right);
|
||||
}
|
||||
public static Expression EndContains(this Expression left, Expression right)
|
||||
{
|
||||
return left.Call("EndsWith", right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// >
|
||||
/// </summary>
|
||||
public static Expression GreaterThan(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.GreaterThan(left, right);
|
||||
}
|
||||
/// <summary>
|
||||
/// >
|
||||
/// </summary>
|
||||
public static Expression GreaterThan(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.GreaterThan(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// >=
|
||||
/// </summary>
|
||||
public static Expression GreaterThanOrEqual(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.GreaterThanOrEqual(left, right);
|
||||
}
|
||||
/// <summary>
|
||||
/// >=
|
||||
/// </summary>
|
||||
public static Expression GreaterThanOrEqual(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.GreaterThanOrEqual(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <
|
||||
/// </summary>
|
||||
public static Expression LessThan(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.LessThan(left, right);
|
||||
}
|
||||
/// <summary>
|
||||
/// <
|
||||
/// </summary>
|
||||
public static Expression LessThan(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.LessThan(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <=
|
||||
/// </summary>
|
||||
public static Expression LessThanOrEqual(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.LessThanOrEqual(left, right);
|
||||
}
|
||||
/// <summary>
|
||||
/// <=
|
||||
/// </summary>
|
||||
public static Expression LessThanOrEqual(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.LessThanOrEqual(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ==
|
||||
/// </summary>
|
||||
public static Expression Equal(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.Equal(left, right);
|
||||
}
|
||||
/// <summary>
|
||||
/// ==
|
||||
/// </summary>
|
||||
public static Expression Equal(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.Equal(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// !=
|
||||
/// </summary>
|
||||
public static Expression NotEqual(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.NotEqual(left, right);
|
||||
}
|
||||
/// <summary>
|
||||
/// !=
|
||||
/// </summary>
|
||||
public static Expression NotEqual(this Expression left, Expression right)
|
||||
{
|
||||
return Expression.NotEqual(left, right);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
namespace Blog.Core.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// 简单的缓存接口,只有查询和添加,以后会进行扩展
|
||||
/// </summary>
|
||||
public interface ICaching
|
||||
{
|
||||
object Get(string cacheKey);
|
||||
|
||||
void Set(string cacheKey, object cacheValue, int timeSpan);
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
|
||||
namespace Blog.Core.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// 实例化缓存接口ICaching
|
||||
/// </summary>
|
||||
public class MemoryCaching : ICaching
|
||||
{
|
||||
//引用Microsoft.Extensions.Caching.Memory;这个和.net 还是不一样,没有了Httpruntime了
|
||||
private readonly IMemoryCache _cache;
|
||||
//还是通过构造函数的方法,获取
|
||||
public MemoryCaching(IMemoryCache cache)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
public object Get(string cacheKey)
|
||||
{
|
||||
return _cache.Get(cacheKey);
|
||||
}
|
||||
|
||||
public void Set(string cacheKey, object cacheValue,int timeSpan)
|
||||
{
|
||||
_cache.Set(cacheKey, cacheValue, TimeSpan.FromSeconds(timeSpan * 60));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
24
Blog.Core.Common/Option/RedisOptions.cs
Normal file
24
Blog.Core.Common/Option/RedisOptions.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using Blog.Core.Common.Option.Core;
|
||||
|
||||
namespace Blog.Core.Common.Option;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存配置选项
|
||||
/// </summary>
|
||||
public sealed class RedisOptions : IConfigurableOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool Enable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Redis连接
|
||||
/// </summary>
|
||||
public string ConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 键值前缀
|
||||
/// </summary>
|
||||
public string InstanceName { get; set; }
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
using Blog.Core.Common;
|
||||
using System;
|
||||
using Blog.Core.Common;
|
||||
using Castle.DynamicProxy;
|
||||
using System.Linq;
|
||||
using Blog.Core.Common.Caches;
|
||||
|
||||
namespace Blog.Core.AOP
|
||||
{
|
||||
|
@ -28,7 +30,7 @@ namespace Blog.Core.AOP
|
|||
//获取自定义缓存键
|
||||
var cacheKey = CustomCacheKey(invocation);
|
||||
//根据key获取相应的缓存值
|
||||
var cacheValue = _cache.Get(cacheKey);
|
||||
var cacheValue = _cache.Get<object>(cacheKey);
|
||||
if (cacheValue != null)
|
||||
{
|
||||
//将当前获取到的缓存值,赋值给当前执行方法
|
||||
|
@ -40,7 +42,7 @@ namespace Blog.Core.AOP
|
|||
//存入缓存
|
||||
if (!string.IsNullOrWhiteSpace(cacheKey))
|
||||
{
|
||||
_cache.Set(cacheKey, invocation.ReturnValue, qCachingAttribute.AbsoluteExpiration);
|
||||
_cache.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromMinutes(qCachingAttribute.AbsoluteExpiration));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Blog.Core.Extensions
|
|||
/// <summary>
|
||||
/// Redis缓存接口
|
||||
/// </summary>
|
||||
[Obsolete("普通缓存考虑直接使用ICaching,如果要使用Redis队列等还是使用此类")]
|
||||
public interface IRedisBasketRepository
|
||||
{
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Blog.Core.Extensions
|
||||
{
|
||||
[Obsolete("普通缓存考虑直接使用ICaching,如果要使用Redis队列等还是使用此类")]
|
||||
public class RedisBasketRepository : IRedisBasketRepository
|
||||
{
|
||||
private readonly ILogger<RedisBasketRepository> _logger;
|
||||
|
|
45
Blog.Core.Extensions/ServiceExtensions/CacheSetup.cs
Normal file
45
Blog.Core.Extensions/ServiceExtensions/CacheSetup.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using Blog.Core.Common;
|
||||
using Blog.Core.Common.Caches;
|
||||
using Blog.Core.Common.Option;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Blog.Core.Extensions.ServiceExtensions;
|
||||
|
||||
public static class CacheSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// 统一注册缓存
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddCacheSetup(this IServiceCollection services)
|
||||
{
|
||||
var cacheOptions = App.GetOptions<RedisOptions>();
|
||||
if (cacheOptions.Enable)
|
||||
{
|
||||
//使用Redis
|
||||
services.AddStackExchangeRedisCache(options =>
|
||||
{
|
||||
options.Configuration = cacheOptions.ConnectionString;
|
||||
if (!cacheOptions.InstanceName.IsNullOrEmpty()) options.InstanceName = cacheOptions.InstanceName;
|
||||
});
|
||||
|
||||
services.AddTransient<IRedisBasketRepository, RedisBasketRepository>();
|
||||
// 配置启动Redis服务,虽然可能影响项目启动速度,但是不能在运行的时候报错,所以是合理的
|
||||
services.AddSingleton<ConnectionMultiplexer>(sp =>
|
||||
{
|
||||
//获取连接字符串
|
||||
var configuration = ConfigurationOptions.Parse(cacheOptions.ConnectionString, true);
|
||||
configuration.ResolveDns = true;
|
||||
return ConnectionMultiplexer.Connect(configuration);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
//使用内存
|
||||
services.AddDistributedMemoryCache();
|
||||
}
|
||||
|
||||
services.AddSingleton<ICaching, Caching>();
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
using Microsoft.Extensions.Caching.Memory;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Blog.Core.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 实现SqlSugar的ICacheService接口
|
||||
/// </summary>
|
||||
public class SqlSugarMemoryCacheService : ICacheService
|
||||
{
|
||||
protected IMemoryCache _memoryCache;
|
||||
public SqlSugarMemoryCacheService(IMemoryCache memoryCache)
|
||||
{
|
||||
_memoryCache = memoryCache;
|
||||
}
|
||||
public void Add<V>(string key, V value)
|
||||
{
|
||||
_memoryCache.Set(key, value);
|
||||
}
|
||||
public void Add<V>(string key, V value, int cacheDurationInSeconds)
|
||||
{
|
||||
_memoryCache.Set(key, value, DateTimeOffset.Now.AddSeconds(cacheDurationInSeconds));
|
||||
}
|
||||
public bool ContainsKey<V>(string key)
|
||||
{
|
||||
return _memoryCache.TryGetValue(key, out _);
|
||||
}
|
||||
|
||||
public V Get<V>(string key)
|
||||
{
|
||||
return _memoryCache.Get<V>(key);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetAllKey<V>()
|
||||
{
|
||||
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
|
||||
var entries = _memoryCache.GetType().GetField("_entries", flags).GetValue(_memoryCache);
|
||||
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;
|
||||
}
|
||||
|
||||
public V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = int.MaxValue)
|
||||
{
|
||||
if (!_memoryCache.TryGetValue<V>(cacheKey, out V value))
|
||||
{
|
||||
value = create();
|
||||
_memoryCache.Set(cacheKey, value, DateTime.Now.AddSeconds(cacheDurationInSeconds));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public void Remove<V>(string key)
|
||||
{
|
||||
_memoryCache.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
using Blog.Core.Common;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
|
||||
namespace Blog.Core.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Memory缓存 启动服务
|
||||
/// </summary>
|
||||
public static class MemoryCacheSetup
|
||||
{
|
||||
public static void AddMemoryCacheSetup(this IServiceCollection services)
|
||||
{
|
||||
if (services == null) throw new ArgumentNullException(nameof(services));
|
||||
|
||||
services.AddScoped<ICaching, MemoryCaching>();
|
||||
services.AddSingleton<IMemoryCache>(factory =>
|
||||
{
|
||||
var value = factory.GetRequiredService<IOptions<MemoryCacheOptions>>();
|
||||
var cache = new MemoryCache(value);
|
||||
return cache;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
using Blog.Core.Common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
|
||||
namespace Blog.Core.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Redis缓存 启动服务
|
||||
/// </summary>
|
||||
public static class RedisCacheSetup
|
||||
{
|
||||
public static void AddRedisCacheSetup(this IServiceCollection services)
|
||||
{
|
||||
if (services == null) throw new ArgumentNullException(nameof(services));
|
||||
|
||||
services.AddTransient<IRedisBasketRepository, RedisBasketRepository>();
|
||||
|
||||
// 配置启动Redis服务,虽然可能影响项目启动速度,但是不能在运行的时候报错,所以是合理的
|
||||
services.AddSingleton<ConnectionMultiplexer>(sp =>
|
||||
{
|
||||
//获取连接字符串
|
||||
string redisConfiguration = AppSettings.app(new string[] { "Redis", "ConnectionString" });
|
||||
|
||||
var configuration = ConfigurationOptions.Parse(redisConfiguration, true);
|
||||
|
||||
configuration.ResolveDns = true;
|
||||
|
||||
return ConnectionMultiplexer.Connect(configuration);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ using StackExchange.Profiling;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Blog.Core.Common.Caches;
|
||||
|
||||
namespace Blog.Core.Extensions
|
||||
{
|
||||
|
@ -57,6 +58,7 @@ namespace Blog.Core.Extensions
|
|||
// 自定义特性
|
||||
ConfigureExternalServices = new ConfigureExternalServices()
|
||||
{
|
||||
DataInfoCacheService = new SqlSugarCacheService(),
|
||||
EntityService = (property, column) =>
|
||||
{
|
||||
if (column.IsPrimarykey && property.PropertyType == typeof(int))
|
||||
|
@ -83,19 +85,11 @@ namespace Blog.Core.Extensions
|
|||
{
|
||||
throw new ApplicationException("未配置Log库连接");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// SqlSugarScope是线程安全,可使用单例注入
|
||||
// 参考:https://www.donet5.com/Home/Doc?typeId=1181
|
||||
services.AddSingleton<ISqlSugarClient>(o =>
|
||||
{
|
||||
var memoryCache = o.GetRequiredService<IMemoryCache>();
|
||||
|
||||
foreach (var config in BaseDBConfig.AllConfigs)
|
||||
{
|
||||
config.ConfigureExternalServices.DataInfoCacheService = new SqlSugarMemoryCacheService(memoryCache);
|
||||
}
|
||||
|
||||
return new SqlSugarScope(BaseDBConfig.AllConfigs, db =>
|
||||
{
|
||||
BaseDBConfig.ValidConfig.ForEach(config =>
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Text.RegularExpressions;
|
|||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Blog.Core.Common;
|
||||
using Blog.Core.Common.Caches;
|
||||
using Blog.Core.Common.Helper;
|
||||
using Nacos.V2;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
|
@ -8,64 +8,66 @@ namespace Blog.Core.Serilog.Utility;
|
|||
|
||||
public class SerilogRequestUtility
|
||||
{
|
||||
public const string HttpMessageTemplate =
|
||||
"HTTP {RequestMethod} {RequestPath} QueryString:{QueryString} Body:{Body} responded {StatusCode} in {Elapsed:0.0000} ms";
|
||||
public const string HttpMessageTemplate =
|
||||
"HTTP {RequestMethod} {RequestPath} QueryString:{QueryString} Body:{Body} responded {StatusCode} in {Elapsed:0.0000} ms";
|
||||
|
||||
private static readonly List<string> _ignoreUrl = new()
|
||||
{
|
||||
"/job",
|
||||
};
|
||||
private static readonly List<string> _ignoreUrl = new()
|
||||
{
|
||||
"/job",
|
||||
};
|
||||
|
||||
private static LogEventLevel DefaultGetLevel(HttpContext ctx,
|
||||
double _,
|
||||
Exception? ex)
|
||||
{
|
||||
return ex is null && ctx.Response.StatusCode <= 499 ? LogEventLevel.Information : LogEventLevel.Error;
|
||||
}
|
||||
private static LogEventLevel DefaultGetLevel(HttpContext ctx,
|
||||
double _,
|
||||
Exception? ex)
|
||||
{
|
||||
return ex is null && ctx.Response.StatusCode <= 499 ? LogEventLevel.Information : LogEventLevel.Error;
|
||||
}
|
||||
|
||||
public static LogEventLevel GetRequestLevel(HttpContext ctx, double _, Exception? ex) =>
|
||||
ex is null && ctx.Response.StatusCode <= 499 ? IgnoreRequest(ctx) : LogEventLevel.Error;
|
||||
public static LogEventLevel GetRequestLevel(HttpContext ctx, double _, Exception? ex) =>
|
||||
ex is null && ctx.Response.StatusCode <= 499 ? IgnoreRequest(ctx) : LogEventLevel.Error;
|
||||
|
||||
private static LogEventLevel IgnoreRequest(HttpContext ctx)
|
||||
{
|
||||
var path = ctx.Request.Path.Value;
|
||||
if (path.IsNullOrEmpty())
|
||||
{
|
||||
return LogEventLevel.Information;
|
||||
}
|
||||
private static LogEventLevel IgnoreRequest(HttpContext ctx)
|
||||
{
|
||||
var path = ctx.Request.Path.Value;
|
||||
if (path.IsNullOrEmpty())
|
||||
{
|
||||
return LogEventLevel.Information;
|
||||
}
|
||||
|
||||
return _ignoreUrl.Any(s => path.StartsWith(s)) ? LogEventLevel.Verbose : LogEventLevel.Information;
|
||||
}
|
||||
return _ignoreUrl.Any(s => path.StartsWith(s)) ? LogEventLevel.Verbose : LogEventLevel.Information;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Request中增加附属属性
|
||||
/// </summary>
|
||||
/// <param name="diagnosticContext"></param>
|
||||
/// <param name="httpContext"></param>
|
||||
public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext)
|
||||
{
|
||||
var request = httpContext.Request;
|
||||
/// <summary>
|
||||
/// 从Request中增加附属属性
|
||||
/// </summary>
|
||||
/// <param name="diagnosticContext"></param>
|
||||
/// <param name="httpContext"></param>
|
||||
public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext)
|
||||
{
|
||||
var request = httpContext.Request;
|
||||
|
||||
diagnosticContext.Set("RequestHost", request.Host);
|
||||
diagnosticContext.Set("RequestScheme", request.Scheme);
|
||||
diagnosticContext.Set("Protocol", request.Protocol);
|
||||
diagnosticContext.Set("RequestIp", httpContext.GetRequestIp());
|
||||
diagnosticContext.Set("RequestHost", request.Host);
|
||||
diagnosticContext.Set("RequestScheme", request.Scheme);
|
||||
diagnosticContext.Set("Protocol", request.Protocol);
|
||||
diagnosticContext.Set("RequestIp", httpContext.GetRequestIp());
|
||||
|
||||
if (request.Method == HttpMethods.Get)
|
||||
{
|
||||
diagnosticContext.Set("QueryString", request.QueryString.HasValue ? request.QueryString.Value : string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
diagnosticContext.Set("QueryString", request.QueryString.HasValue ? request.QueryString.Value : string.Empty);
|
||||
diagnosticContext.Set("Body", request.ContentLength > 0 ? request.GetRequestBody() : string.Empty);
|
||||
}
|
||||
diagnosticContext.Set("ContentType", httpContext.Response.ContentType);
|
||||
if (request.Method == HttpMethods.Get)
|
||||
{
|
||||
diagnosticContext.Set("QueryString", request.QueryString.HasValue ? request.QueryString.Value : string.Empty);
|
||||
diagnosticContext.Set("Body", string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
diagnosticContext.Set("QueryString", request.QueryString.HasValue ? request.QueryString.Value : string.Empty);
|
||||
diagnosticContext.Set("Body", request.ContentLength > 0 ? request.GetRequestBody() : string.Empty);
|
||||
}
|
||||
|
||||
var endpoint = httpContext.GetEndpoint();
|
||||
if (endpoint != null)
|
||||
{
|
||||
diagnosticContext.Set("EndpointName", endpoint.DisplayName);
|
||||
}
|
||||
}
|
||||
diagnosticContext.Set("ContentType", httpContext.Response.ContentType);
|
||||
|
||||
var endpoint = httpContext.GetEndpoint();
|
||||
if (endpoint != null)
|
||||
{
|
||||
diagnosticContext.Set("EndpointName", endpoint.DisplayName);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user