added comments

master
Young 7 months ago
parent 1c9c3c3ee2
commit c6a36c055d

@ -1,5 +1,11 @@
namespace Infrastructure.Attributes;
/// <summary>
/// 幂等性Attribute
/// </summary>
/// <param name="parameter">用于获取请求参数的key,比如form或者body参数的名称</param>
/// <param name="seconds">判定时长</param>
/// <param name="message">返回消息</param>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class IdempotencyAttribute(string parameter, int seconds = 5, string message = "invalid request")
: Attribute

@ -3,6 +3,9 @@ using Microsoft.AspNetCore.Mvc;
namespace Infrastructure;
/// <summary>
/// controller基类
/// </summary>
[ApiController]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK)]
@ -38,18 +41,15 @@ public class DefaultControllerBase : ControllerBase
[NonAction]
[ApiExplorerSettings(IgnoreApi = true)]
public static MessageData<PageData<T>> SucceedPage<T>(int page, int dataCount, int pageSize, List<T> data,
int pageCount,
public static MessageData<PageData<T>> SucceedPage<T>(
int page,
int totalItems,
int pageSize,
List<T> data,
int totalPages,
string message = "successful")
{
var pageData = new PageData<T>()
{
Data = data,
TotalPages = pageCount,
PageSize = pageSize,
Page = page,
TotalItems = dataCount,
};
var pageData = new PageData<T>(page, pageSize, totalPages, totalItems, data);
return new MessageData<PageData<T>>(pageData, true, message);
}

@ -1,5 +1,10 @@
namespace Infrastructure.Exceptions;
/// <summary>
/// 返回客户端的友好错误提示
/// </summary>
/// <param name="message">错误信息</param>
/// <param name="code">错误code</param>
public sealed class FriendlyException(string message, int code = 500) : Exception
{
public string? Message { get; set; } = message;

@ -5,6 +5,12 @@ namespace Infrastructure.Extensions;
public static class AuthorizeSetup
{
/// <summary>
/// 添加权限认证权限Policy、Roles从配置中获取
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <returns></returns>
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()

@ -9,6 +9,11 @@ namespace Infrastructure.Extensions;
public static class ControllerSetup
{
/// <summary>
/// 配置controller包含过滤器、json序列化以及模型验证等配置
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddDefaultControllers(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);

@ -2,6 +2,11 @@ namespace Infrastructure.Extensions;
public static class EncryptionSetup
{
/// <summary>
/// 注入Aes加密对称加密服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddAesEncryption(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);

@ -1,10 +1,17 @@
using Infrastructure.Options;
using Infrastructure.Repository;
using StackExchange.Redis;
namespace Infrastructure.Extensions;
public static class RedisSetup
{
/// <summary>
/// 配置redis连接服务,以及redis数据访问仓储
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <returns></returns>
public static IServiceCollection AddDefaultRedis(this IServiceCollection services, IConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(services);
@ -15,6 +22,7 @@ public static class RedisSetup
return services;
}
services.TryAddScoped<IRedisBasketRepository, RedisBasketRepository>();
services.TryAddSingleton<ConnectionMultiplexer>(_ =>
{
var host = configuration["REDIS_HOST"] ?? redisOptions.Host;

@ -4,6 +4,11 @@ namespace Infrastructure.Extensions;
public static class RepositoryContextSetup
{
/// <summary>
/// 配置数据库仓储服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddDefaultRepositoryContext(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);

@ -9,6 +9,13 @@ namespace Infrastructure.Extensions;
public static class SqlSugarSetup
{
/// <summary>
/// 配置sqlsugar ORM连接
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <param name="hostEnvironment"></param>
/// <returns></returns>
public static IServiceCollection AddDefaultSqlSugarSetup(
this IServiceCollection services,
IConfiguration configuration,

@ -2,6 +2,11 @@ namespace Infrastructure.Extensions;
public static class TokenContextSetup
{
/// <summary>
///
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddDefaultTokenContext(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);

@ -4,6 +4,12 @@ namespace Infrastructure.Extensions;
public static class UserContextSetup
{
/// <summary>
/// 配置用户上下文服务 T为主键类型
/// </summary>
/// <param name="services"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IServiceCollection AddDefaultUserContext<T>(this IServiceCollection services) where T : IEquatable<T>
{
ArgumentNullException.ThrowIfNull(services);

@ -6,6 +6,10 @@ using Microsoft.AspNetCore.Mvc.Filters;
namespace Infrastructure.Filters;
/// <summary>
/// controller异常过滤器用于处理已知或未知异常。
/// </summary>
/// <param name="logger"></param>
public class ExceptionsFilter(ILogger<ExceptionsFilter> logger) : IAsyncExceptionFilter
{
public Task OnExceptionAsync(ExceptionContext context)
@ -14,6 +18,7 @@ public class ExceptionsFilter(ILogger<ExceptionsFilter> logger) : IAsyncExceptio
{
return Task.CompletedTask;
}
var message = default(MessageData);
if (context.Exception is FriendlyException fe)
{
@ -32,6 +37,6 @@ public class ExceptionsFilter(ILogger<ExceptionsFilter> logger) : IAsyncExceptio
Content = message.Serialize()
};
context.ExceptionHandled = true;
return Task.CompletedTask;
return Task.CompletedTask;
}
}

@ -8,6 +8,11 @@ using Microsoft.AspNetCore.Mvc;
namespace Infrastructure.Filters;
/// <summary>
/// 请求幂等性过滤器配合redis统一处理需要幂等性的请求。
/// </summary>
/// <param name="logger"></param>
/// <param name="redis"></param>
public class IdempotencyFilter(ILogger<IdempotencyFilter> logger, IRedisBasketRepository redis) : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)

@ -2,21 +2,54 @@
namespace Infrastructure.HttpUserContext;
/// <summary>
/// 用户上下文
/// </summary>
/// <typeparam name="TId"></typeparam>
public interface IUserContext<out TId> where TId : IEquatable<TId>
{
/// <summary>
/// 用户primary key的类型
/// </summary>
TId Id { get; }
/// <summary>
/// 用户名
/// </summary>
string Username { get; }
/// <summary>
/// 名称
/// </summary>
string Name { get; }
/// <summary>
/// 邮箱
/// </summary>
string Email { get; }
/// <summary>
/// 角色id
/// </summary>
string[] RoleIds { get; }
/// <summary>
/// 访问Ip
/// </summary>
string RemoteIpAddress { get; }
JwtTokenInfo GenerateTokenInfo(JwtSecurityToken jwtSecurityToken,double? duration, string schemeName);
/// <summary>
/// 生成Jwt token信息
/// </summary>
/// <param name="jwtSecurityToken"></param>
/// <param name="duration"></param>
/// <param name="schemeName"></param>
/// <returns></returns>
JwtTokenInfo GenerateTokenInfo(JwtSecurityToken jwtSecurityToken, double? duration, string schemeName);
/// <summary>
/// 从当前用户上下文获取claims
/// </summary>
/// <returns></returns>
IList<Claim> GetClaimsFromUserContext();
}

@ -7,9 +7,17 @@ using Microsoft.IdentityModel.Tokens;
namespace Infrastructure.HttpUserContext;
/// <summary>
/// <inheritdoc cref="IUserContext{TId}"/>
/// </summary>
/// <param name="httpContextAccessor"></param>
/// <param name="jwtContext"></param>
/// <param name="encryptionService"></param>
/// <param name="jwtSecurityTokenHandler"></param>
/// <typeparam name="TId"></typeparam>
public class UserContext<TId>(
IHttpContextAccessor httpContextAccessor,
JwtOptions jwtOptions,
JwtContext jwtContext,
IEncryptionService encryptionService,
JwtSecurityTokenHandler jwtSecurityTokenHandler)
: IUserContext<TId> where TId : IEquatable<TId>
@ -35,15 +43,15 @@ public class UserContext<TId>(
{
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<Claim> GetClaimsFromUserContext()
@ -58,7 +66,7 @@ public class UserContext<TId>(
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;

@ -1,5 +1,8 @@
namespace Infrastructure;
/// <summary>
/// 实体类软删除接口用于filter
/// </summary>
public interface IDeletable
{
bool IsDeleted { get; set; }

@ -1,5 +1,11 @@
namespace Infrastructure;
/// <summary>
/// 客户端返回统一封装
/// </summary>
/// <param name="successful"></param>
/// <param name="message"></param>
/// <param name="code"></param>
public class MessageData(bool successful, string message, int code = 500)
{
public bool Successful { get; set; } = successful;

@ -3,6 +3,10 @@ using Microsoft.AspNetCore.Http;
namespace Infrastructure.Middlewares;
/// <summary>
/// 访问路由404自定义中间件
/// </summary>
/// <param name="next"></param>
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());
}
}
}

@ -1,5 +1,8 @@
namespace Infrastructure.Options;
/// <summary>
/// Jwt配置
/// </summary>
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; }

@ -1,5 +1,8 @@
namespace Infrastructure.Options;
/// <summary>
/// rabbitmq链接配置
/// </summary>
public class RabbitMqOptions
{
public string Host { get; set; } = string.Empty;

@ -1,5 +1,8 @@
namespace Infrastructure.Options;
/// <summary>
/// redis连接配置
/// </summary>
public sealed class RedisOptions : OptionsBase
{
public const string Name = "Redis";

@ -1,5 +1,8 @@
namespace Infrastructure.Options;
/// <summary>
/// ORM连接配置
/// </summary>
public sealed class SqlSugarOptions : OptionsBase
{
public const string Name = "SqlSugar";

@ -1,5 +1,8 @@
namespace Infrastructure.Options;
/// <summary>
/// api版本配置
/// </summary>
public class VersionOptions : OptionsBase
{
public const string Name = "Version";

@ -1,27 +1,23 @@
namespace Infrastructure;
public class PageData<T>
/// <summary>
/// 分页数据
/// </summary>
/// <param name="page">当前页</param>
/// <param name="pageSize">当前页数量</param>
/// <param name="totalPages">总页数量</param>
/// <param name="totalItems">总条目数量</param>
/// <param name="data">返回数据</param>
/// <typeparam name="T">实体类型</typeparam>
public class PageData<T>(int page, int pageSize, int totalPages, int totalItems, List<T> data)
{
public PageData()
{
}
public int Page { get; set; } = page;
public PageData(int page, int pageSize, int totalPages, int totalItems, List<T> 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<T> Data { get; set; }
public List<T> Data { get; set; } = data;
}

@ -1,8 +1,10 @@
using Infrastructure.Utils;
using StackExchange.Redis;
using StackExchange.Redis;
namespace Infrastructure.Repository;
/// <summary>
/// redis访问仓储
/// </summary>
public interface IRedisBasketRepository
{
Task<string> GetValue(string key);
@ -46,172 +48,4 @@ public interface IRedisBasketRepository
Task<long> ListDelRangeAsync(string redisKey, string redisValue, long type = 0, int db = -1);
Task ListClearAsync(string redisKey, int db = -1);
}
public class RedisBasketRepository(ILogger<RedisBasketRepository> 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<bool> Exist(string key)
{
return await _database.KeyExistsAsync(key);
}
public async Task<string> 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<bool> SetValues(Dictionary<string, object> 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<TEntity?> Get<TEntity>(string key)
{
var value = await _database.StringGetAsync(key);
if (value.HasValue)
{
var jsonString = Encoding.UTF8.GetString(value);
return jsonString.Deserialize<TEntity>();
}
else
{
return default;
}
}
public async Task<List<T>> GetValues<T>(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<T>(r)).ToList();
}
public async Task<RedisValue[]> ListRangeAsync(string redisKey)
{
return await _database.ListRangeAsync(redisKey);
}
public async Task<long> ListLeftPushAsync(string redisKey, string redisValue, int db = -1)
{
return await _database.ListLeftPushAsync(redisKey, redisValue);
}
public async Task<long> ListRightPushAsync(string redisKey, string redisValue, int db = -1)
{
return await _database.ListRightPushAsync(redisKey, redisValue);
}
public async Task<long> ListRightPushAsync(string redisKey, IEnumerable<string> redisValue, int db = -1)
{
var redislist = redisValue.Select(r => (RedisValue)r).ToArray();
return await _database.ListRightPushAsync(redisKey, redislist);
}
public async Task<T> ListLeftPopAsync<T>(string redisKey, int db = -1) where T : class
{
var value = await _database.ListLeftPopAsync(redisKey);
return SerializeExtension.Deserialize<T>(await _database.ListLeftPopAsync(redisKey));
}
public async Task<T> ListRightPopAsync<T>(string redisKey, int db = -1) where T : class
{
return SerializeExtension.Deserialize<T>(await _database.ListRightPopAsync(redisKey));
}
public async Task<string> ListLeftPopAsync(string redisKey, int db = -1)
{
return await _database.ListLeftPopAsync(redisKey);
}
public async Task<string> ListRightPopAsync(string redisKey, int db = -1)
{
return await _database.ListRightPopAsync(redisKey);
}
public async Task<long> ListLengthAsync(string redisKey, int db = -1)
{
return await _database.ListLengthAsync(redisKey);
}
public async Task<IEnumerable<string>> ListRangeAsync(string redisKey, int db = -1)
{
var result = await _database.ListRangeAsync(redisKey);
return result.Select(o => o.ToString());
}
public async Task<IEnumerable<string>> 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<long> 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);
}
}

@ -3,6 +3,10 @@ using SqlSugar;
namespace Infrastructure.Repository;
/// <summary>
/// 数据库ORM仓储
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IRepositoryBase<T> where T : class, new()
{
ISqlSugarClient DbContext { get; }

@ -3,6 +3,10 @@ using SqlSugar;
namespace Infrastructure.Repository;
/// <summary>
/// 数据库访问层
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IServiceBase<T> where T : class, new()
{
IRepositoryBase<T> DAL { get; }

@ -2,6 +2,9 @@
namespace Infrastructure.Repository;
/// <summary>
/// 工作单元
/// </summary>
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();
}
}
}

@ -0,0 +1,177 @@
using Infrastructure.Utils;
using StackExchange.Redis;
namespace Infrastructure.Repository;
/// <summary>
/// <inheritdoc cref="IRedisBasketRepository"/>
/// </summary>
/// <param name="logger"></param>
/// <param name="redis"></param>
public class RedisBasketRepository(ILogger<RedisBasketRepository> 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<bool> Exist(string key)
{
return await _database.KeyExistsAsync(key);
}
public async Task<string> 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<bool> SetValues(Dictionary<string, object> 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<TEntity?> Get<TEntity>(string key)
{
var value = await _database.StringGetAsync(key);
if (value.HasValue)
{
var jsonString = Encoding.UTF8.GetString(value);
return jsonString.Deserialize<TEntity>();
}
else
{
return default;
}
}
public async Task<List<T>> GetValues<T>(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<T>(r)).ToList();
}
public async Task<RedisValue[]> ListRangeAsync(string redisKey)
{
return await _database.ListRangeAsync(redisKey);
}
public async Task<long> ListLeftPushAsync(string redisKey, string redisValue, int db = -1)
{
return await _database.ListLeftPushAsync(redisKey, redisValue);
}
public async Task<long> ListRightPushAsync(string redisKey, string redisValue, int db = -1)
{
return await _database.ListRightPushAsync(redisKey, redisValue);
}
public async Task<long> ListRightPushAsync(string redisKey, IEnumerable<string> redisValue, int db = -1)
{
var redislist = redisValue.Select(r => (RedisValue)r).ToArray();
return await _database.ListRightPushAsync(redisKey, redislist);
}
public async Task<T> ListLeftPopAsync<T>(string redisKey, int db = -1) where T : class
{
var value = await _database.ListLeftPopAsync(redisKey);
return SerializeExtension.Deserialize<T>(await _database.ListLeftPopAsync(redisKey));
}
public async Task<T> ListRightPopAsync<T>(string redisKey, int db = -1) where T : class
{
return SerializeExtension.Deserialize<T>(await _database.ListRightPopAsync(redisKey));
}
public async Task<string> ListLeftPopAsync(string redisKey, int db = -1)
{
return await _database.ListLeftPopAsync(redisKey);
}
public async Task<string> ListRightPopAsync(string redisKey, int db = -1)
{
return await _database.ListRightPopAsync(redisKey);
}
public async Task<long> ListLengthAsync(string redisKey, int db = -1)
{
return await _database.ListLengthAsync(redisKey);
}
public async Task<IEnumerable<string>> ListRangeAsync(string redisKey, int db = -1)
{
var result = await _database.ListRangeAsync(redisKey);
return result.Select(o => o.ToString());
}
public async Task<IEnumerable<string>> 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<long> 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);
}
}

@ -4,6 +4,11 @@ using SqlSugar.Extensions;
namespace Infrastructure.Repository;
/// <summary>
/// <inheritdoc cref="IRepositoryBase{T}"/>
/// </summary>
/// <param name="context"></param>
/// <typeparam name="T"></typeparam>
public class RepositoryBase<T>(ISqlSugarClient context) : IRepositoryBase<T> where T : class, new()
{
public ISqlSugarClient DbContext => context;

@ -3,6 +3,11 @@ using SqlSugar;
namespace Infrastructure.Repository;
/// <summary>
/// <inheritdoc cref="IServiceBase{T}"/>
/// </summary>
/// <param name="dbContext"></param>
/// <typeparam name="T"></typeparam>
public abstract class ServiceBase<T>(IRepositoryBase<T> dbContext) : IServiceBase<T> where T : class, new()
{
public IRepositoryBase<T> DAL { get; } = dbContext;

@ -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();
}
}
}

@ -5,6 +5,12 @@ using Microsoft.AspNetCore.Http;
namespace Infrastructure.Security;
/// <summary>
/// 用于统一处理验证和授权
/// </summary>
/// <param name="options"></param>
/// <param name="logger"></param>
/// <param name="encoder"></param>
public class DefaultAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,

@ -2,6 +2,11 @@ using Microsoft.IdentityModel.Tokens;
namespace Infrastructure.Security;
/// <summary>
/// 自定义token解密
/// </summary>
/// <param name="encryptionService"></param>
/// <param name="jwtSecurityTokenHandler"></param>
public class DefaultTokenHandler(IEncryptionService encryptionService, JwtSecurityTokenHandler jwtSecurityTokenHandler)
: TokenHandler
{

@ -2,6 +2,9 @@ using System.Security.Cryptography;
namespace Infrastructure.Security;
/// <summary>
/// aes对称加解密服务
/// </summary>
public interface IEncryptionService
{
string Encrypt(string plain, string? aesKey = null);

@ -2,7 +2,14 @@ using Microsoft.IdentityModel.Tokens;
namespace Infrastructure.Security;
public class JwtOptions(
/// <summary>
/// jwt配置上下文
/// </summary>
/// <param name="issuer"></param>
/// <param name="audience"></param>
/// <param name="duration"></param>
/// <param name="credentials"></param>
public class JwtContext(
string issuer,
string audience,
long duration,

@ -1,5 +1,11 @@
namespace Infrastructure.Security;
/// <summary>
/// 返回客户端的jwt信息
/// </summary>
/// <param name="token"></param>
/// <param name="expiredIn"></param>
/// <param name="tokenType"></param>
public class JwtTokenInfo(string token, double expiredIn, string tokenType)
{
public string? Token { get; } = token;

@ -2,8 +2,16 @@ using Microsoft.AspNetCore.Http;
namespace Infrastructure.Utils;
/// <summary>
/// HttpContext扩展
/// </summary>
public static class HttpContextExtension
{
/// <summary>
/// 用于获取用户访问ip
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static string? GetRequestIp(this HttpContext context)
{
var ip = context.GetRequestHeaderValue<string>("X-Forwarded-For");
@ -20,7 +28,14 @@ public static class HttpContextExtension
return ip;
}
/// <summary>
/// 获取header值
/// </summary>
/// <param name="context"></param>
/// <param name="headerName"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T? GetRequestHeaderValue<T>(this HttpContext context, string headerName)
{
if (!context.Request.Headers.TryGetValue(headerName, out var value))

@ -3,6 +3,9 @@ using Newtonsoft.Json.Serialization;
namespace Infrastructure.Utils;
/// <summary>
/// json序列化扩展
/// </summary>
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);

Loading…
Cancel
Save