欢迎访问 生活随笔!

凯发ag旗舰厅登录网址下载

当前位置: 凯发ag旗舰厅登录网址下载 > 编程语言 > >内容正文

asp.net

基于 abp vnext 和 .net core 开发博客项目 -凯发ag旗舰厅登录网址下载

发布时间:2025/1/21 19 豆豆
凯发ag旗舰厅登录网址下载 收集整理的这篇文章主要介绍了 基于 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));}/// /// 异常处理/// /// /// 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 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();}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;/// /// 12小时过期/// public const int half_day = 720;/// /// 8小时过期/// public const int eight_hours = 480;/// /// 5小时过期/// public const int five_hours = 300;/// /// 3小时过期/// public const int three_hours = 180;/// /// 2小时过期/// public const int two_hours = 120;/// /// 1小时过期/// public const int one_hours = 60;/// /// 半小时过期/// public const int half_hours = 30;/// /// 5分钟过期/// public const int five_minutes = 5;/// /// 1分钟过期/// public const int one_minute = 1;/// /// 永不过期/// 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 getloginaddressasync(func> factory);

/// /// 获取accesstoken/// /// /// /// task> getaccesstokenasync(string code, func>> factory);/// /// 登录成功,生成token/// /// /// /// task> generatetokenasync(string access_token, func>> 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}";/// /// 获取登录地址(github)/// /// /// public async task> getloginaddressasync(func>> factory){return await cache.getoraddasync(key_getloginaddress, factory, cachestrategy.never);}/// /// 获取accesstoken/// /// /// /// public async task> getaccesstokenasync(string code, func>> factory){return await cache.getoraddasync(key_getaccesstoken.formatwith(code), factory, cachestrategy.five_minutes);}/// /// 登录成功,生成token/// /// /// /// public async task> generatetokenasync(string access_token, func>> 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;}/// /// 获取登录地址(github)/// /// public async task> getloginaddressasync(){return await _authorizecacheservice.getloginaddressasync(async () =>{var result = new serviceresult();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);});}/// /// 获取accesstoken/// /// /// public async task> getaccesstokenasync(string code){var result = new serviceresult();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;});}/// /// 登录成功,生成token/// /// /// public async task> generatetokenasync(string access_token){var result = new serviceresult();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();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

总结

以上是凯发ag旗舰厅登录网址下载为你收集整理的基于 abp vnext 和 .net core 开发博客项目 - 使用redis缓存数据的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发ag旗舰厅登录网址下载网站内容还不错,欢迎将凯发ag旗舰厅登录网址下载推荐给好友。

网站地图