日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

基于 abp vNext 和 .NET Core 开发博客项目 - 使用Redis缓存数据

發布時間:2025/1/21 asp.net 73 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于 abp vNext 和 .NET Core 开发博客项目 - 使用Redis缓存数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

基于 abp vNext 和 .NET Core 開發博客項目 - 使用Redis緩存數據
轉載于:https://github.com/Meowv/Blog
在日志記錄中使用的靜態方法有人指出寫法不是很優雅,遂優化一下上一篇中日志記錄的方法,具體操作如下:

在.ToolKits層中新建擴展方法Log4NetExtensions.cs。

//Log4NetExtensions.cs
using log4net;
using log4net.Config;
using Microsoft.Extensions.Hosting;
using System.IO;
using System.Reflection;

namespace Meowv.Blog.ToolKits.Extensions
{
public static class Log4NetExtensions
{
public static IHostBuilder UseLog4Net(this IHostBuilder hostBuilder)
{
var log4netRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
XmlConfigurator.Configure(log4netRepository, new FileInfo(“log4net.config”));

return hostBuilder;} }

}
配置log4net,然后我們直接返回IHostBuilder對象,便于在Main方法中鏈式調用。

//Program.cs
using Meowv.Blog.ToolKits.Extensions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using System.Threading.Tasks;

namespace Meowv.Blog.HttpApi.Hosting
{
public class Program
{
public static async Task Main(string[] args)
{
await Host.CreateDefaultBuilder(args)
.UseLog4Net()
.ConfigureWebHostDefaults(builder =>
{
builder.UseIISIntegration()
.UseStartup();
}).UseAutofac().Build().RunAsync();
}
}
}
然后修改MeowvBlogExceptionFilter過濾器,代碼如下:

//MeowvBlogExceptionFilter.cs
using log4net;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Meowv.Blog.HttpApi.Hosting.Filters
{
public class MeowvBlogExceptionFilter : IExceptionFilter
{
private readonly ILog _log;

public MeowvBlogExceptionFilter(){_log = LogManager.GetLogger(typeof(MeowvBlogExceptionFilter));}/// <summary>/// 異常處理/// </summary>/// <param name="context"></param>/// <returns></returns>public void OnException(ExceptionContext context){// 錯誤日志記錄_log.Error($"{context.HttpContext.Request.Path}|{context.Exception.Message}", context.Exception);} }

}
可以刪掉之前添加的LoggerHelper.cs類,運行一下,同樣可以達到預期效果。

本篇將集成Redis,使用Redis來緩存數據,使用方法參考的微軟官方文檔:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed

關于Redis的介紹這里就不多說了,這里有一篇快速入門的文章:Redis快速入門及使用,對于不了解的同學可以看看。

直入主題,先在appsettings.json配置Redis的連接字符串。

//appsettings.json

“Caching”: {
“RedisConnectionString”: “127.0.0.1:6379,password=123456,ConnectTimeout=15000,SyncTimeout=5000”
}

對應的,在AppSettings.cs中讀取。

//AppSettings.cs

///
/// Caching
///
public static class Caching
{
///
/// RedisConnectionString
///
public static string RedisConnectionString => _config[“Caching:RedisConnectionString”];
}

在.Application.Caching層添加包Microsoft.Extensions.Caching.StackExchangeRedis,然后在模塊類MeowvBlogApplicationCachingModule中添加配置緩存實現。

//MeowvBlogApplicationCachingModule.cs
using Meowv.Blog.Domain;
using Meowv.Blog.Domain.Configurations;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;

namespace Meowv.Blog.Application.Caching
{
[DependsOn(
typeof(AbpCachingModule),
typeof(MeowvBlogDomainModule)
)]
public class MeowvBlogApplicationCachingModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = AppSettings.Caching.RedisConnectionString;
//options.InstanceName
//options.ConfigurationOptions
});
}
}
}
options.Configuration是 Redis 的連接字符串。

options.InstanceNam是 Redis 實例名稱,這里沒填。

options.ConfigurationOptions是 Redis 的配置屬性,如果配置了這個字,將優先于 Configuration 中的配置,同時它支持更多的選項。我這里也沒填。

緊接著我們就可以直接使用了,直接將IDistributedCache接口依賴關系注入即可。

圖片

