CCITU.Middleware
2.2.6
dotnet add package CCITU.Middleware --version 2.2.6
NuGet\Install-Package CCITU.Middleware -Version 2.2.6
<PackageReference Include="CCITU.Middleware" Version="2.2.6" />
paket add CCITU.Middleware --version 2.2.6
#r "nuget: CCITU.Middleware, 2.2.6"
// Install CCITU.Middleware as a Cake Addin #addin nuget:?package=CCITU.Middleware&version=2.2.6 // Install CCITU.Middleware as a Cake Tool #tool nuget:?package=CCITU.Middleware&version=2.2.6
一、ABP.Authentication身份认证
使用场景:
用于登录授权,接口鉴权。
依赖包:已安装
Install-Package JWT -Version 10.0.2
配置:放入appsettings.json文件里
{
"Authentication": {
"SecretKey": "用户授权、鉴权的密钥",
"TokenEffectiveMinutes": Token有效分钟数,
"RefreshTokenMinutes": Token在过期多少分钟前刷新Token
}
}
初始化:
1. 注册ABP依赖模块:AbpAuthenticationModule
[DependsOn(typeof(AbpAuthenticationModule))]
public class AbpTestModule:AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
//如果已经在appsettings.json文件里填了配置信息,这里可以不用调用,两种初始化方式用一种就好
services.AddAbpAuthentication(options =>
{
options.SecretKey = "";//用户授权、鉴权的密钥
options.TokenEffectiveMinutes = 30;//Token有效分钟数
options.RefreshTokenMinutes = 5;//Token在过期多少分钟前刷新Token
});
}
}
过滤器:
AuthenticationAttribute,用于对请求头部的Token进行校验
1. 鉴权
2. 有效期验证
3. 当Token即将过期刷新Token,刷新的Token会放到响应头部中,Key=NewToken
4. 将授权数据写入HttpContext.Items.Add("Auth_Data", "授权数据");
扩展方法:
1. 获取授权数据:string GetAuthenticationData(this HttpContext context)
使用说明:
1. 引入依赖注入实例IAuthenticationService
public interface IAuthenticationService
{
/// <summary>
/// 授权
/// </summary>
/// <param name="data">授权数据:用于存储跟授权用户相关的数据</param>
/// <returns>返回Token</returns>
string Authorization(Dictionary<string, object> data);
/// <summary>
/// 鉴权
/// </summary>
/// <param name="token">访问令牌</param>
/// <returns>授权用户相关的数据</returns>
string Authentication(string token);
/// <summary>
/// 是否刷新Token
/// </summary>
/// <param name="expTime">token过期时间</param>
/// <returns></returns>
bool IsRefreshToke(DateTime expTime);
}
二、ABP.DataEncryption数据加密
使用场景:
用于调用接口时,对请求参数加密处理
依赖包:已安装
Install-Package Portable.BouncyCastle -Version 1.9.0
初始化:
1. 注册ABP依赖模块:AbpDataEncryptionModule
2. 在配置服务容器中添加以下代码
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
services.AddDataEncryption(options =>
{
options.RSAPublic = "RSA加密公钥";
options.RSAPrivate = "RSA加密私钥";
});
}
前端:
1. RsaPublicKey=获取公钥
2. AesKey=随机生成一个字符串作为对称加密的密钥,16个字符
3. 用AesKey对请求数据进行对称加密,加密后的密文放到请求body里
4. 用公钥RsaPublicKey对密钥AesKey进行非对称加密,加密后的密文放到请求头部里,key=AesKey
5. 请求头部的数据类型=Aes,Content-Type=Aes
后端:
1. 在需要加密的实体类上面加上注解[ModelBinder(BinderType = typeof(DataEncryption.DataEncryptionModelBinder))]
2. 在接口参数左边加上参数注解[FromBody]
三、ABP.DataValidation数据验证
初始化:
1. 注册ABP依赖模块:AbpModelStateValidatorModule
基于数据注解验证:
Required:指定属性不能为空
Range:指定数值属性的范围
RegularExpression:指定属性的正则表达式
MaxLength:指定字符串属性的最大长度
MinLength:指定字符串属性的最小长度
DataType:指定属性的数据类型,例如日期、电子邮件或 URL 等
Compare:指定要比较的属性名称,例如两次输入密码是否一致等
自定义数据注解验证:
NotContainChinese:不包含中文
NotContainSpecialCharacter:不包含特殊字符
NotContainNumber:不包含数字
四、ABP.Hangfire任务调度
使用场景:
用于定时任务,在指定的周期时间内,调用指定的接口
依赖包:已安装
Install-Package Hangfire -Version 1.8.1
Install-Package Hangfire.Dashboard.BasicAuthorization -Version 1.0.2
Install-Package Hangfire.HttpJob -Version 3.7.6
Install-Package Hangfire.HttpJob.Client -Version 1.2.9
Install-Package Hangfire.Redis.StackExchange -Version 1.8.7
配置:放入appsettings.json文件里
{
"Hangfire": {
"ConnectionString": "数据库连接字符串",
"DbType": 2, //数据库类型,1=SqlServer|2=Redis,默认为SqlServer
"DefaultDatabase": 10, //如果使用的是Redis,可以指定默认使用的数据库,不指定为0
"UserName": "后台管理授权账号",
"Password": "后台管理授权密码"
}
}
初始化:
1. 注册ABP依赖模块:AbpHangfireModule
2. 在配置服务容器中添加以下代码
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
//如果已经在appsettings.json文件里填了配置信息,这里可以不用调用,两种初始化方式用一种就好
services.AddAbpHangfire(options =>
{
options.ConnectionString = "数据库连接字符串";
options.DbType = "数据库类型,默认为SqlServer";
options.DefaultDatabase = "如果使用的是Redis,可以指定使用的数据库,默认为0";
options.UserName = "登录账号";
options.Password = "登录密码";
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
//如果已经在appsettings.json文件里填了配置信息,这里可以不用调用,两种初始化方式用一种就好
app.UseAbpHangfireDashboard();
}
后台管理:路由地址/hangfire
1. 添加定时任务
2. 查看定时任务执行结果
五、ABP.LogDashboard日志面板
使用场景:
用于记录日志、查看日志
依赖包:已安装
Install-Package LogDashboard -Version 1.4.8
Install-Package Serilog.AspNetCore -Version 6.1.0
配置:放入appsettings.json文件里
{
"LogDashboard": {
"UserName": "后台管理授权账号",
"Password": "后台管理授权密码"
}
}
初始化:
1. 注册ABP依赖模块:AbpLogDashboardModule
过滤器:
ApiLogFilterAttribute 记录接口请求响应日志
ErrorLogFilterAttribute 记录系统异常日志
自定义属性:
NotRecordApiLog 不记录日志
NotRecordApiRequestLog 不记录接口请求日志
NotRecordApiResponseLog 不记录接口响应日志
后台管理:路由地址/logdashboard
1. 查看日志
使用说明:
1. 引入依赖注入实例ILogger
记录日志使用方式跟netcore框架自带的ILogger一样
六、ABP.RabbitMQ消息队列
依赖包:已安装
Install-Package RabbitMQ.Client -Version 6.5.0
配置:放入appsettings.json文件里
{
"RabbitMQ": {
"Host": "主机地址",
"Port": 端口号,
"UserName": "账号",
"PassWord": "密码",
"VirtualHost": "/",
"ChannelOptions":{
"PrefetchCount":每个消费者一次能预取的消息数量,数值越大内存占用越高
}
}
}
初始化:
1. 注册ABP依赖模块:AbpRabbitMQModule
使用说明:
1. 引入依赖注入实例IRabbitMQService
/// <summary>
/// MQ消息队列服务
/// </summary>
public interface IRabbitMQService
{
/// <summary>
/// 发送消息
/// </summary>
/// <param name="queueName">队列名称</param>
/// <param name="msg">消息</param>
void Publish(string queueName, string msg);
/// <summary>
/// 发送消息
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queueName"></param>
/// <param name="msg"></param>
void Publish<T>(string queueName, T msg);
/// <summary>
/// 消费消息
/// </summary>
/// <param name="queueName">队列名称</param>
/// <param name="consumeFunc">消息回调函数:返回true消费成功,返回false消费失败</param>
/// <param name="maxRetryCount">消费失败最大重试次数</param>
/// <returns></returns>
string Consume(string queueName, Func<string, bool> consumeFunc, int maxRetryCount = 3);
/// <summary>
/// 消费消息
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queueName"></param>
/// <param name="consumeFunc"></param>
/// <param name="maxRetryCount"></param>
/// <returns></returns>
string Consume<T>(string queueName, Func<T, bool> consumeFunc, int maxRetryCount = 3);
}
七、ABP.Redis缓存
依赖包:已安装
Install-Package StackExchange.Redis -Version 2.6.104
配置:放入appsettings.json文件里
{
"Redis": {
"ConnectionString": "Redis数据库连接字符串",
"DefaultDatabase": 0,//默认使用的数据库,不指定为0
"Enable": true,//是否启用,如果不启用会用内存缓存
"LockType": 1,//锁类型:1=线程锁,2=Redis分布式锁。默认值=1
}
}
初始化:
1. 注册ABP依赖模块:AbpRedisModule
缓存使用说明:
1. 引入依赖注入实例ICacheService
/// <summary>
/// 缓存服务
/// </summary>
public interface ICacheService
{
/// <summary>
/// 添加对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiry">过期时间</param>
/// <param name="dbIndex">数据库索引,如果为null则使用配置文件里的DefaultDatabase</param>
/// <returns></returns>
bool Add<T>(string key, T value, TimeSpan? expiry = null, int? dbIndex = null);
/// <summary>
/// 添加字符串
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiry"></param>
/// <param name="dbIndex"></param>
/// <returns></returns>
bool AddString(string key, string value, TimeSpan? expiry = null, int? dbIndex = null);
/// <summary>
/// 获取对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="dbIndex"></param>
/// <returns></returns>
T Get<T>(string key, int? dbIndex = null);
/// <summary>
/// 获取字符串
/// </summary>
/// <param name="key"></param>
/// <param name="dbIndex"></param>
/// <returns></returns>
string GetString(string key, int? dbIndex = null);
/// <summary>
/// 移除缓存
/// </summary>
/// <param name="key"></param>
/// <param name="dbIndex"></param>
/// <returns></returns>
bool Remove(string key, int? dbIndex = null);
/// <summary>
/// 搜索key
/// </summary>
/// <param name="pattern">搜索关键字</param>
/// <param name="dbIndex"></param>
/// <returns></returns>
IEnumerable<string> GetAllKey(string pattern, int? dbIndex = null);
/// <summary>
/// 缓存是否存在
/// </summary>
/// <param name="key"></param>
/// <param name="dbIndex"></param>
/// <returns></returns>
bool Exists(string key, int? dbIndex = null);
/// <summary>
/// 设置缓存过期时间
/// </summary>
/// <param name="key"></param>
/// <param name="expiry"></param>
/// <param name="dbIndex"></param>
/// <returns></returns>
bool KeyExpire(string key, TimeSpan? expiry, int? dbIndex = null);
}
锁使用说明:
1. 引入依赖注入实例ILockService
/// <summary>
/// 锁
/// </summary>
public interface ILockService
{
/// <summary>
/// 加锁:回调函数中的代码会串行
/// </summary>
/// <param name="lockKey">锁的名称:相同的名称视为同一个锁</param>
/// <param name="action">回调函数</param>
/// <param name="secondsTimeout">超时时间:默认5分钟</param>
T ActionLock<T>(string lockKey, Func<T> action, int secondsTimeout = 300);
Task<T> ActionLockAsync<T>(string lockKey, Func<Task<T>> action, int secondsTimeout = 300);
}
2. 使用案例
var result = lockService.ActionLock("锁的名称:相同的名称视为同一个锁", () =>
{
//业务代码执行中
Thread.Sleep(5000);
return true;
});
自增使用说明:
1. 引入依赖注入实例IAutoIncrementService
/// <summary>
/// 自增
/// </summary>
public interface IAutoIncrementService
{
/// <summary>
/// 生成自增ID
/// </summary>
/// <param name="key"></param>
/// <param name="dbIndex"></param>
/// <param name="secondsTimeout">超时时间:默认3秒</param>
/// <returns></returns>
Task<long> GenerateIdAsync(string key, int? dbIndex = null, int secondsTimeout = 3);
}
八、ABP.SqlSugar数据库访问
依赖包:已安装
Install-Package SqlSugarCore -Version 5.1.4.69
配置:放入appsettings.json文件里
{
"SqlSugar": {
"ConnConfigList": [
{
"Tenant": "租户名称",
"ConnStr": "数据库连接字符串",
"DbType": "数据库类型:0=MySql,1=SqlServer,2=Sqlite,默认值为1",
"IsAutoCloseConnection": "是否自动关闭连接:默认是",
"IsEnableReadWriteSeparation": "是否启用读写分离:默认不启用",
"SlaveConnConfigs":[
{
"HitRate": 权重:数值越高,读到的概率越高,
"ConnStr": "数据库连接字符串"
}
]//从库连接配置集合,用于读写分离
}
],//数据库连接配置集合
"CommandTimeOut": "执行命令超时时间:默认30秒",
"IsWithNoLockQuery": "是否脏读:默认值true",
"IsUtcNow": "是否是Utc时间:默认值false",
"WorkId":"用于生成雪花ID的:不同的机器不要配置一样的,默认值1"
}
}
初始化:
1. 注册ABP依赖模块:AbpSqlSugarModule,无需二级缓存的注册AbpSqlSugarNoCacheModule
使用说明:
1.引入依赖注入实例:ISqlSugarService
/// <summary>
/// 数据库访问服务
/// </summary>
public interface ISqlSugarService
{
/// <summary>
/// 数据库配置参数
/// </summary>
SqlSugarOptions Options { get; }
/// <summary>
/// 数据库访问客户端
/// </summary>
SqlSugarClient Client { get; }
/// <summary>
/// 获取雪花ID
/// </summary>
/// <returns></returns>
long GetSnowFlakeSingle();
}
2.多库实现:
2.1 需要在Do上面加上属性标注:[Tenant("租户名称,对应配置文件里的Tenant,根据值去匹配数据库连接字符串")]
2.2 增删改查需要使用带WithAttr后缀的方法:例如:QueryableWithAttr、InsertableWithAttr
3.读写分离:主库负责增删改,从库负责读
3.1 启用读写分离的三种方式:默认是不启用的
3.1.1 修改配置文件IsEnableReadWriteSeparation=true(不推荐使用,会影响到所有的代码)
3.1.2 在需要的接口上面添加属性标记[ReadWriteSeparation](推荐使用,影响范围只有这个接口)
3.1.3 用SlaveQueryableWithAttr方法查询数据(合理使用,对于时效性要求不高的查询可以用)
3.2 事务里会强制读主库,如需在事务外读主库用MasterQueryableWithAttr方法查询数据。
仓储使用说明:
应用服务层代码:
public class CfgAppImpl : RepositoryService<CfgAppDo>, IScopedDependency
{
public CfgAppImpl(ISqlSugarService db, IObjectMapper mapper) : base(db, mapper)
{
}
}
展现层调用代码:
public class CfgAppController : ControllerBase
{
private readonly CfgAppImpl cfgAppImpl;
public CfgAppController(CfgAppImpl cfgAppImpl)
{
this.cfgAppImpl = cfgAppImpl;
}
public async Task Add()
{
AddOrEditCfgAppRequestDto dto = new AddOrEditCfgAppRequestDto()
{
CfgId = 10003,
Name = "Name3",
Value = "Value3"
};
var result = await cfgAppImpl.InsertAsync(dto);
}
public async Task Edit()
{
AddOrEditCfgAppRequestDto dto = new AddOrEditCfgAppRequestDto()
{
CfgId = 10001,
Name = "Name11",
Value = "Value11"
};
var result = await cfgAppImpl.UpdateAsync(dto);
}
public async Task Del()
{
var result = await cfgAppImpl.DeleteAsync(new CfgAppDo() { CfgId = 10001 });
}
public async Task ToPageList()
{
var result = await cfgAppImpl.ToPageListAsync(new QueryParameters(), 1, 2);
}
}
分表使用说明:
[SplitTable(SplitType.Month)]
[SugarTable("SplitTestTable_{year}{month}{day}"), Tenant("EDM")]
public class SplitTestTableDo
{
[SugarColumn(IsPrimaryKey = true)]
public long Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
[SplitField] //分表字段 在插入的时候会根据这个字段插入哪个表,在更新删除的时候用这个字段找出相关表
public DateTime CreateTime { get; set; }
}
增:
//已CreateTime字段按月分表
List<SplitTestTableDo> list = new List<SplitTestTableDo>()
{
new SplitTestTableDo(){ Id = 1, Name = "Name1", Age = 100, CreateTime = DateTime.Parse("2024-1-3 10:10:10")},
new SplitTestTableDo(){ Id = 2, Name = "Name2", Age = 200, CreateTime = DateTime.Parse("2024-2-15 11:11:11")},
new SplitTestTableDo(){ Id = 3, Name = "Name3", Age = 300, CreateTime = DateTime.Parse("2024-2-16 12:12:12")},
new SplitTestTableDo(){ Id = 4, Name = "Name4", Age = 400, CreateTime = DateTime.Parse("2024-3-15")}
};
var result = db.Client.InsertableWithAttr<SplitTestTableDo>(list).SplitTable().ExecuteCommand();
删:
long id = 3;
DateTime createTime = DateTime.Parse("2024-2-1");
var result = db.Client.DeleteableWithAttr<SplitTestTableDo>()
.Where(o => o.Id == id)
//.SplitTable(tas => tas)//不知道该条数据的创建时间是哪个月(分表字段),此写法会把1-3月的表都删除一遍
.SplitTable(tas =>
{
return tas.Where(o => o.Date == createTime);
})//知道该条数据的创建时间是哪个月会只删除2月的表(SplitTestTable_20240201)
.ExecuteCommand();
改:
long id = 2;
DateTime createTime = DateTime.Parse("2024-2-1");
var result = db.Client.UpdateableWithAttr<SplitTestTableDo>()
.SetColumns(o => o.Age == 201)
.Where(o => o.Id == id)
//.SplitTable(tas => tas)//不知道该条数据的创建时间是哪个月(分表字段),此写法会把1-3月的表都修改一遍
.SplitTable(tas =>
{
return tas.Where(o => o.Date == createTime);
})//知道该条数据的创建时间是哪个月会只修改2月的表(SplitTestTable_20240201)
.ExecuteCommand();
查:
DateTime createTime = DateTime.Parse("2024-1-1");
DateTime startTime = DateTime.Parse("2024-2-3");
DateTime endTime = DateTime.Parse("2024-3-25");
var result = db.Client.QueryableWithAttr<SplitTestTableDo>()
.Where(o => o.Age >= 200 && o.Age <= 500)
//.SplitTable()//此写法会把1-3月的表并起来查
//.SplitTable(startTime, endTime)//此写法会把2-3月的表并起来查,查询2月3号-3月25号的数据
.SplitTable(tas =>
{
return tas.Where(o => o.Date == createTime);
})//此写法只查1月份的数据
.ToList();
九、ABP.Swagger接口文档
依赖包:已安装
Install-Package Swashbuckle.AspNetCore -Version 6.5.0
Install-Package Swashbuckle.AspNetCore.Annotations -Version 6.5.0
初始化:
1. 注册ABP依赖模块:AbpSwaggerModule
使用说明:
1. 在浏览器中输入路由地址:/swagger即可查看接口文档
十、ABP.Kafka消息队列
依赖包:已安装
Install-Package Confluent.Kafka -Version 1.9.0
Install-Package protobuf-net -Version 3.1.17
配置:放入appsettings.json文件里
{
"Kafka": {
"ProduceBootstrapServers": "生产者 kafka 代理主机:端口",
"ConsumeBootstrapServers": "消费者 kakfa 代理主机:端口",
"UserName":"认证账号",
"Password":"认证密码"
}
}
初始化:
1. 注册ABP依赖模块:AbpKafkaModule
使用说明:
1. 拥入依赖注入实例:ICommonConfulentKafka
public interface ICommonConfulentKafka
{
/// <summary>
/// 获取主题分区数
/// </summary>
/// <param name="topicName">主题</param>
/// <returns></returns>
int? GetPartitionsByTopic(string topicName);
/// <summary>
/// 删除标题
/// </summary>
/// <param name="topicName">标题名称</param>
/// <returns></returns>
Task DeleteTopicAsync(string topicName);
/// <summary>
/// 创建标题
/// </summary>
/// <param name="topicName">标题名称</param>
/// <returns></returns>
Task CreateTopicAsync(string topicName);
/// <summary>
/// 生产者 发送消息
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="topicName">标题</param>
/// <param name="msg">消息内容</param>
/// <returns></returns>
Task ProduceMsgAsync<T>(string topicName, T msg);
/// <summary>
/// 消费者 接收消息
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="topics">标题类型</param>
/// <param name="group">组名</param>
/// <returns></returns>
IConsumer<Ignore, T> ConsumeMsg<T>(string group);
/// <summary>
/// 生产者 发送Proto消息
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="topicName">标题</param>
/// <param name="msg">消息内容</param>
/// <returns></returns>
Task ProduceProtoBufMsgAsync<T>(string topicName, T msg);
/// <summary>
/// 消费者 接收Proto消息
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="topics">标题类型</param>
/// <param name="group">组名</param>
/// <returns></returns>
IConsumer<Ignore, T> ConsumeProtoBufMsg<T>(string group);
}
十一、ABP.Mail邮件服务
配置:放入appsettings.json文件里
{
"Mail": {
"Host": "邮件服务商主机地址",
"Port": "邮件服务商主机端口号",
"SenderEmail": "发件人邮箱",
"SenderPwd": "发件人密码",
"SenderName": "发件人名称",
"WriteBackEmail": "回信邮箱"
}
}
初始化:
1. 注册ABP依赖模块:AbpMailModule
使用说明:
1.引入依赖注入实例:IMailService
/// <summary>
/// 邮件服务
/// </summary>
public interface IMailService
{
/// <summary>
/// 发送邮件
/// </summary>
/// <param name="sendMailOptions"></param>
void Send(SendMailOptions sendMailOptions);
}
发送邮件参数说明SendMailOptions:
AddresseeEmail:收件人邮箱。
Subject:主题。
Contents:内容集合
ContentType:内容类型text/html|text/plain|text/richtext|text/xml
更多类型查看MediaTypeNames常量。
Content:内容文本。
ContentEncoding:内容编码。
Attachments:附件集合。
十二、ABP.SMS短信服务
依赖包:已安装
阿里云短信服务开发包
Install-Package AlibabaCloud.SDK.Dysmsapi20170525 -Version 2.0.23
配置:放入appsettings.json文件里
{
"SmsOptions": {
"AccessKeyId": "账号ID",
"AccessKeySecret": "api访问密钥"
}//短信平台参数
}
初始化:
1. 注册ABP依赖模块:AbpSmsModule
使用说明:
1.引入依赖注入实例:ISmsService
/// <summary>
/// 短信服务
/// </summary>
public interface ISmsService
{
/// <summary>
/// 发送短信
/// </summary>
/// <param name="sendSmsOptions"></param>
/// <returns></returns>
bool Send(SendSmsOptions sendSmsOptions);
}
发送短信参数说明SendSmsOptions:
PhoneNumbers:接收人手机号码。
SignName:签名,显示在短信前面,需要去短信平台申请。
TemplateCode:模板CODE,需要去短信平台申请。
TemplateParam:模板参数:json对象字符串。
十三、ABP.FileCore文件服务
使用场景:
保存文件、excel导入导出
依赖包:已安装
Install-Package NPOI -Version 2.6.0
初始化:
1. 注册ABP依赖模块:AbpFileCoreModule
2. 在配置服务容器中添加以下代码
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
services.AddFileCore(options =>
{
options.AllowFileExts = "允许的文件扩展名集合";
options.LimitMaxSize = "文件最大长度:单位字节";
options.StorageRootDir = "存储文件根目录";
options.MappingUrlPath = "访问文件url地址根路径";
});
}
属性说明:
导入Excel:
导入列*:[Display(Name = "列名")]
忽略导入列:[IgnoreImportColumn]
必填列:[Required(ErrorMessage = "{0}不能为空")],更多属性参考netcore数据注解模型验证
导出Excel:
导出列*:[Display(Name = "列名", Order = 排序:非必填,不填按属性从上到下排)]
忽略导出列:[IgnoreColumn]
行高:[RowHeight(表头行高, 数据列行高)]
列宽:[HeaderStyle(ColumnSize = 单位:字符个数)]
表头字体颜色:[HeaderFont(Color = HSSFColor.Pink.Index)]
数据列字体颜色:[DataFont(Color = HSSFColor.Red.Index)]
数据列样式:[DataStyle(DataFormat = "yyyy-MM-dd HH:mm")]
数据列求和:[ColumnStats((int)FunctionEnum.Sum)]
数据列求平均值:[ColumnStats((int)FunctionEnum.Avg, OffsetRow = 3)]
使用说明:
1.引入依赖注入实例:IFileService
/// <summary>
/// 文件服务
/// </summary>
public interface IFileService
{
/// <summary>
/// 保存文件
/// </summary>
/// <param name="fileData">文件数据</param>
/// <param name="fileName">文件名称</param>
/// <param name="fileRelativeDir">文件的相对目录,会跟存储文件的根目录拼接起来</param>
/// <returns></returns>
SaveFileResultDto SaveFile(byte[] fileData, string fileName, string fileRelativeDir = "");
}
保存文件返回值说明SaveFileResultDto:
FileDir:文件完整存储目录
Url:访问文件的url地址
2.引入依赖注入实例:IExcelService
/// <summary>
/// Excel导入导出
/// </summary>
public interface IExcelService
{
/// <summary>
/// 导出
/// </summary>
/// <typeparam name="TExportDto"></typeparam>
/// <param name="data">数据集合</param>
/// <param name="fileName">文件名称</param>
/// <param name="fileRelativeDir">文件的相对目录,如果传了会跟存储文件的根目录拼接起来</param>
/// <returns></returns>
Task<ExportFileResultDto> ExportAsync<TExportDto>(List<TExportDto> data, string fileName, string fileRelativeDir = "") where TExportDto : class, new();
/// <summary>
/// 导出:支持复杂表头合并、动态表头
/// </summary>
/// <param name="data">导出信息</param>
/// <param name="fileName">文件名称</param>
/// <param name="fileRelativeDir">文件的相对目录,如果传了会跟存储文件的根目录拼接起来</param>
/// <param name="isUnique"></param>
/// <returns></returns>
Task<ExportFileResultDto> ExportAsync(ExportInfoDto data, string fileName, string fileRelativeDir = "Export");
/// <summary>
/// 导入
/// </summary>
/// <typeparam name="TImportDto"></typeparam>
/// <param name="filePath">导入的文件路径</param>
/// <param name="importFunc">导入成功回调函数</param>
/// <param name="fileName">文件名称</param>
/// <param name="fileRelativeDir">文件的相对目录,会跟存储文件的根目录拼接起来</param>
/// <returns></returns>
Task<ImportFileResultDto> ImportAsync<TImportDto>(string filePath, Func<IEnumerable<TImportDto>, IEnumerable<TImportDto>> importFunc, string fileName, string fileRelativeDir = "") where TImportDto : ImportItemDto, new();
}
导出返回值说明:ExportFileResultDto:
FileDir:文件完整存储目录
FileData:文件数据:字节数组
Url:访问文件的url地址
导入返回值说明:ImportFileResultDto:
FileDir:导入结果文件完整存储目录
FileData:导入结果文件数据:字节数组
Url:导入结果文件的url地址
Total:导入总记录数
SuccessCount:导入成功记录数
FailCount:导入失败记录数
导入输入参数说明:ExportInfoDto
SheetName:表名
HeaderList:表头集合
DataList:表体集合
AutoMerge:自动合并表头
使用案例:导出复杂表头合并、动态表头
合并前: <table border="1"> <tr> <td>序号1</td> <td>单位名称</td> <td>合计</td> <td>合计</td> <td>合计</td> <td>动态列1</td> <td>动态列2</td> </tr> <tr> <td>序号2</td> <td>单位名称</td> <td>合计A</td> <td>合计B</td> <td>合计C</td> <td>动态列1</td> <td>动态列2</td> </tr> <tr> <td>序号3</td> <td>单位信息</td> <td>合计A</td> <td>合计B</td> <td>合计C</td> <td>动态列1</td> <td>动态列2</td> </tr> </table> 合并后: <table border="1"> <tr> <td>序号1</td> <td rowspan="2">单位名称</td> <td colspan="3" align="center">合计</td> <td rowspan="3">动态列1</td> <td rowspan="3">动态列2</td> </tr> <tr> <td>序号2</td> <td rowspan="2">合计A</td> <td rowspan="2">合计B</td> <td rowspan="2">合计C</td> </tr> <tr> <td>序号3</td> <td>单位信息</td> </tr> </table>
1.导出:支持复杂表头合并、动态表头
//表头集合
var headerList = new List<List<CellInfo>>
{
new List<CellInfo>
{
new CellInfo()
{
Name = "序号1",//列名
HorizontalAlignment = HorizontalAlignment.Center,//水平对齐
VerticalAlignment = VerticalAlignment.Center,//垂直对齐
FontColor = IndexedColors.Black.Index,//字体颜色
FontHeightInPoints = 11,//字体大小
FillForegroundColor = IndexedColors.White.Index,//填充背景颜色
FillPattern = FillPattern.NoFill//填充模式
},
new CellInfo(){Name = "单位名称"},
new CellInfo(){Name = "合计"},
new CellInfo(){Name = "合计"},
new CellInfo(){Name = "合计"},
new CellInfo(){Name = "动态列1"},
new CellInfo(){Name = "动态列2"}
},
new List<CellInfo>
{
new CellInfo(){Name = "序号2"},
new CellInfo(){Name = "单位名称"},
new CellInfo(){Name = "合计A"},
new CellInfo(){Name = "合计B"},
new CellInfo(){Name = "合计C"},
new CellInfo(){Name = "动态列1"},
new CellInfo(){Name = "动态列2"}
},
new List<CellInfo>
{
new CellInfo(){Name = "序号3"},
new CellInfo(){Name = "单位信息"},
new CellInfo(){Name = "合计A"},
new CellInfo(){Name = "合计B"},
new CellInfo(){Name = "合计C"},
new CellInfo(){Name = "动态列1"},
new CellInfo(){Name = "动态列2"}
}
};
//表体集合
var dataList = new DataTable();
dataList.Columns.Add("column1", typeof(int));//列名可以不跟上面列名保持一致,但是顺序必须保持一致
dataList.Columns.Add("单位名称", typeof(string));
dataList.Columns.Add("合计A", typeof(int));
dataList.Columns.Add("合计B", typeof(int));
dataList.Columns.Add("合计C", typeof(int));
dataList.Columns.Add("动态列1", typeof(int));
dataList.Columns.Add("动态列2", typeof(int));
//添加测试数据
dataList.Rows.Add(1, "单位111", 86, 13, 45, 11, 12);
dataList.Rows.Add(2, "单位222", 23, 453, 234, 21, 22);
//导出
var exportInfo = new ExportInfoDto()
{
SheetName = "复杂表头合并、动态表头",
HeaderList = headerList,
DataList = dataList,
AutoMerge = true//自动合并表头
};
var result = await excelService.ExportAsync(exportInfo, "导出的Excel.xlsx");
十四、ABP.PaymentCore在线支付
使用场景:
用于空中云汇支付、支付宝支付
依赖包:已安装
Install-Package RestSharp -Version 106.13.0
初始化:
1. 注册ABP依赖模块:AbpPaymentCoreModule
2. 在配置服务容器中添加以下代码
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
//添加空中云汇支付
services.AddAirwallexPayment(options =>
{
options.ClientId = "客户ID:第三方支付平台提供";
options.ApiKey = "调用Api密钥:第三方支付平台提供";
options.GetTokenUrl = "获取Token接口地址";
options.PaymentUrl = "支付下单接口地址";
options.IsRecordRequestMessage = "是否记录请求报文:默认值为true";
options.CacheKeyPrefix = "缓存key前缀:默认值为Airwallex_";
});
}
使用说明:
1.引入依赖注入实例:IPaymentService
/// <summary>
/// 支付服务
/// </summary>
public interface IPaymentService
{
/// <summary>
/// 开始支付:向第三方支付平台下单
/// </summary>
/// <param name="request"></param>
/// <param name="paymentType"></param>
/// <returns></returns>
DirectPayResponse BeginPay(DirectPayRequest request, PaymentTypeEnum paymentType);
/// <summary>
/// 支付完成:解析第三方平台支付成功信息
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
Task<DirectPayResult> PayComplete(HttpContext context);
/// <summary>
/// 支付完成
/// </summary>
/// <param name="packet"></param>
/// <returns></returns>
DirectPayResult PayComplete(HttpPacket packet);
}
1.支付下单参数说明DirectPayRequest:
TradeId:唯一交易ID
TradeName:订单编号
Amount:支付金额
Currency:支付币种
2.支付下单返回值说明DirectPayResponse:
Type:数据类型:由于各平台的支付方式不一样,返回的数据类型也不一样,有的是返回支付链接、有的是返回支付密钥,还有返回支付二维码的
UrlData:支付链接
JsonData:支付密钥
ImageData:二维码数据:字节数组
3.支付成功返回值说明:DirectPayResult
Success:是否支付成功
TradeId:唯一交易ID:我们支付下单的时候提供的
TradeName:订单编号:我们支付下单的时候提供的
PaymentType:支付类型
ThirdPartyTradeId:第三方交易ID
PracticalCurrency:实付币种
PracticalAmount:实付金额
十五、ABP.AutoInject自动依赖注入
使用场景:
1.用于属性依赖注入懒加载,首次访问属性才去容器中创建实例
2.用于依赖注入检查:避免忘记做依赖注入了,导致运行中才报空引用错误!
依赖包:已安装
Install-Package Volo.Abp.Autofac -Version 4.4.4
Install-Package Volo.Abp.AspNetCore -Version 4.4.4
初始化:
1.在Startup启动类加上下面方法
public void ConfigureContainer(ContainerBuilder builder)
{
//添加自动注入:给依赖注入实例做动态代理,动态代理会通过拦截器来拦截属性,从而实现属性自动懒加载,只在访问属性的时候才去获取依赖注入实例
builder.AddAutoInject<AppModule>();
}
2. 在配置服务容器中添加以下代码
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
//用于将控制器注入到容器中,以便对控制器做动态代理
services.AddControllers().AddControllersAsServices();
}
public override void PostConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
//依赖注入检查:避免忘记做依赖注入了,导致运行中才报空引用错误!
services.DependencyInjectCheck<AppModule>();
}
使用说明:
1.在Applidation应用服务层使用案例
public class TestC : IScopedDependency, IAutoLazyInject
{
/// <summary>
/// 属性懒加载:自动获取依赖注入实例
/// 要求:
/// 1.类必须继承IAutoLazyInject接口
/// 2.属性必须是虚属性
/// 3.属性必须是public的
/// 4.属性必须加[AutoLazyInject]标记
/// 建议:
/// 1.建议用下划线开头,表示私有,不提倡在类的外部去访问
/// </summary>
[AutoLazyInject]
public virtual TestB _testB { get; }
public void Test()
{
_testB.Test();
}
}
2.在Api展现层使用案例
跟应用服务层一样,控制器继承IAutoLazyInject接口
十六、ABP.RateLimit接口IP白名单、IP限流
使用场景:
用于接口限流、白名单访问
接口限流github:https://github.com/stefanprodan/AspNetCoreRateLimit
依赖包:已安装
Install-Package AspNetCoreRateLimit -Version 4.0.2
配置:放入appsettings.json文件里
{
"RateLimit": {
"IpAccess": {
//是否启用IP白名单访问
"EnableIpWhitelistAccess": true,
//允许访问的IP白名单
"AccessIpWhitelist": [ "::1" ],
//是否启用代理服务
"EnableProxyServer": false,
//允许访问的代理服务器IP白名单
"ProxyServerIpWhitelist": [],
//如果使用代理服务器需要填写,将从该请求头部获取客户端IP地址
"RealIpHeader": null
},
"IpRateLimiting": {
//false:则全局将应用限制,并且仅应用具有作为端点的规则*。例如,如果您设置每秒5次调用的限制,则对任何端点的任何HTTP调用都将计入该限制
//true:则限制将应用于每个端点,如{HTTP_Verb}{PATH}。例如,如果您为*:/api/values客户端设置每秒5个呼叫的限制,
"EnableEndpointRateLimiting": false,
//false:拒绝的API调用不会添加到调用次数计数器上;如 客户端每秒发出3个请求并且您设置了每秒一个调用的限制,则每分钟或每天计数器等其他限制将仅记录第一个调用,即成功的API调用。
//true:如果您希望被拒绝的API调用计入其他时间的显示(分钟,小时等),则必须设置StackBlockedRequests为true。
"StackBlockedRequests": false,
//应用服务器背后是一个反向代理,如果你的代理服务器使用不同的页眉然后提取客户端IP X-Real-IP使用此选项来设置
"RealIpHeader": "X-Real-IP",
//限制状态码
"QuotaExceededResponse": {
"Content": "{{\"Success\":false,\"ResultCode\":400,\"Message\":\"Quota exceeded. Maximum allowed: {0} per {1}. Please try again in {2} second(s).\"}}",
"ContentType": "application/json",
"StatusCode": 429
},
//IP白名单:支持Ip v4和v6
//"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ],
//端点白名单
//"EndpointWhitelist": [ "get:/api/license", "*:/api/status" ],
//通用规则
"GeneralRules": [
{
//端点路径
"Endpoint": "*",
//时间段,格式:{数字}{单位};可使用单位秒分时天:s, m, h, d
"Period": "5s",
//限制
"Limit": 2
}
]
},
"IpRateLimitPolicies": {
//ip规则
"IpRules": [
{
"Ip": "::1",
"Rules": [
{
"Endpoint": "*",
"Period": "5s",
"Limit": 3
}
]
}
]
}
}
}
初始化:
1. 注册ABP依赖模块:AbpIpWhitelistModule、AbpIpRateLimitModule
[DependsOn(typeof(AbpIpWhitelistModule), typeof(AbpIpRateLimitModule))]
public class AbpTestModule:AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
}
}
2. 如需单独对某个ip设置限流,需要加上以下代码
public static async Task Main(string[] args)
{
//CreateHostBuilder(args).Build().Run();
var webHost = CreateHostBuilder(args).Build();
using (var scope = webHost.Services.CreateScope())
{
// get the IpPolicyStore instance
var ipPolicyStore = scope.ServiceProvider.GetRequiredService<IIpPolicyStore>();
// seed IP data from appsettings
await ipPolicyStore.SeedAsync();
}
await webHost.RunAsync();
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 is compatible. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net5.0
- AlibabaCloud.SDK.Dysmsapi20170525 (>= 2.0.23)
- AlipaySDKNet.Standard (>= 4.7.295)
- AspNetCoreRateLimit (>= 4.0.2)
- CCITU.Common (>= 2.1.1)
- Confluent.Kafka (>= 1.9.0)
- EasyCaching.InMemory (>= 1.9.2)
- EasyCaching.Redis (>= 1.9.2)
- EasyCaching.Serialization.Json (>= 1.9.2)
- EPPlus (>= 6.0.3)
- Hangfire (>= 1.8.1)
- Hangfire.Dashboard.BasicAuthorization (>= 1.0.2)
- Hangfire.HttpJob (>= 3.7.6)
- Hangfire.HttpJob.Client (>= 1.2.9)
- Hangfire.Redis.StackExchange (>= 1.8.7)
- JWT (>= 10.0.2)
- LogDashboard (>= 1.4.8)
- NPOI (>= 2.6.0)
- Portable.BouncyCastle (>= 1.9.0)
- protobuf-net (>= 3.1.17)
- RestSharp (>= 106.13.0)
- Serilog.AspNetCore (>= 8.0.0)
- SqlSugarCore (>= 5.1.4.154)
- StackExchange.Redis (>= 2.6.111)
- Swashbuckle.AspNetCore (>= 6.5.0)
- Swashbuckle.AspNetCore.Annotations (>= 6.5.0)
- Volo.Abp.AspNetCore (>= 4.4.4)
- Volo.Abp.AspNetCore.Mvc (>= 4.4.4)
- Volo.Abp.Autofac (>= 4.4.4)
- Volo.Abp.AutoMapper (>= 4.4.4)
-
net6.0
- AlibabaCloud.SDK.Dysmsapi20170525 (>= 2.0.23)
- AlipaySDKNet.Standard (>= 4.7.295)
- AspNetCoreRateLimit (>= 4.0.2)
- CCITU.Common (>= 2.1.1)
- Confluent.Kafka (>= 2.4.0)
- EPPlus (>= 6.0.3)
- Hangfire (>= 1.8.1)
- Hangfire.Dashboard.BasicAuthorization (>= 1.0.2)
- Hangfire.HttpJob (>= 3.7.6)
- Hangfire.HttpJob.Client (>= 1.2.9)
- Hangfire.Redis.StackExchange (>= 1.8.7)
- JWT (>= 10.0.2)
- LogDashboard (>= 1.4.8)
- NPOI (>= 2.6.0)
- Portable.BouncyCastle (>= 1.9.0)
- protobuf-net (>= 3.2.30)
- RestSharp (>= 106.13.0)
- Serilog.AspNetCore (>= 8.0.0)
- SqlSugarCore (>= 5.1.4.154)
- StackExchange.Redis (>= 2.6.111)
- Swashbuckle.AspNetCore (>= 6.5.0)
- Swashbuckle.AspNetCore.Annotations (>= 6.5.0)
- Volo.Abp.AspNetCore (>= 6.0.3)
- Volo.Abp.AspNetCore.Mvc (>= 6.0.3)
- Volo.Abp.Autofac (>= 6.0.3)
- Volo.Abp.AutoMapper (>= 6.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.2.6 | 124 | 11/8/2024 |
2.2.5 | 138 | 10/23/2024 |
2.2.4 | 132 | 10/14/2024 |
2.2.3 | 106 | 9/20/2024 |
2.2.2 | 131 | 9/19/2024 |
2.2.1 | 86 | 9/19/2024 |
2.2.0 | 122 | 9/19/2024 |
2.1.34 | 122 | 9/19/2024 |
2.1.33 | 153 | 6/27/2024 |
2.1.32 | 101 | 6/3/2024 |
2.1.31 | 147 | 5/29/2024 |
2.1.30 | 117 | 5/29/2024 |
2.1.29 | 114 | 5/29/2024 |
2.1.28 | 111 | 5/28/2024 |
2.1.27.2 | 122 | 5/16/2024 |
2.1.27.1 | 94 | 5/13/2024 |
2.1.27 | 74 | 5/13/2024 |
2.1.26 | 251 | 2/23/2024 |
2.1.25 | 132 | 2/5/2024 |
2.1.25-beta | 117 | 2/5/2024 |
2.1.24 | 236 | 2/5/2024 |
2.1.23 | 126 | 1/24/2024 |
2.1.22 | 219 | 1/9/2024 |
2.1.21 | 136 | 1/8/2024 |
2.1.20 | 160 | 12/29/2023 |
2.1.19 | 184 | 12/1/2023 |
2.1.18 | 219 | 11/30/2023 |
2.1.17 | 156 | 11/23/2023 |
2.1.16 | 237 | 11/23/2023 |
2.1.15 | 175 | 11/21/2023 |
2.1.14 | 143 | 11/17/2023 |
2.1.13 | 155 | 11/16/2023 |
2.1.12 | 183 | 11/13/2023 |
2.1.11 | 156 | 11/2/2023 |
2.1.10 | 166 | 10/18/2023 |
2.1.9 | 146 | 9/20/2023 |
2.1.8 | 139 | 9/15/2023 |
2.1.7 | 173 | 9/11/2023 |
2.1.6 | 204 | 9/5/2023 |
2.1.5 | 181 | 8/26/2023 |
2.1.4 | 167 | 8/22/2023 |
2.1.3 | 151 | 8/16/2023 |
2.1.2 | 182 | 8/15/2023 |
2.1.1 | 211 | 8/7/2023 |
2.1.0 | 190 | 8/4/2023 |
2.0.20 | 186 | 8/3/2023 |
2.0.19 | 190 | 8/3/2023 |
2.0.18 | 185 | 7/29/2023 |
2.0.17 | 166 | 7/29/2023 |
2.0.16 | 183 | 7/13/2023 |
2.0.15 | 185 | 7/6/2023 |
2.0.14 | 171 | 7/5/2023 |
2.0.13 | 157 | 6/29/2023 |
2.0.12 | 157 | 6/28/2023 |
2.0.11 | 199 | 6/27/2023 |
2.0.10 | 170 | 6/25/2023 |
2.0.9 | 212 | 6/20/2023 |
2.0.8 | 180 | 6/19/2023 |
2.0.7 | 214 | 6/19/2023 |
2.0.6 | 189 | 6/13/2023 |
2.0.5 | 168 | 6/13/2023 |
2.0.4 | 195 | 6/12/2023 |
2.0.3 | 165 | 6/12/2023 |
2.0.2 | 168 | 6/9/2023 |
2.0.1 | 189 | 6/9/2023 |
2.0.0 | 181 | 6/9/2023 |
1.0.2 | 201 | 6/7/2023 |
1.0.1 | 150 | 6/7/2023 |
1.0.0 | 188 | 6/7/2023 |