diff --git a/src/Infrastructure/Attributes/IdempotencyAttribute.cs b/src/Infrastructure/Attributes/IdempotencyAttribute.cs
index f8d83a0..bc2bac1 100644
--- a/src/Infrastructure/Attributes/IdempotencyAttribute.cs
+++ b/src/Infrastructure/Attributes/IdempotencyAttribute.cs
@@ -1,5 +1,11 @@
namespace Infrastructure.Attributes;
+///
+/// 幂等性Attribute
+///
+/// 用于获取请求参数的key,比如form或者body参数的名称
+/// 判定时长
+/// 返回消息
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class IdempotencyAttribute(string parameter, int seconds = 5, string message = "invalid request")
: Attribute
diff --git a/src/Infrastructure/DefaultControllerBase.cs b/src/Infrastructure/DefaultControllerBase.cs
index 09c5f9d..32b4344 100644
--- a/src/Infrastructure/DefaultControllerBase.cs
+++ b/src/Infrastructure/DefaultControllerBase.cs
@@ -3,6 +3,9 @@ using Microsoft.AspNetCore.Mvc;
namespace Infrastructure;
+///
+/// controller基类
+///
[ApiController]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -38,18 +41,15 @@ public class DefaultControllerBase : ControllerBase
[NonAction]
[ApiExplorerSettings(IgnoreApi = true)]
- public static MessageData> SucceedPage(int page, int dataCount, int pageSize, List data,
- int pageCount,
+ public static MessageData> SucceedPage(
+ int page,
+ int totalItems,
+ int pageSize,
+ List data,
+ int totalPages,
string message = "successful")
{
- var pageData = new PageData()
- {
- Data = data,
- TotalPages = pageCount,
- PageSize = pageSize,
- Page = page,
- TotalItems = dataCount,
- };
+ var pageData = new PageData(page, pageSize, totalPages, totalItems, data);
return new MessageData>(pageData, true, message);
}
diff --git a/src/Infrastructure/Exceptions/FriendlyException.cs b/src/Infrastructure/Exceptions/FriendlyException.cs
index bd33cfe..5d3c1c0 100644
--- a/src/Infrastructure/Exceptions/FriendlyException.cs
+++ b/src/Infrastructure/Exceptions/FriendlyException.cs
@@ -1,5 +1,10 @@
namespace Infrastructure.Exceptions;
+///
+/// 返回客户端的友好错误提示
+///
+/// 错误信息
+/// 错误code
public sealed class FriendlyException(string message, int code = 500) : Exception
{
public string? Message { get; set; } = message;
diff --git a/src/Infrastructure/Extensions/AuthorizeSetup.cs b/src/Infrastructure/Extensions/AuthorizeSetup.cs
index 044e889..ead8b96 100644
--- a/src/Infrastructure/Extensions/AuthorizeSetup.cs
+++ b/src/Infrastructure/Extensions/AuthorizeSetup.cs
@@ -5,6 +5,12 @@ namespace Infrastructure.Extensions;
public static class AuthorizeSetup
{
+ ///
+ /// 添加权限认证,权限Policy、Roles从配置中获取
+ ///
+ ///
+ ///
+ ///
public static IServiceCollection AddDefaultAuthorize(this IServiceCollection services, IConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(services);
@@ -21,10 +27,10 @@ public static class AuthorizeSetup
var securityKey = new SymmetricSecurityKey(buffer);
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
- services.AddSingleton(new JwtOptions(
+ services.AddSingleton(new JwtContext(
audienceOptions.Issuer,
audienceOptions.Audience,
- audienceOptions.Expiration,
+ audienceOptions.Duration,
signingCredentials));
services.AddAuthorizationBuilder()
diff --git a/src/Infrastructure/Extensions/ControllerSetup.cs b/src/Infrastructure/Extensions/ControllerSetup.cs
index f0eaba9..5050d8e 100644
--- a/src/Infrastructure/Extensions/ControllerSetup.cs
+++ b/src/Infrastructure/Extensions/ControllerSetup.cs
@@ -9,6 +9,11 @@ namespace Infrastructure.Extensions;
public static class ControllerSetup
{
+ ///
+ /// 配置controller,包含过滤器、json序列化以及模型验证等配置
+ ///
+ ///
+ ///
public static IServiceCollection AddDefaultControllers(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);
diff --git a/src/Infrastructure/Extensions/EncryptionSetup.cs b/src/Infrastructure/Extensions/EncryptionSetup.cs
index 4b52be9..55142ec 100644
--- a/src/Infrastructure/Extensions/EncryptionSetup.cs
+++ b/src/Infrastructure/Extensions/EncryptionSetup.cs
@@ -2,6 +2,11 @@ namespace Infrastructure.Extensions;
public static class EncryptionSetup
{
+ ///
+ /// 注入Aes加密对称加密服务
+ ///
+ ///
+ ///
public static IServiceCollection AddAesEncryption(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);
diff --git a/src/Infrastructure/Extensions/RedisSetup.cs b/src/Infrastructure/Extensions/RedisSetup.cs
index a737ef4..2c15b08 100644
--- a/src/Infrastructure/Extensions/RedisSetup.cs
+++ b/src/Infrastructure/Extensions/RedisSetup.cs
@@ -1,10 +1,17 @@
using Infrastructure.Options;
+using Infrastructure.Repository;
using StackExchange.Redis;
namespace Infrastructure.Extensions;
public static class RedisSetup
{
+ ///
+ /// 配置redis连接服务,以及redis数据访问仓储
+ ///
+ ///
+ ///
+ ///
public static IServiceCollection AddDefaultRedis(this IServiceCollection services, IConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(services);
@@ -15,6 +22,7 @@ public static class RedisSetup
return services;
}
+ services.TryAddScoped();
services.TryAddSingleton(_ =>
{
var host = configuration["REDIS_HOST"] ?? redisOptions.Host;
diff --git a/src/Infrastructure/Extensions/RepositoryContextSetup.cs b/src/Infrastructure/Extensions/RepositoryContextSetup.cs
index 3cc20e5..721cc76 100644
--- a/src/Infrastructure/Extensions/RepositoryContextSetup.cs
+++ b/src/Infrastructure/Extensions/RepositoryContextSetup.cs
@@ -4,6 +4,11 @@ namespace Infrastructure.Extensions;
public static class RepositoryContextSetup
{
+ ///
+ /// 配置数据库仓储服务
+ ///
+ ///
+ ///
public static IServiceCollection AddDefaultRepositoryContext(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);
diff --git a/src/Infrastructure/Extensions/SqlSugarSetup.cs b/src/Infrastructure/Extensions/SqlSugarSetup.cs
index 0975be7..72231b0 100644
--- a/src/Infrastructure/Extensions/SqlSugarSetup.cs
+++ b/src/Infrastructure/Extensions/SqlSugarSetup.cs
@@ -9,6 +9,13 @@ namespace Infrastructure.Extensions;
public static class SqlSugarSetup
{
+ ///
+ /// 配置sqlsugar ORM连接
+ ///
+ ///
+ ///
+ ///
+ ///
public static IServiceCollection AddDefaultSqlSugarSetup(
this IServiceCollection services,
IConfiguration configuration,
diff --git a/src/Infrastructure/Extensions/TokenContextSetup.cs b/src/Infrastructure/Extensions/TokenContextSetup.cs
index 1f305f4..f908cf2 100644
--- a/src/Infrastructure/Extensions/TokenContextSetup.cs
+++ b/src/Infrastructure/Extensions/TokenContextSetup.cs
@@ -2,6 +2,11 @@ namespace Infrastructure.Extensions;
public static class TokenContextSetup
{
+ ///
+ ///
+ ///
+ ///
+ ///
public static IServiceCollection AddDefaultTokenContext(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);
diff --git a/src/Infrastructure/Extensions/UserContextSetup.cs b/src/Infrastructure/Extensions/UserContextSetup.cs
index 37e6b97..c5ffae5 100644
--- a/src/Infrastructure/Extensions/UserContextSetup.cs
+++ b/src/Infrastructure/Extensions/UserContextSetup.cs
@@ -4,6 +4,12 @@ namespace Infrastructure.Extensions;
public static class UserContextSetup
{
+ ///
+ /// 配置用户上下文服务 T为主键类型
+ ///
+ ///
+ ///
+ ///
public static IServiceCollection AddDefaultUserContext(this IServiceCollection services) where T : IEquatable
{
ArgumentNullException.ThrowIfNull(services);
diff --git a/src/Infrastructure/Filters/ExceptionsFilter.cs b/src/Infrastructure/Filters/ExceptionsFilter.cs
index bd3207f..8e03583 100644
--- a/src/Infrastructure/Filters/ExceptionsFilter.cs
+++ b/src/Infrastructure/Filters/ExceptionsFilter.cs
@@ -6,6 +6,10 @@ using Microsoft.AspNetCore.Mvc.Filters;
namespace Infrastructure.Filters;
+///
+/// controller异常过滤器,用于处理已知或未知异常。
+///
+///
public class ExceptionsFilter(ILogger logger) : IAsyncExceptionFilter
{
public Task OnExceptionAsync(ExceptionContext context)
@@ -14,6 +18,7 @@ public class ExceptionsFilter(ILogger logger) : IAsyncExceptio
{
return Task.CompletedTask;
}
+
var message = default(MessageData);
if (context.Exception is FriendlyException fe)
{
@@ -32,6 +37,6 @@ public class ExceptionsFilter(ILogger logger) : IAsyncExceptio
Content = message.Serialize()
};
context.ExceptionHandled = true;
- return Task.CompletedTask;
+ return Task.CompletedTask;
}
}
\ No newline at end of file
diff --git a/src/Infrastructure/Filters/IdempotencyFilter.cs b/src/Infrastructure/Filters/IdempotencyFilter.cs
index c7c468e..5afb641 100644
--- a/src/Infrastructure/Filters/IdempotencyFilter.cs
+++ b/src/Infrastructure/Filters/IdempotencyFilter.cs
@@ -8,6 +8,11 @@ using Microsoft.AspNetCore.Mvc;
namespace Infrastructure.Filters;
+///
+/// 请求幂等性过滤器,配合redis统一处理需要幂等性的请求。
+///
+///
+///
public class IdempotencyFilter(ILogger logger, IRedisBasketRepository redis) : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
diff --git a/src/Infrastructure/HttpUserContext/IUserContext.cs b/src/Infrastructure/HttpUserContext/IUserContext.cs
index dc07605..5adcb82 100644
--- a/src/Infrastructure/HttpUserContext/IUserContext.cs
+++ b/src/Infrastructure/HttpUserContext/IUserContext.cs
@@ -2,21 +2,54 @@
namespace Infrastructure.HttpUserContext;
+///
+/// 用户上下文
+///
+///
public interface IUserContext where TId : IEquatable
{
+ ///
+ /// 用户primary key的类型
+ ///
TId Id { get; }
+ ///
+ /// 用户名
+ ///
string Username { get; }
+ ///
+ /// 名称
+ ///
string Name { get; }
+ ///
+ /// 邮箱
+ ///
string Email { get; }
+ ///
+ /// 角色id
+ ///
string[] RoleIds { get; }
+ ///
+ /// 访问Ip
+ ///
string RemoteIpAddress { get; }
- JwtTokenInfo GenerateTokenInfo(JwtSecurityToken jwtSecurityToken,double? duration, string schemeName);
-
+ ///
+ /// 生成Jwt token信息
+ ///
+ ///
+ ///
+ ///
+ ///
+ JwtTokenInfo GenerateTokenInfo(JwtSecurityToken jwtSecurityToken, double? duration, string schemeName);
+
+ ///
+ /// 从当前用户上下文获取claims
+ ///
+ ///
IList GetClaimsFromUserContext();
}
\ No newline at end of file
diff --git a/src/Infrastructure/HttpUserContext/UserContext.cs b/src/Infrastructure/HttpUserContext/UserContext.cs
index 5082a5b..cea4deb 100644
--- a/src/Infrastructure/HttpUserContext/UserContext.cs
+++ b/src/Infrastructure/HttpUserContext/UserContext.cs
@@ -7,9 +7,17 @@ using Microsoft.IdentityModel.Tokens;
namespace Infrastructure.HttpUserContext;
+///
+///
+///
+///
+///
+///
+///
+///
public class UserContext(
IHttpContextAccessor httpContextAccessor,
- JwtOptions jwtOptions,
+ JwtContext jwtContext,
IEncryptionService encryptionService,
JwtSecurityTokenHandler jwtSecurityTokenHandler)
: IUserContext where TId : IEquatable
@@ -35,15 +43,15 @@ public class UserContext(
{
var claims = GetClaimsFromUserContext();
securityToken ??= new JwtSecurityToken(
- issuer: jwtOptions.Issuer,
- audience: jwtOptions.Audience,
+ issuer: jwtContext.Issuer,
+ audience: jwtContext.Audience,
claims: claims,
notBefore: DateTime.Now,
- expires: DateTime.Now.AddSeconds(jwtOptions.Duration),
- signingCredentials: jwtOptions.SigningCredentials);
+ expires: DateTime.Now.AddSeconds(jwtContext.Duration),
+ signingCredentials: jwtContext.SigningCredentials);
var token = jwtSecurityTokenHandler.WriteToken(securityToken);
token = encryptionService.Encrypt(token);
- return new JwtTokenInfo(token, duration ?? jwtOptions.Duration, schemeName);
+ return new JwtTokenInfo(token, duration ?? jwtContext.Duration, schemeName);
}
public IList GetClaimsFromUserContext()
@@ -58,7 +66,7 @@ public class UserContext(
EpochTime.GetIntDate(DateTime.Now).ToString(CultureInfo.InvariantCulture),
ClaimValueTypes.Integer64),
new(JwtRegisteredClaimNames.Exp,
- TimeSpan.FromSeconds(jwtOptions.Duration).ToString())
+ TimeSpan.FromSeconds(jwtContext.Duration).ToString())
};
claims.AddRange(RoleIds.Select(rId => new Claim(ClaimTypes.Role, rId)));
return claims;
diff --git a/src/Infrastructure/IDeleteable.cs b/src/Infrastructure/IDeleteable.cs
index 427d7b4..86ae522 100644
--- a/src/Infrastructure/IDeleteable.cs
+++ b/src/Infrastructure/IDeleteable.cs
@@ -1,5 +1,8 @@
namespace Infrastructure;
+///
+/// 实体类软删除接口,用于filter
+///
public interface IDeletable
{
bool IsDeleted { get; set; }
diff --git a/src/Infrastructure/MessageData.cs b/src/Infrastructure/MessageData.cs
index 4140bb3..8e13703 100644
--- a/src/Infrastructure/MessageData.cs
+++ b/src/Infrastructure/MessageData.cs
@@ -1,5 +1,11 @@
namespace Infrastructure;
+///
+/// 客户端返回统一封装
+///
+///
+///
+///
public class MessageData(bool successful, string message, int code = 500)
{
public bool Successful { get; set; } = successful;
diff --git a/src/Infrastructure/Middlewares/NotFoundMiddleware.cs b/src/Infrastructure/Middlewares/NotFoundMiddleware.cs
index 1c80c93..70399e4 100644
--- a/src/Infrastructure/Middlewares/NotFoundMiddleware.cs
+++ b/src/Infrastructure/Middlewares/NotFoundMiddleware.cs
@@ -3,6 +3,10 @@ using Microsoft.AspNetCore.Http;
namespace Infrastructure.Middlewares;
+///
+/// 访问路由404自定义中间件
+///
+///
public class NotFoundMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
@@ -12,10 +16,10 @@ public class NotFoundMiddleware(RequestDelegate next)
if (context.Response.StatusCode == StatusCodes.Status404NotFound)
{
var path = context.Request.Path.Value;
- var message=new MessageData(false,$"request path: {path} not found",404);
+ var message = new MessageData(false, $"request path: {path} not found", 404);
context.Response.ContentType = "application/json";
context.Response.StatusCode = StatusCodes.Status200OK;
- await context.Response.WriteAsync(message.Serialize());
+ await context.Response.WriteAsync(message.Serialize());
}
}
}
\ No newline at end of file
diff --git a/src/Infrastructure/Options/AudienceOptions.cs b/src/Infrastructure/Options/AudienceOptions.cs
index 08c12f7..4979141 100644
--- a/src/Infrastructure/Options/AudienceOptions.cs
+++ b/src/Infrastructure/Options/AudienceOptions.cs
@@ -1,5 +1,8 @@
namespace Infrastructure.Options;
+///
+/// Jwt配置
+///
public sealed class AudienceOptions : OptionsBase
{
public const string Name = "Audience";
@@ -10,7 +13,7 @@ public sealed class AudienceOptions : OptionsBase
public string Secret { get; set; }
- public int Expiration { get; set; }
+ public int Duration { get; set; }
public string? Policy { get; set; }
diff --git a/src/Infrastructure/Options/RabbitMqOptions.cs b/src/Infrastructure/Options/RabbitMqOptions.cs
index c9abc5d..3c6eaa4 100644
--- a/src/Infrastructure/Options/RabbitMqOptions.cs
+++ b/src/Infrastructure/Options/RabbitMqOptions.cs
@@ -1,5 +1,8 @@
namespace Infrastructure.Options;
+///
+/// rabbitmq链接配置
+///
public class RabbitMqOptions
{
public string Host { get; set; } = string.Empty;
diff --git a/src/Infrastructure/Options/RedisOptions.cs b/src/Infrastructure/Options/RedisOptions.cs
index 6cbe7e3..d19fdc8 100644
--- a/src/Infrastructure/Options/RedisOptions.cs
+++ b/src/Infrastructure/Options/RedisOptions.cs
@@ -1,5 +1,8 @@
namespace Infrastructure.Options;
+///
+/// redis连接配置
+///
public sealed class RedisOptions : OptionsBase
{
public const string Name = "Redis";
diff --git a/src/Infrastructure/Options/SqlSugarOptions.cs b/src/Infrastructure/Options/SqlSugarOptions.cs
index 04b189b..4a05f10 100644
--- a/src/Infrastructure/Options/SqlSugarOptions.cs
+++ b/src/Infrastructure/Options/SqlSugarOptions.cs
@@ -1,5 +1,8 @@
namespace Infrastructure.Options;
+///
+/// ORM连接配置
+///
public sealed class SqlSugarOptions : OptionsBase
{
public const string Name = "SqlSugar";
diff --git a/src/Infrastructure/Options/VersionOptions.cs b/src/Infrastructure/Options/VersionOptions.cs
index 6e8fd68..738e039 100644
--- a/src/Infrastructure/Options/VersionOptions.cs
+++ b/src/Infrastructure/Options/VersionOptions.cs
@@ -1,5 +1,8 @@
namespace Infrastructure.Options;
+///
+/// api版本配置
+///
public class VersionOptions : OptionsBase
{
public const string Name = "Version";
diff --git a/src/Infrastructure/PageData.cs b/src/Infrastructure/PageData.cs
index ffaf742..2402d80 100644
--- a/src/Infrastructure/PageData.cs
+++ b/src/Infrastructure/PageData.cs
@@ -1,27 +1,23 @@
namespace Infrastructure;
-public class PageData
+///
+/// 分页数据
+///
+/// 当前页
+/// 当前页数量
+/// 总页数量
+/// 总条目数量
+/// 返回数据
+/// 实体类型
+public class PageData(int page, int pageSize, int totalPages, int totalItems, List data)
{
- public PageData()
- {
- }
+ public int Page { get; set; } = page;
- public PageData(int page, int pageSize, int totalPages, int totalItems, List data)
- {
- Page = page;
- PageSize = pageSize;
- TotalItems = totalItems;
- TotalPages = totalPages;
- Data = data;
- }
+ public int PageSize { get; set; } = pageSize;
- public int Page { get; set; }
+ public int TotalPages { get; set; } = totalPages;
- public int PageSize { get; set; }
+ public int TotalItems { get; set; } = totalItems;
- public int TotalPages { get; set; }
-
- public int TotalItems { get; set; }
-
- public List Data { get; set; }
+ public List Data { get; set; } = data;
}
\ No newline at end of file
diff --git a/src/Infrastructure/Repository/IRedisBasketRepository.cs b/src/Infrastructure/Repository/IRedisBasketRepository.cs
index e5581df..8508d43 100644
--- a/src/Infrastructure/Repository/IRedisBasketRepository.cs
+++ b/src/Infrastructure/Repository/IRedisBasketRepository.cs
@@ -1,8 +1,10 @@
-using Infrastructure.Utils;
-using StackExchange.Redis;
+using StackExchange.Redis;
namespace Infrastructure.Repository;
+///
+/// redis访问仓储
+///
public interface IRedisBasketRepository
{
Task GetValue(string key);
@@ -46,172 +48,4 @@ public interface IRedisBasketRepository
Task ListDelRangeAsync(string redisKey, string redisValue, long type = 0, int db = -1);
Task ListClearAsync(string redisKey, int db = -1);
-}
-
-public class RedisBasketRepository(ILogger logger, ConnectionMultiplexer redis)
- : IRedisBasketRepository
-{
- private readonly IDatabase _database = redis.GetDatabase();
-
- private IServer GetServer()
- {
- var endpoint = redis.GetEndPoints();
- return redis.GetServer(endpoint.First());
- }
-
- public async Task Clear()
- {
- foreach (var endPoint in redis.GetEndPoints())
- {
- var server = GetServer();
- foreach (var key in server.Keys())
- {
- await _database.KeyDeleteAsync(key);
- }
- }
- }
-
- public async Task Exist(string key)
- {
- return await _database.KeyExistsAsync(key);
- }
-
- public async Task GetValue(string key)
- {
- return await _database.StringGetAsync(key);
- }
-
- public async Task Remove(string key)
- {
- await _database.KeyDeleteAsync(key);
- }
-
- public async Task Set(string key, object value, TimeSpan cacheTime)
- {
- if (value != null)
- {
- if (value is string cacheValue)
- {
- await _database.StringSetAsync(key, cacheValue, cacheTime);
- }
- else
- {
- var jsonString = value.Serialize();
- var buffer = Encoding.UTF8.GetBytes(jsonString);
- await _database.StringSetAsync(key, buffer, cacheTime);
- }
- }
- }
-
- public async Task SetValues(Dictionary valuePairs, TimeSpan cacheTime)
- {
- var transaction = _database.CreateTransaction();
- foreach (var pair in valuePairs)
- {
- if (pair.Value is string value)
- {
- await _database.StringSetAsync(pair.Key, value, cacheTime);
- }
- else
- {
- var jsonString = pair.Value.Serialize();
- var buffer = Encoding.UTF8.GetBytes(jsonString);
- await _database.StringSetAsync(pair.Key, buffer, cacheTime);
- }
- }
-
- return await transaction.ExecuteAsync();
- }
-
- public async Task Get(string key)
- {
- var value = await _database.StringGetAsync(key);
- if (value.HasValue)
- {
- var jsonString = Encoding.UTF8.GetString(value);
- return jsonString.Deserialize();
- }
- else
- {
- return default;
- }
- }
-
- public async Task> GetValues(string[] keys) where T : class
- {
- var redisKeys = keys.Select(k => new RedisKey(k)).ToArray();
- var redisValues = await _database.StringGetAsync(redisKeys);
-
- return redisValues.Where(v => v.HasValue).Select(r => SerializeExtension.Deserialize(r)).ToList();
- }
-
- public async Task ListRangeAsync(string redisKey)
- {
- return await _database.ListRangeAsync(redisKey);
- }
-
- public async Task ListLeftPushAsync(string redisKey, string redisValue, int db = -1)
- {
- return await _database.ListLeftPushAsync(redisKey, redisValue);
- }
-
- public async Task ListRightPushAsync(string redisKey, string redisValue, int db = -1)
- {
- return await _database.ListRightPushAsync(redisKey, redisValue);
- }
-
- public async Task ListRightPushAsync(string redisKey, IEnumerable redisValue, int db = -1)
- {
- var redislist = redisValue.Select(r => (RedisValue)r).ToArray();
- return await _database.ListRightPushAsync(redisKey, redislist);
- }
-
- public async Task ListLeftPopAsync(string redisKey, int db = -1) where T : class
- {
- var value = await _database.ListLeftPopAsync(redisKey);
-
- return SerializeExtension.Deserialize(await _database.ListLeftPopAsync(redisKey));
- }
-
- public async Task ListRightPopAsync(string redisKey, int db = -1) where T : class
- {
- return SerializeExtension.Deserialize(await _database.ListRightPopAsync(redisKey));
- }
-
- public async Task ListLeftPopAsync(string redisKey, int db = -1)
- {
- return await _database.ListLeftPopAsync(redisKey);
- }
-
- public async Task ListRightPopAsync(string redisKey, int db = -1)
- {
- return await _database.ListRightPopAsync(redisKey);
- }
-
- public async Task ListLengthAsync(string redisKey, int db = -1)
- {
- return await _database.ListLengthAsync(redisKey);
- }
-
- public async Task> ListRangeAsync(string redisKey, int db = -1)
- {
- var result = await _database.ListRangeAsync(redisKey);
- return result.Select(o => o.ToString());
- }
-
- public async Task> ListRangeAsync(string redisKey, int start, int stop, int db = -1)
- {
- var result = await _database.ListRangeAsync(redisKey, start, stop);
- return result.Select(o => o.ToString());
- }
-
- public async Task ListDelRangeAsync(string redisKey, string redisValue, long type = 0, int db = -1)
- {
- return await _database.ListRemoveAsync(redisKey, redisValue, type);
- }
-
- public async Task ListClearAsync(string redisKey, int db = -1)
- {
- await _database.ListTrimAsync(redisKey, 1, 0);
- }
}
\ No newline at end of file
diff --git a/src/Infrastructure/Repository/IRepositoryBase.cs b/src/Infrastructure/Repository/IRepositoryBase.cs
index b93880d..7fc690b 100644
--- a/src/Infrastructure/Repository/IRepositoryBase.cs
+++ b/src/Infrastructure/Repository/IRepositoryBase.cs
@@ -3,6 +3,10 @@ using SqlSugar;
namespace Infrastructure.Repository;
+///
+/// 数据库ORM仓储
+///
+///
public interface IRepositoryBase where T : class, new()
{
ISqlSugarClient DbContext { get; }
diff --git a/src/Infrastructure/Repository/IServiceBase.cs b/src/Infrastructure/Repository/IServiceBase.cs
index 4b4abf7..1541c19 100644
--- a/src/Infrastructure/Repository/IServiceBase.cs
+++ b/src/Infrastructure/Repository/IServiceBase.cs
@@ -3,6 +3,10 @@ using SqlSugar;
namespace Infrastructure.Repository;
+///
+/// 数据库访问层
+///
+///
public interface IServiceBase where T : class, new()
{
IRepositoryBase DAL { get; }
diff --git a/src/Infrastructure/Repository/IUnitOfWork.cs b/src/Infrastructure/Repository/IUnitOfWork.cs
index bb01ae1..06092c0 100644
--- a/src/Infrastructure/Repository/IUnitOfWork.cs
+++ b/src/Infrastructure/Repository/IUnitOfWork.cs
@@ -2,6 +2,9 @@
namespace Infrastructure.Repository;
+///
+/// 工作单元
+///
public interface IUnitOfWork
{
SqlSugarScope DbClient { get; }
@@ -11,61 +14,4 @@ public interface IUnitOfWork
void CommitTransaction();
void RollbackTransaction();
-}
-
-public class UnitOfWork : IUnitOfWork
-{
- private int _count;
-
- private readonly SqlSugarScope? _dbClient;
-
- public SqlSugarScope DbClient => _dbClient!;
-
- public UnitOfWork(ISqlSugarClient sqlSugarClient)
- {
- if (sqlSugarClient is SqlSugarScope scope)
- {
- _dbClient = scope;
- }
- }
-
- public void BeginTransaction()
- {
- lock (this)
- {
- _count++;
- _dbClient?.BeginTran();
- }
- }
-
- public void CommitTransaction()
- {
- lock (this)
- {
- _count--;
- if (_count != 0)
- {
- return;
- }
-
- try
- {
- _dbClient?.CommitTran();
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- _dbClient?.RollbackTran();
- }
- }
- }
-
- public void RollbackTransaction()
- {
- lock (this)
- {
- _count--;
- _dbClient?.RollbackTran();
- }
- }
}
\ No newline at end of file
diff --git a/src/Infrastructure/Repository/RedisBasketRepository.cs b/src/Infrastructure/Repository/RedisBasketRepository.cs
new file mode 100644
index 0000000..9f82964
--- /dev/null
+++ b/src/Infrastructure/Repository/RedisBasketRepository.cs
@@ -0,0 +1,177 @@
+using Infrastructure.Utils;
+using StackExchange.Redis;
+
+namespace Infrastructure.Repository;
+
+///
+///
+///
+///
+///
+public class RedisBasketRepository(ILogger logger, ConnectionMultiplexer redis)
+ : IRedisBasketRepository
+{
+ private readonly IDatabase _database = redis.GetDatabase();
+
+ private IServer GetServer()
+ {
+ var endpoint = redis.GetEndPoints();
+ return redis.GetServer(endpoint.First());
+ }
+
+ public async Task Clear()
+ {
+ foreach (var endPoint in redis.GetEndPoints())
+ {
+ var server = GetServer();
+ foreach (var key in server.Keys())
+ {
+ await _database.KeyDeleteAsync(key);
+ }
+ }
+ }
+
+ public async Task Exist(string key)
+ {
+ return await _database.KeyExistsAsync(key);
+ }
+
+ public async Task GetValue(string key)
+ {
+ return await _database.StringGetAsync(key);
+ }
+
+ public async Task Remove(string key)
+ {
+ await _database.KeyDeleteAsync(key);
+ }
+
+ public async Task Set(string key, object value, TimeSpan cacheTime)
+ {
+ if (value != null)
+ {
+ if (value is string cacheValue)
+ {
+ await _database.StringSetAsync(key, cacheValue, cacheTime);
+ }
+ else
+ {
+ var jsonString = value.Serialize();
+ var buffer = Encoding.UTF8.GetBytes(jsonString);
+ await _database.StringSetAsync(key, buffer, cacheTime);
+ }
+ }
+ }
+
+ public async Task SetValues(Dictionary valuePairs, TimeSpan cacheTime)
+ {
+ var transaction = _database.CreateTransaction();
+ foreach (var pair in valuePairs)
+ {
+ if (pair.Value is string value)
+ {
+ await _database.StringSetAsync(pair.Key, value, cacheTime);
+ }
+ else
+ {
+ var jsonString = pair.Value.Serialize();
+ var buffer = Encoding.UTF8.GetBytes(jsonString);
+ await _database.StringSetAsync(pair.Key, buffer, cacheTime);
+ }
+ }
+
+ return await transaction.ExecuteAsync();
+ }
+
+ public async Task Get(string key)
+ {
+ var value = await _database.StringGetAsync(key);
+ if (value.HasValue)
+ {
+ var jsonString = Encoding.UTF8.GetString(value);
+ return jsonString.Deserialize();
+ }
+ else
+ {
+ return default;
+ }
+ }
+
+ public async Task> GetValues(string[] keys) where T : class
+ {
+ var redisKeys = keys.Select(k => new RedisKey(k)).ToArray();
+ var redisValues = await _database.StringGetAsync(redisKeys);
+
+ return redisValues.Where(v => v.HasValue).Select(r => SerializeExtension.Deserialize(r)).ToList();
+ }
+
+ public async Task ListRangeAsync(string redisKey)
+ {
+ return await _database.ListRangeAsync(redisKey);
+ }
+
+ public async Task ListLeftPushAsync(string redisKey, string redisValue, int db = -1)
+ {
+ return await _database.ListLeftPushAsync(redisKey, redisValue);
+ }
+
+ public async Task ListRightPushAsync(string redisKey, string redisValue, int db = -1)
+ {
+ return await _database.ListRightPushAsync(redisKey, redisValue);
+ }
+
+ public async Task ListRightPushAsync(string redisKey, IEnumerable redisValue, int db = -1)
+ {
+ var redislist = redisValue.Select(r => (RedisValue)r).ToArray();
+ return await _database.ListRightPushAsync(redisKey, redislist);
+ }
+
+ public async Task ListLeftPopAsync(string redisKey, int db = -1) where T : class
+ {
+ var value = await _database.ListLeftPopAsync(redisKey);
+
+ return SerializeExtension.Deserialize(await _database.ListLeftPopAsync(redisKey));
+ }
+
+ public async Task ListRightPopAsync(string redisKey, int db = -1) where T : class
+ {
+ return SerializeExtension.Deserialize(await _database.ListRightPopAsync(redisKey));
+ }
+
+ public async Task ListLeftPopAsync(string redisKey, int db = -1)
+ {
+ return await _database.ListLeftPopAsync(redisKey);
+ }
+
+ public async Task ListRightPopAsync(string redisKey, int db = -1)
+ {
+ return await _database.ListRightPopAsync(redisKey);
+ }
+
+ public async Task ListLengthAsync(string redisKey, int db = -1)
+ {
+ return await _database.ListLengthAsync(redisKey);
+ }
+
+ public async Task> ListRangeAsync(string redisKey, int db = -1)
+ {
+ var result = await _database.ListRangeAsync(redisKey);
+ return result.Select(o => o.ToString());
+ }
+
+ public async Task> ListRangeAsync(string redisKey, int start, int stop, int db = -1)
+ {
+ var result = await _database.ListRangeAsync(redisKey, start, stop);
+ return result.Select(o => o.ToString());
+ }
+
+ public async Task ListDelRangeAsync(string redisKey, string redisValue, long type = 0, int db = -1)
+ {
+ return await _database.ListRemoveAsync(redisKey, redisValue, type);
+ }
+
+ public async Task ListClearAsync(string redisKey, int db = -1)
+ {
+ await _database.ListTrimAsync(redisKey, 1, 0);
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/Repository/RepositoryBase.cs b/src/Infrastructure/Repository/RepositoryBase.cs
index 3c71fa5..7d3c96a 100644
--- a/src/Infrastructure/Repository/RepositoryBase.cs
+++ b/src/Infrastructure/Repository/RepositoryBase.cs
@@ -4,6 +4,11 @@ using SqlSugar.Extensions;
namespace Infrastructure.Repository;
+///
+///
+///
+///
+///
public class RepositoryBase(ISqlSugarClient context) : IRepositoryBase where T : class, new()
{
public ISqlSugarClient DbContext => context;
diff --git a/src/Infrastructure/Repository/ServiceBase.cs b/src/Infrastructure/Repository/ServiceBase.cs
index 3946393..3a9f3ef 100644
--- a/src/Infrastructure/Repository/ServiceBase.cs
+++ b/src/Infrastructure/Repository/ServiceBase.cs
@@ -3,6 +3,11 @@ using SqlSugar;
namespace Infrastructure.Repository;
+///
+///
+///
+///
+///
public abstract class ServiceBase(IRepositoryBase dbContext) : IServiceBase where T : class, new()
{
public IRepositoryBase DAL { get; } = dbContext;
diff --git a/src/Infrastructure/Repository/UnitOfWork.cs b/src/Infrastructure/Repository/UnitOfWork.cs
new file mode 100644
index 0000000..745d996
--- /dev/null
+++ b/src/Infrastructure/Repository/UnitOfWork.cs
@@ -0,0 +1,60 @@
+using SqlSugar;
+
+namespace Infrastructure.Repository;
+
+public class UnitOfWork : IUnitOfWork
+{
+ private int _count;
+
+ private readonly SqlSugarScope? _dbClient;
+
+ public SqlSugarScope DbClient => _dbClient!;
+
+ public UnitOfWork(ISqlSugarClient sqlSugarClient)
+ {
+ if (sqlSugarClient is SqlSugarScope scope)
+ {
+ _dbClient = scope;
+ }
+ }
+
+ public void BeginTransaction()
+ {
+ lock (this)
+ {
+ _count++;
+ _dbClient?.BeginTran();
+ }
+ }
+
+ public void CommitTransaction()
+ {
+ lock (this)
+ {
+ _count--;
+ if (_count != 0)
+ {
+ return;
+ }
+
+ try
+ {
+ _dbClient?.CommitTran();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ _dbClient?.RollbackTran();
+ }
+ }
+ }
+
+ public void RollbackTransaction()
+ {
+ lock (this)
+ {
+ _count--;
+ _dbClient?.RollbackTran();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/Security/DefaultAuthenticationHandler.cs b/src/Infrastructure/Security/DefaultAuthenticationHandler.cs
index 7202829..331553b 100644
--- a/src/Infrastructure/Security/DefaultAuthenticationHandler.cs
+++ b/src/Infrastructure/Security/DefaultAuthenticationHandler.cs
@@ -5,6 +5,12 @@ using Microsoft.AspNetCore.Http;
namespace Infrastructure.Security;
+///
+/// 用于统一处理验证和授权
+///
+///
+///
+///
public class DefaultAuthenticationHandler(
IOptionsMonitor options,
ILoggerFactory logger,
diff --git a/src/Infrastructure/Security/DefaultTokenHandler.cs b/src/Infrastructure/Security/DefaultTokenHandler.cs
index 05a1395..03a595e 100644
--- a/src/Infrastructure/Security/DefaultTokenHandler.cs
+++ b/src/Infrastructure/Security/DefaultTokenHandler.cs
@@ -2,6 +2,11 @@ using Microsoft.IdentityModel.Tokens;
namespace Infrastructure.Security;
+///
+/// 自定义token解密
+///
+///
+///
public class DefaultTokenHandler(IEncryptionService encryptionService, JwtSecurityTokenHandler jwtSecurityTokenHandler)
: TokenHandler
{
diff --git a/src/Infrastructure/Security/IEncryptionService.cs b/src/Infrastructure/Security/IEncryptionService.cs
index fa55a99..5fda4c8 100644
--- a/src/Infrastructure/Security/IEncryptionService.cs
+++ b/src/Infrastructure/Security/IEncryptionService.cs
@@ -2,6 +2,9 @@ using System.Security.Cryptography;
namespace Infrastructure.Security;
+///
+/// aes对称加解密服务
+///
public interface IEncryptionService
{
string Encrypt(string plain, string? aesKey = null);
diff --git a/src/Infrastructure/Security/JwtOptions.cs b/src/Infrastructure/Security/JwtContext.cs
similarity index 63%
rename from src/Infrastructure/Security/JwtOptions.cs
rename to src/Infrastructure/Security/JwtContext.cs
index e646178..82e760f 100644
--- a/src/Infrastructure/Security/JwtOptions.cs
+++ b/src/Infrastructure/Security/JwtContext.cs
@@ -2,7 +2,14 @@ using Microsoft.IdentityModel.Tokens;
namespace Infrastructure.Security;
-public class JwtOptions(
+///
+/// jwt配置上下文
+///
+///
+///
+///
+///
+public class JwtContext(
string issuer,
string audience,
long duration,
diff --git a/src/Infrastructure/Security/JwtTokenInfo.cs b/src/Infrastructure/Security/JwtTokenInfo.cs
index 8404a98..a97d907 100644
--- a/src/Infrastructure/Security/JwtTokenInfo.cs
+++ b/src/Infrastructure/Security/JwtTokenInfo.cs
@@ -1,5 +1,11 @@
namespace Infrastructure.Security;
+///
+/// 返回客户端的jwt信息
+///
+///
+///
+///
public class JwtTokenInfo(string token, double expiredIn, string tokenType)
{
public string? Token { get; } = token;
diff --git a/src/Infrastructure/Utils/HttpContextExtension.cs b/src/Infrastructure/Utils/HttpContextExtension.cs
index 4d7ec90..91c238d 100644
--- a/src/Infrastructure/Utils/HttpContextExtension.cs
+++ b/src/Infrastructure/Utils/HttpContextExtension.cs
@@ -2,8 +2,16 @@ using Microsoft.AspNetCore.Http;
namespace Infrastructure.Utils;
+///
+/// HttpContext扩展
+///
public static class HttpContextExtension
{
+ ///
+ /// 用于获取用户访问ip
+ ///
+ ///
+ ///
public static string? GetRequestIp(this HttpContext context)
{
var ip = context.GetRequestHeaderValue("X-Forwarded-For");
@@ -20,7 +28,14 @@ public static class HttpContextExtension
return ip;
}
-
+
+ ///
+ /// 获取header值
+ ///
+ ///
+ ///
+ ///
+ ///
public static T? GetRequestHeaderValue(this HttpContext context, string headerName)
{
if (!context.Request.Headers.TryGetValue(headerName, out var value))
diff --git a/src/Infrastructure/Utils/SerializeExtension.cs b/src/Infrastructure/Utils/SerializeExtension.cs
index 332429d..a839fa7 100644
--- a/src/Infrastructure/Utils/SerializeExtension.cs
+++ b/src/Infrastructure/Utils/SerializeExtension.cs
@@ -3,6 +3,9 @@ using Newtonsoft.Json.Serialization;
namespace Infrastructure.Utils;
+///
+/// json序列化扩展
+///
public static class SerializeExtension
{
static SerializeExtension()
@@ -16,6 +19,7 @@ public static class SerializeExtension
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
}
+
public static string Serialize(this object obj)
{
return JsonConvert.SerializeObject(obj);