可以看到默認已經實現了這么多常用的接口,已經夠我這個小項目用的了,同時在Microsoft.Extensions.Caching.Distributed.DistributedCacheExtensions中微軟還給我們提供了很多擴展方法。

于是,我們我就想到寫一個新的擴展方法,可以同時處理獲取和添加緩存的操作,當緩存存在時,直接返回,不存在時,添加緩存。

新建MeowvBlogApplicationCachingExtensions.cs擴展方法,如下:

//MeowvBlogApplicationCachingExtensions.cs
using Meowv.Blog.ToolKits.Extensions;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Caching
{
public static class MeowvBlogApplicationCachingExtensions
{
///
/// 獲取或添加緩存
///
///
///
///
///
///
///
public static async Task GetOrAddAsync(this IDistributedCache cache, string key, Func<Task> factory, int minutes)
{
TCacheItem cacheItem;

var result = await cache.GetStringAsync(key);if (string.IsNullOrEmpty(result)){cacheItem = await factory.Invoke();var options = new DistributedCacheEntryOptions();if (minutes != CacheStrategy.NEVER){options.AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes);}await cache.SetStringAsync(key, cacheItem.ToJson(), options);}else{cacheItem = result.FromJson<TCacheItem>();}return cacheItem;} }

}
我們可以在DistributedCacheEntryOptions中可以配置我們的緩存過期時間,其中有一個判斷條件,就是當minutes = -1的時候,不指定過期時間,那么我們的緩存就不會過期了。

GetStringAsync()、SetStringAsync()是DistributedCacheExtensions的擴展方法,最終會將緩存項cacheItem轉換成JSON格式進行存儲。

CacheStrategy是在.Domain.Shared層定義的緩存過期時間策略常量。

//MeowvBlogConsts.cs

