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);