///
/// 緩存過期時間策略
///
public static class CacheStrategy
{
///
/// 一天過期24小時
///

public const int ONE_DAY = 1440;/// <summary>/// 12小時過期/// </summary>public const int HALF_DAY = 720;/// <summary>/// 8小時過期/// </summary>public const int EIGHT_HOURS = 480;/// <summary>/// 5小時過期/// </summary>public const int FIVE_HOURS = 300;/// <summary>/// 3小時過期/// </summary>public const int THREE_HOURS = 180;/// <summary>/// 2小時過期/// </summary>public const int TWO_HOURS = 120;/// <summary>/// 1小時過期/// </summary>public const int ONE_HOURS = 60;/// <summary>/// 半小時過期/// </summary>public const int HALF_HOURS = 30;/// <summary>/// 5分鐘過期/// </summary>public const int FIVE_MINUTES = 5;/// <summary>/// 1分鐘過期/// </summary>public const int ONE_MINUTE = 1;/// <summary>/// 永不過期/// </summary>public const int NEVER = -1;}


接下來去創建緩存接口類和實現類,然后再我們的引用服務層.Application中進行調用,拿上一篇中接入GitHub的幾個接口來做新增緩存操作。

和.Application層格式一樣,在.Application.Caching中新建Authorize文件夾,添加緩存接口IAuthorizeCacheService和實現類AuthorizeCacheService。

注意命名規范,實現類肯定要繼承一個公共的CachingServiceBase基類。在.Application.Caching層根目錄添加MeowvBlogApplicationCachingServiceBase.cs,繼承ITransientDependency。

//MeowvBlogApplicationCachingServiceBase.cs
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.DependencyInjection;

namespace Meowv.Blog.Application.Caching
{
public class CachingServiceBase : ITransientDependency
{
public IDistributedCache Cache { get; set; }
}
}
然后使用屬性注入的方式,注入IDistributedCache。這樣我們只要繼承了基類:CachingServiceBase,就可以愉快的使用緩存了。

添加要緩存的接口到IAuthorizeCacheService,在這里我們使用Func()方法,我們的接口返回什么類型由Func()來決定,于是添加三個接口如下:

//IAuthorizeCacheService.cs
using Meowv.Blog.ToolKits.Base;
using System;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Caching.Authorize
{
public interface IAuthorizeCacheService
{
///
/// 獲取登錄地址(GitHub)
///
///
Task<ServiceResult> GetLoginAddressAsync(Func<Task<ServiceResult>> factory);

/// <summary>/// 獲取AccessToken/// </summary>/// <param name="code"></param>/// <param name="factory"></param>/// <returns></returns>Task<ServiceResult<string>> GetAccessTokenAsync(string code, Func<Task<ServiceResult<string>>> factory);/// <summary>/// 登錄成功,生成Token/// </summary>/// <param name="access_token"></param>/// <param name="factory"></param>/// <returns></returns>Task<ServiceResult<string>> GenerateTokenAsync(string access_token, Func<Task<ServiceResult<string>>> factory); }

}
是不是和IAuthorizeService代碼很像,的確,我就是直接復制過來改的。

在AuthorizeCacheService中實現接口。

//AuthorizeCacheService.cs
using Meowv.Blog.ToolKits.Base;
using Meowv.Blog.ToolKits.Extensions;
using System;
using System.Threading.Tasks;
using static Meowv.Blog.Domain.Shared.MeowvBlogConsts;

namespace Meowv.Blog.Application.Caching.Authorize.Impl
{
public class AuthorizeCacheService : CachingServiceBase, IAuthorizeCacheService
{
private const string KEY_GetLoginAddress = “Authorize:GetLoginAddress”;

private const string KEY_GetAccessToken = "Authorize:GetAccessToken-{0}";private const string KEY_GenerateToken = "Authorize:GenerateToken-{0}";/// <summary>/// 獲取登錄地址(GitHub)/// </summary>/// <param name="factory"></param>/// <returns></returns>public async Task<ServiceResult<string>> GetLoginAddressAsync(Func<Task<ServiceResult<string>>> factory){return await Cache.GetOrAddAsync(KEY_GetLoginAddress, factory, CacheStrategy.NEVER);}/// <summary>/// 獲取AccessToken/// </summary>/// <param name="code"></param>/// <param name="factory"></param>/// <returns></returns>public async Task<ServiceResult<string>> GetAccessTokenAsync(string code, Func<Task<ServiceResult<string>>> factory){return await Cache.GetOrAddAsync(KEY_GetAccessToken.FormatWith(code), factory, CacheStrategy.FIVE_MINUTES);}/// <summary>/// 登錄成功,生成Token/// </summary>/// <param name="access_token"></param>/// <param name="factory"></param>/// <returns></returns>public async Task<ServiceResult<string>> GenerateTokenAsync(string access_token, Func<Task<ServiceResult<string>>> factory){return await Cache.GetOrAddAsync(KEY_GenerateToken.FormatWith(access_token), factory, CacheStrategy.ONE_HOURS);} }

}
代碼很簡單,每個緩存都有固定KEY值,根據參數生成KEY,然后調用前面寫的擴展方法,再給一個過期時間即可,可以看到KEY里面包含了冒號 :,這個冒號 : 可以起到類似于文件夾的操作,在界面化管理工具中可以很友好的查看。

這樣我們的緩存就搞定了,然后在.Application層對應的Service中進行調用。代碼如下:

//AuthorizeService.cs
using Meowv.Blog.Application.Caching.Authorize;
using Meowv.Blog.Domain.Configurations;
using Meowv.Blog.ToolKits.Base;
using Meowv.Blog.ToolKits.Extensions;
using Meowv.Blog.ToolKits.GitHub;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Authorize.Impl
{
public class AuthorizeService : ServiceBase, IAuthorizeService
{
private readonly IAuthorizeCacheService _authorizeCacheService;
private readonly IHttpClientFactory _httpClient;

public AuthorizeService(IAuthorizeCacheService authorizeCacheService,IHttpClientFactory httpClient){_authorizeCacheService = authorizeCacheService;_httpClient = httpClient;}/// <summary>/// 獲取登錄地址(GitHub)/// </summary>/// <returns></returns>public async Task<ServiceResult<string>> GetLoginAddressAsync(){return await _authorizeCacheService.GetLoginAddressAsync(async () =>{var result = new ServiceResult<string>();var request = new AuthorizeRequest();var address = string.Concat(new string[]{GitHubConfig.API_Authorize,"?client_id=", request.Client_ID,"&scope=", request.Scope,"&state=", request.State,"&redirect_uri=", request.Redirect_Uri});result.IsSuccess(address);return await Task.FromResult(result);});}/// <summary>/// 獲取AccessToken/// </summary>/// <param name="code"></param>/// <returns></returns>public async Task<ServiceResult<string>> GetAccessTokenAsync(string code){var result = new ServiceResult<string>();if (string.IsNullOrEmpty(code)){result.IsFailed("code為空");return result;}return await _authorizeCacheService.GetAccessTokenAsync(code, async () =>{var request = new AccessTokenRequest();var content = new StringContent($"code={code}&client_id={request.Client_ID}&redirect_uri={request.Redirect_Uri}&client_secret={request.Client_Secret}");content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");using var client = _httpClient.CreateClient();var httpResponse = await client.PostAsync(GitHubConfig.API_AccessToken, content);var response = await httpResponse.Content.ReadAsStringAsync();if (response.StartsWith("access_token"))result.IsSuccess(response.Split("=")[1].Split("&").First());elseresult.IsFailed("code不正確");return result;});}/// <summary>/// 登錄成功,生成Token/// </summary>/// <param name="access_token"></param>/// <returns></returns>public async Task<ServiceResult<string>> GenerateTokenAsync(string access_token){var result = new ServiceResult<string>();if (string.IsNullOrEmpty(access_token)){result.IsFailed("access_token為空");return result;}return await _authorizeCacheService.GenerateTokenAsync(access_token, async () =>{var url = $"{GitHubConfig.API_User}?access_token={access_token}";using var client = _httpClient.CreateClient();client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.14 Safari/537.36 Edg/83.0.478.13");var httpResponse = await client.GetAsync(url);if (httpResponse.StatusCode != HttpStatusCode.OK){result.IsFailed("access_token不正確");return result;}var content = await httpResponse.Content.ReadAsStringAsync();var user = content.FromJson<UserResponse>();if (user.IsNull()){result.IsFailed("未獲取到用戶數據");return result;}if (user.Id != GitHubConfig.UserId){result.IsFailed("當前賬號未授權");return result;}var claims = new[] {new Claim(ClaimTypes.Name, user.Name),new Claim(ClaimTypes.Email, user.Email),new Claim(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(DateTime.Now.AddMinutes(AppSettings.JWT.Expires)).ToUnixTimeSeconds()}"),new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}")};var key = new SymmetricSecurityKey(AppSettings.JWT.SecurityKey.SerializeUtf8());var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);var securityToken = new JwtSecurityToken(issuer: AppSettings.JWT.Domain,audience: AppSettings.JWT.Domain,claims: claims,expires: DateTime.Now.AddMinutes(AppSettings.JWT.Expires),signingCredentials: creds);var token = new JwtSecurityTokenHandler().WriteToken(securityToken);result.IsSuccess(token);return await Task.FromResult(result);});} }

}
直接return我們的緩存接口,當查詢到Redis中存在KEY值的緩存就不會再走我們的具體的實現方法了。

注意注意,千萬不要忘了在.Application層的模塊類中添加依賴緩存模塊MeowvBlogApplicationCachingModule,不然就會報錯報錯報錯(我就是忘了添加…)

//MeowvBlogApplicationCachingModule.cs
using Meowv.Blog.Domain;
using Meowv.Blog.Domain.Configurations;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;

namespace Meowv.Blog.Application.Caching
{
[DependsOn(
typeof(AbpCachingModule),
typeof(MeowvBlogDomainModule)
)]
public class MeowvBlogApplicationCachingModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = AppSettings.Caching.RedisConnectionString;
});
}
}
}
此時項目的層級目錄結構。

圖片

好的,編譯運行項目,現在去調用接口看看效果,為了真實,這里我先將我redis緩存數據全部干掉。

圖片

訪問接口,…/auth/url,成功返回數據,現在再去看看我們的redis。

圖片

成功將KEY為:Authorize:GetLoginAddress 添加進去了,這里直接使用RedisDesktopManager進行查看。

圖片

那么再次調用這個接口,只要沒有過期,就會直接返回數據了,調試圖如下:

圖片

可以看到,是可以直接取到緩存數據的,其他接口大家自己試試吧,一樣的效果。

是不是很簡單,用最少的代碼集成Redis進行數據緩存,你學會了嗎?😁😁😁

開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial

總結

以上是生活随笔為你收集整理的基于 abp vNext 和 .NET Core 开发博客项目 - 使用Redis缓存数据的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。