From 3e07ca822abb2a7a52d88209b9382bef40ba9c8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com>
Date: Sun, 23 Feb 2025 03:06:06 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20ai+=E4=BA=BA=E5=B7=A5=E9=87=8D?=
=?UTF-8?q?=E6=9E=84=E4=BC=98=E5=8C=96=20framework?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Builder/ApiInfoBuilderExtensions.cs | 18 +-
.../Builder/SwaggerBuilderExtensons.cs | 100 +++--
.../Middlewares/ApiInfoMiddleware.cs | 54 ++-
.../SwaggerAddExtensions.cs | 254 +++++++-----
.../Mvc/YiConventionalRouteBuilder.cs | 152 +++++---
.../Mvc/YiServiceConvention.cs | 148 ++++---
.../RealIpHttpContextWebClientInfoProvider.cs | 41 +-
.../RemoteServiceSuccessInfo.cs | 62 +--
.../YiFrameworkAspNetCoreModule.cs | 17 +-
.../UnitOfWorkHangfireFilter.cs | 44 ++-
...ramework.BackgroundWorkers.Hangfire.csproj | 1 +
...rameworkBackgroundWorkersHangfireModule.cs | 63 ++-
.../YiHangfireConventionalRegistrar.cs | 26 +-
.../YiTokenAuthorizationFilter.cs | 187 +++++----
.../YiDistributedCacheKeyNormalizer.cs | 33 +-
.../YiFrameworkCachingFreeRedisModule.cs | 52 ++-
.../Yi.Framework.Core/Data/IOrderNum.cs | 13 +
.../Yi.Framework.Core/Data/IState.cs | 15 +-
.../Yi.Framework.Core/Enums/FileTypeEnum.cs | 35 +-
.../Yi.Framework.Core/Enums/OrderByEnum.cs | 18 +-
.../Enums/QueryOperatorEnum.cs | 74 ++--
.../Yi.Framework.Core/Enums/ResultCodeEnum.cs | 25 +-
.../Extensions/HttpContextExtensions.cs | 131 ++++---
.../Json/DatetimeJsonConverter.cs | 35 +-
.../Modularity/YiModuleManager.cs | 63 ++-
.../YiFrameworkCoreModule.cs | 22 +-
.../IDeletesAppService.cs | 11 +-
.../IPageTimeResultRequestDto.cs | 10 +
.../IPagedAllResultRequestDto.cs | 3 +
.../IYiCrudAppService.cs | 25 +-
.../PagedAllResultRequestDto.cs | 32 +-
...iFrameworkDddApplicationContractsModule.cs | 3 +
.../YiCacheCrudAppService.cs | 123 +++---
.../YiCrudAppService.cs | 169 +++++---
.../YiFrameworkDddApplicationModule.cs | 26 +-
.../MapsterAutoObjectMappingProvider.cs | 24 +-
.../MapsterObjectMapper.cs | 41 +-
.../YiFrameworkMapsterModule.cs | 24 +-
.../DbConnOptions.cs | 22 +-
.../DefaultTenantTableAttribute.cs | 13 +-
.../ISqlSugarDbContext.cs | 7 +-
.../ISqlSugarDbContextDependencies.cs | 42 +-
.../ISqlSugarRepository.cs | 256 ++++++++++---
.../ISugarDbContextProvider.cs | 11 +-
.../IgnoreCodeFirstAttribute.cs | 4 +
...FrameworkSqlSugarCoreAbstractionsModule.cs | 6 +-
.../AsyncLocalDbContextAccessor .cs | 24 +-
.../DefaultSqlSugarDbContext.cs | 361 ++++++++++--------
.../Repositories/SqlSugarRepository.cs | 29 +-
.../SqlSugarCoreExtensions.cs | 68 ++--
.../SqlSugarDbContext.cs | 50 ++-
.../SqlSugarDbContextCreationContext.cs | 40 +-
.../SqlSugarDbContextFactory.cs | 302 ++++++++-------
.../SqlSugarNonPublicSerializer.cs | 6 +-
.../TenantConfigurationWrapper.cs | 64 ++--
.../Uow/SqlSugarDatabaseApi.cs | 10 +
.../Uow/SqlSugarTransactionApi.cs | 37 +-
.../UnitOfWorkSqlsugarDbContextProvider.cs | 107 +++---
.../YiFrameworkSqlSugarCoreModule.cs | 227 ++++++-----
Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs | 2 +-
.../Yi.Abp.Tool.Web/YiAbpToolWebModule.cs | 2 +-
61 files changed, 2604 insertions(+), 1260 deletions(-)
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ApiInfoBuilderExtensions.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ApiInfoBuilderExtensions.cs
index e94d369a..5525a2e5 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ApiInfoBuilderExtensions.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ApiInfoBuilderExtensions.cs
@@ -4,13 +4,23 @@ using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares;
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder
{
+ ///
+ /// 提供API信息处理的应用程序构建器扩展方法
+ ///
public static class ApiInfoBuilderExtensions
{
- public static IApplicationBuilder UseYiApiHandlinge([NotNull] this IApplicationBuilder app)
+ ///
+ /// 使用Yi框架的API信息处理中间件
+ ///
+ /// 应用程序构建器实例
+ /// 配置后的应用程序构建器实例
+ /// 当builder参数为null时抛出
+ public static IApplicationBuilder UseApiInfoHandling([NotNull] this IApplicationBuilder builder)
{
- app.UseMiddleware();
- return app;
-
+ // 添加API信息处理中间件到请求管道
+ builder.UseMiddleware();
+
+ return builder;
}
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerBuilderExtensons.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerBuilderExtensons.cs
index 7ea50a4c..03fb034f 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerBuilderExtensons.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerBuilderExtensons.cs
@@ -5,49 +5,101 @@ using Volo.Abp.AspNetCore.Mvc;
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder
{
- public static class SwaggerBuilderExtensons
+ ///
+ /// Swagger构建器扩展类
+ ///
+ public static class SwaggerBuilderExtensions
{
- public static IApplicationBuilder UseYiSwagger(this IApplicationBuilder app, params SwaggerModel[] swaggerModels)
+ ///
+ /// 配置并使用Yi框架的Swagger中间件
+ ///
+ /// 应用程序构建器
+ /// Swagger配置模型数组
+ /// 应用程序构建器
+ public static IApplicationBuilder UseYiSwagger(
+ this IApplicationBuilder app,
+ params SwaggerConfiguration[] swaggerConfigs)
{
- var mvcOptions = app.ApplicationServices.GetRequiredService>().Value;
-
- app.UseSwagger();
- app.UseSwaggerUI(c =>
+ if (app == null)
{
- foreach (var setting in mvcOptions.ConventionalControllers.ConventionalControllerSettings)
+ throw new ArgumentNullException(nameof(app));
+ }
+
+ var mvcOptions = app.ApplicationServices
+ .GetRequiredService>()
+ .Value;
+
+ // 启用Swagger中间件
+ app.UseSwagger();
+
+ // 配置SwaggerUI
+ app.UseSwaggerUI(options =>
+ {
+ // 添加约定控制器的Swagger终结点
+ var conventionalSettings = mvcOptions.ConventionalControllers.ConventionalControllerSettings;
+ foreach (var setting in conventionalSettings)
{
- c.SwaggerEndpoint($"/swagger/{setting.RemoteServiceName}/swagger.json", setting.RemoteServiceName);
+ options.SwaggerEndpoint(
+ $"/swagger/{setting.RemoteServiceName}/swagger.json",
+ setting.RemoteServiceName);
}
- if (mvcOptions.ConventionalControllers.ConventionalControllerSettings.Count==0&&swaggerModels.Length == 0)
+
+ // 如果没有配置任何终结点,使用默认配置
+ if (!conventionalSettings.Any() && (swaggerConfigs == null || !swaggerConfigs.Any()))
{
- c.SwaggerEndpoint("/swagger/v1/swagger.json", "Yi.Framework");
+ options.SwaggerEndpoint("/swagger/v1/swagger.json", "Yi.Framework");
+ return;
}
- else
+
+ // 添加自定义Swagger配置的终结点
+ if (swaggerConfigs != null)
{
- foreach (var k in swaggerModels)
+ foreach (var config in swaggerConfigs)
{
- c.SwaggerEndpoint(k.Url, k.Name);
+ options.SwaggerEndpoint(config.Url, config.Name);
}
}
-
});
+
return app;
}
-
}
- public class SwaggerModel
+
+ ///
+ /// Swagger配置模型
+ ///
+ public class SwaggerConfiguration
{
- public SwaggerModel(string name)
+ private const string DefaultSwaggerUrl = "/swagger/v1/swagger.json";
+
+ ///
+ /// Swagger JSON文档的URL
+ ///
+ public string Url { get; }
+
+ ///
+ /// Swagger文档的显示名称
+ ///
+ public string Name { get; }
+
+ ///
+ /// 使用默认URL创建Swagger配置
+ ///
+ /// 文档显示名称
+ public SwaggerConfiguration(string name)
+ : this(DefaultSwaggerUrl, name)
{
- this.Name = name;
- this.Url = "/swagger/v1/swagger.json";
}
- public SwaggerModel(string url, string name)
+
+ ///
+ /// 创建自定义Swagger配置
+ ///
+ /// Swagger JSON文档URL
+ /// 文档显示名称
+ public SwaggerConfiguration(string url, string name)
{
- this.Url = url;
- this.Name = name;
+ Url = url ?? throw new ArgumentNullException(nameof(url));
+ Name = name ?? throw new ArgumentNullException(nameof(name));
}
- public string Url { get; set; }
- public string Name { get; set; }
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs
index 3d89d729..8a8bb7b7 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs
@@ -1,39 +1,61 @@
using System.Diagnostics;
-using System.Net.Http;
using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
-using Volo.Abp.Json;
using Yi.Framework.Core.Extensions;
-using static System.Net.WebRequestMethods;
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares
{
+ ///
+ /// API响应信息处理中间件
+ /// 主要用于处理特定文件类型的响应头信息
+ ///
[DebuggerStepThrough]
public class ApiInfoMiddleware : IMiddleware, ITransientDependency
{
-
+ ///
+ /// 处理HTTP请求的中间件方法
+ ///
+ /// HTTP上下文
+ /// 请求处理委托
+ /// 异步任务
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
- context.Response.OnStarting([DebuggerStepThrough] () =>
+ // 在响应开始时处理文件下载相关的响应头
+ context.Response.OnStarting(() =>
{
- if (context.Response.StatusCode == StatusCodes.Status200OK
- && context.Response.Headers["Content-Type"].ToString() == "application/vnd.ms-excel")
- {
- context.FileAttachmentHandle($"{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.xlsx");
- }
- if (context.Response.StatusCode == StatusCodes.Status200OK &&
- context.Response.Headers["Content-Type"].ToString() == "application/x-zip-compressed")
- {
- context.FileAttachmentHandle($"{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.zip");
- }
+ HandleFileDownloadResponse(context);
return Task.CompletedTask;
});
+ // 继续处理管道中的下一个中间件
await next(context);
+ }
+ ///
+ /// 处理文件下载响应的响应头信息
+ ///
+ /// HTTP上下文
+ private static void HandleFileDownloadResponse(HttpContext context)
+ {
+ // 仅处理状态码为200的响应
+ if (context.Response.StatusCode != StatusCodes.Status200OK)
+ {
+ return;
+ }
+ var contentType = context.Response.Headers["Content-Type"].ToString();
+ var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
+ // 处理Excel文件下载
+ if (contentType == "application/vnd.ms-excel")
+ {
+ context.FileAttachmentHandle($"{timestamp}.xlsx");
+ }
+ // 处理ZIP文件下载
+ else if (contentType == "application/x-zip-compressed")
+ {
+ context.FileAttachmentHandle($"{timestamp}.zip");
+ }
}
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs
index 7f446586..b6fe3861 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs
@@ -9,129 +9,193 @@ using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Options;
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
{
+ ///
+ /// Swagger生成器扩展类
+ ///
public static class SwaggerAddExtensions
{
- public static IServiceCollection AddYiSwaggerGen(this IServiceCollection services,
- Action? action = null)
+ ///
+ /// 添加Yi框架的Swagger生成器服务
+ ///
+ /// 程序入口类型
+ /// 服务集合
+ /// 自定义配置动作
+ /// 服务集合
+ public static IServiceCollection AddYiSwaggerGen(
+ this IServiceCollection services,
+ Action? setupAction = null)
{
+ // 获取MVC配置选项
var mvcOptions = services.GetPreConfigureActions().Configure();
- var mvcSettings =
- mvcOptions.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
-
+ // 获取并去重远程服务名称
+ var remoteServiceSettings = mvcOptions.ConventionalControllers
+ .ConventionalControllerSettings
+ .DistinctBy(x => x.RemoteServiceName);
services.AddAbpSwaggerGen(
options =>
{
- if (action is not null)
- {
- action.Invoke(options);
- }
+ // 应用外部配置
+ setupAction?.Invoke(options);
- // 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
- foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
- {
- if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
- {
- options.SwaggerDoc(setting.RemoteServiceName,
- new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
- }
- }
+ // 配置API文档分组
+ ConfigureApiGroups(options, remoteServiceSettings);
- // 根据分组名称过滤 API 文档
- options.DocInclusionPredicate((docName, apiDesc) =>
- {
- if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
- {
- var settingOrNull = mvcSettings
- .Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly)
- .FirstOrDefault();
- if (settingOrNull is not null)
- {
- return docName == settingOrNull.RemoteServiceName;
- }
- }
-
- return false;
- });
+ // 配置API文档过滤器
+ ConfigureApiFilter(options, remoteServiceSettings);
+ // 配置Schema ID生成规则
options.CustomSchemaIds(type => type.FullName);
- var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
- if (basePath is not null)
- {
- foreach (var item in Directory.GetFiles(basePath, "*.xml"))
- {
- options.IncludeXmlComments(item, true);
- }
- }
- options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
- {
- Description = "直接输入Token即可",
- Name = "Authorization",
- In = ParameterLocation.Header,
- Type = SecuritySchemeType.Http,
- Scheme = "bearer"
- });
- var scheme = new OpenApiSecurityScheme()
- {
- Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
- };
- options.AddSecurityRequirement(new OpenApiSecurityRequirement()
- {
- [scheme] = new string[0]
- });
+ // 包含XML注释文档
+ IncludeXmlComments(options);
- options.OperationFilter();
- options.SchemaFilter();
+ // 配置JWT认证
+ ConfigureJwtAuthentication(options);
+
+ // 添加自定义过滤器
+ ConfigureCustomFilters(options);
}
);
-
return services;
}
+
+ ///
+ /// 配置API分组
+ ///
+ private static void ConfigureApiGroups(
+ SwaggerGenOptions options,
+ IEnumerable settings)
+ {
+ foreach (var setting in settings.OrderBy(x => x.RemoteServiceName))
+ {
+ if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
+ {
+ options.SwaggerDoc(setting.RemoteServiceName, new OpenApiInfo
+ {
+ Title = setting.RemoteServiceName,
+ Version = "v1"
+ });
+ }
+ }
+ }
+
+ ///
+ /// 配置API文档过滤器
+ ///
+ private static void ConfigureApiFilter(
+ SwaggerGenOptions options,
+ IEnumerable settings)
+ {
+ options.DocInclusionPredicate((docName, apiDesc) =>
+ {
+ if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerDesc)
+ {
+ var matchedSetting = settings
+ .FirstOrDefault(x => x.Assembly == controllerDesc.ControllerTypeInfo.Assembly);
+ return matchedSetting?.RemoteServiceName == docName;
+ }
+ return false;
+ });
+ }
+
+ ///
+ /// 包含XML注释文档
+ ///
+ private static void IncludeXmlComments(SwaggerGenOptions options)
+ {
+ var basePath = Path.GetDirectoryName(typeof(TProgram).Assembly.Location);
+ if (basePath is not null)
+ {
+ foreach (var xmlFile in Directory.GetFiles(basePath, "*.xml"))
+ {
+ options.IncludeXmlComments(xmlFile, true);
+ }
+ }
+ }
+
+ ///
+ /// 配置JWT认证
+ ///
+ private static void ConfigureJwtAuthentication(SwaggerGenOptions options)
+ {
+ options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme
+ {
+ Description = "请在此输入JWT Token",
+ Name = "Authorization",
+ In = ParameterLocation.Header,
+ Type = SecuritySchemeType.Http,
+ Scheme = "bearer"
+ });
+
+ var scheme = new OpenApiSecurityScheme
+ {
+ Reference = new OpenApiReference
+ {
+ Type = ReferenceType.SecurityScheme,
+ Id = "JwtBearer"
+ }
+ };
+
+ options.AddSecurityRequirement(new OpenApiSecurityRequirement
+ {
+ [scheme] = Array.Empty()
+ });
+ }
+
+ ///
+ /// 配置自定义过滤器
+ ///
+ private static void ConfigureCustomFilters(SwaggerGenOptions options)
+ {
+ options.OperationFilter();
+ options.SchemaFilter();
+ }
}
-
///
- /// Swagger文档枚举字段显示枚举属性和枚举值,以及枚举描述
+ /// Swagger文档枚举字段显示过滤器
///
public class EnumSchemaFilter : ISchemaFilter
{
///
- /// 实现接口
+ /// 应用枚举架构过滤器
///
- ///
- ///
- public void Apply(OpenApiSchema model, SchemaFilterContext context)
+ /// OpenAPI架构
+ /// 架构过滤器上下文
+ public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
- if (context.Type.IsEnum)
+ if (!context.Type.IsEnum) return;
+
+ schema.Enum.Clear();
+ schema.Type = "string";
+ schema.Format = null;
+
+ var enumDescriptions = new StringBuilder();
+ foreach (var enumName in Enum.GetNames(context.Type))
{
- model.Enum.Clear();
- model.Type = "string";
- model.Format = null;
+ var enumValue = (Enum)Enum.Parse(context.Type, enumName);
+ var description = GetEnumDescription(enumValue);
+ var enumIntValue = Convert.ToInt64(enumValue);
-
- StringBuilder stringBuilder = new StringBuilder();
- Enum.GetNames(context.Type)
- .ToList()
- .ForEach(name =>
- {
- Enum e = (Enum)Enum.Parse(context.Type, name);
- var descrptionOrNull = GetEnumDescription(e);
- model.Enum.Add(new OpenApiString(name));
- stringBuilder.Append(
- $"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】
");
- });
- model.Description = stringBuilder.ToString();
+ schema.Enum.Add(new OpenApiString(enumName));
+ enumDescriptions.AppendLine(
+ $"【枚举:{enumName}{(description is null ? string.Empty : $"({description})")}={enumIntValue}】");
}
+ schema.Description = enumDescriptions.ToString();
}
+ ///
+ /// 获取枚举描述特性值
+ ///
private static string? GetEnumDescription(Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
@@ -140,22 +204,30 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
}
}
-
- public class AddRequiredHeaderParameter : IOperationFilter
+ ///
+ /// 租户头部参数过滤器
+ ///
+ public class TenantHeaderOperationFilter : IOperationFilter
{
- public static string HeaderKey { get; set; } = "__tenant";
+ ///
+ /// 租户标识键名
+ ///
+ private const string TenantHeaderKey = "__tenant";
+ ///
+ /// 应用租户头部参数过滤器
+ ///
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
- if (operation.Parameters == null)
- operation.Parameters = new List();
+ operation.Parameters ??= new List();
+
operation.Parameters.Add(new OpenApiParameter
{
- Name = HeaderKey,
+ Name = TenantHeaderKey,
In = ParameterLocation.Header,
Required = false,
AllowEmptyValue = true,
- Description = "租户id或者租户名称(可空为默认租户)"
+ Description = "租户ID或租户名称(留空表示默认租户)"
});
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiConventionalRouteBuilder.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiConventionalRouteBuilder.cs
index dc946ea0..47a9a746 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiConventionalRouteBuilder.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiConventionalRouteBuilder.cs
@@ -9,65 +9,129 @@ using Volo.Abp.Reflection;
namespace Yi.Framework.AspNetCore.Mvc
{
+ ///
+ /// 自定义路由构建器,用于生成API路由规则
+ ///
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IConventionalRouteBuilder))]
public class YiConventionalRouteBuilder : ConventionalRouteBuilder
{
- public YiConventionalRouteBuilder(IOptions options) : base(options)
+ ///
+ /// 构造函数
+ ///
+ /// ABP约定控制器配置选项
+ public YiConventionalRouteBuilder(IOptions options)
+ : base(options)
{
}
+
+ ///
+ /// 构建API路由
+ ///
+ /// 根路径
+ /// 控制器名称
+ /// Action模型
+ /// HTTP方法
+ /// 控制器配置
+ /// 构建的路由URL
public override string Build(
- string rootPath,
- string controllerName,
- ActionModel action,
- string httpMethod,
- [CanBeNull] ConventionalControllerSetting configuration)
+ string rootPath,
+ string controllerName,
+ ActionModel action,
+ string httpMethod,
+ [CanBeNull] ConventionalControllerSetting configuration)
{
-
+ // 获取API路由前缀
var apiRoutePrefix = GetApiRoutePrefix(action, configuration);
- var controllerNameInUrl =
- NormalizeUrlControllerName(rootPath, controllerName, action, httpMethod, configuration);
+
+ // 规范化控制器名称
+ var normalizedControllerName = NormalizeUrlControllerName(
+ rootPath,
+ controllerName,
+ action,
+ httpMethod,
+ configuration);
- var url = $"{rootPath}/{NormalizeControllerNameCase(controllerNameInUrl, configuration)}";
+ // 构建基础URL
+ var url = $"{rootPath}/{NormalizeControllerNameCase(normalizedControllerName, configuration)}";
- //Add {id} path if needed
- var idParameterModel = action.Parameters.FirstOrDefault(p => p.ParameterName == "id");
- if (idParameterModel != null)
- {
- if (TypeHelper.IsPrimitiveExtended(idParameterModel.ParameterType, includeEnums: true))
- {
- url += "/{id}";
- }
- else
- {
- var properties = idParameterModel
- .ParameterType
- .GetProperties(BindingFlags.Instance | BindingFlags.Public);
+ // 处理ID参数路由
+ url = BuildIdParameterRoute(url, action, configuration);
- foreach (var property in properties)
- {
- url += "/{" + NormalizeIdPropertyNameCase(property, configuration) + "}";
- }
- }
- }
-
- //Add action name if needed
- var actionNameInUrl = NormalizeUrlActionName(rootPath, controllerName, action, httpMethod, configuration);
- if (!actionNameInUrl.IsNullOrEmpty())
- {
- url += $"/{NormalizeActionNameCase(actionNameInUrl, configuration)}";
-
- //Add secondary Id
- var secondaryIds = action.Parameters
- .Where(p => p.ParameterName.EndsWith("Id", StringComparison.Ordinal)).ToList();
- if (secondaryIds.Count == 1)
- {
- url += $"/{{{NormalizeSecondaryIdNameCase(secondaryIds[0], configuration)}}}";
- }
- }
+ // 处理Action名称路由
+ url = BuildActionNameRoute(url, rootPath, controllerName, action, httpMethod, configuration);
return url;
}
+ ///
+ /// 构建ID参数路由部分
+ ///
+ private string BuildIdParameterRoute(
+ string baseUrl,
+ ActionModel action,
+ ConventionalControllerSetting configuration)
+ {
+ var idParameter = action.Parameters.FirstOrDefault(p => p.ParameterName == "id");
+ if (idParameter == null)
+ {
+ return baseUrl;
+ }
+
+ // 处理原始类型ID
+ if (TypeHelper.IsPrimitiveExtended(idParameter.ParameterType, includeEnums: true))
+ {
+ return $"{baseUrl}/{{id}}";
+ }
+
+ // 处理复杂类型ID
+ var properties = idParameter.ParameterType
+ .GetProperties(BindingFlags.Instance | BindingFlags.Public);
+
+ foreach (var property in properties)
+ {
+ baseUrl += $"/{{{NormalizeIdPropertyNameCase(property, configuration)}}}";
+ }
+
+ return baseUrl;
+ }
+
+ ///
+ /// 构建Action名称路由部分
+ ///
+ private string BuildActionNameRoute(
+ string baseUrl,
+ string rootPath,
+ string controllerName,
+ ActionModel action,
+ string httpMethod,
+ ConventionalControllerSetting configuration)
+ {
+ var actionNameInUrl = NormalizeUrlActionName(
+ rootPath,
+ controllerName,
+ action,
+ httpMethod,
+ configuration);
+
+ if (actionNameInUrl.IsNullOrEmpty())
+ {
+ return baseUrl;
+ }
+
+ baseUrl += $"/{NormalizeActionNameCase(actionNameInUrl, configuration)}";
+
+ // 处理次要ID参数
+ var secondaryIds = action.Parameters
+ .Where(p => p.ParameterName.EndsWith("Id", StringComparison.Ordinal))
+ .ToList();
+
+ if (secondaryIds.Count == 1)
+ {
+ baseUrl += $"/{{{NormalizeSecondaryIdNameCase(secondaryIds[0], configuration)}}}";
+ }
+
+ return baseUrl;
+ }
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiServiceConvention.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiServiceConvention.cs
index 200fcd4b..7f3afc12 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiServiceConvention.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiServiceConvention.cs
@@ -13,24 +13,46 @@ using Volo.Abp.Reflection;
namespace Yi.Framework.AspNetCore.Mvc
{
+ ///
+ /// 自定义服务约定实现,用于处理API路由和HTTP方法约束
+ ///
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IAbpServiceConvention))]
public class YiServiceConvention : AbpServiceConvention
{
- public YiServiceConvention(IOptions options, IConventionalRouteBuilder conventionalRouteBuilder) : base(options, conventionalRouteBuilder)
+ ///
+ /// 初始化服务约定的新实例
+ ///
+ /// ABP AspNetCore MVC 配置选项
+ /// 约定路由构建器
+ public YiServiceConvention(
+ IOptions options,
+ IConventionalRouteBuilder conventionalRouteBuilder)
+ : base(options, conventionalRouteBuilder)
{
}
- protected override void ConfigureSelector(string rootPath, string controllerName, ActionModel action, ConventionalControllerSetting? configuration)
+ ///
+ /// 配置选择器,处理路由和HTTP方法约束
+ ///
+ protected override void ConfigureSelector(
+ string rootPath,
+ string controllerName,
+ ActionModel action,
+ ConventionalControllerSetting? configuration)
{
+ // 移除空选择器
RemoveEmptySelectors(action.Selectors);
- var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault(action.ActionMethod);
- if (remoteServiceAtt != null && !remoteServiceAtt.IsEnabledFor(action.ActionMethod))
+ // 检查远程服务特性
+ var remoteServiceAttr = ReflectionHelper
+ .GetSingleAttributeOrDefault(action.ActionMethod);
+ if (remoteServiceAttr != null && !remoteServiceAttr.IsEnabledFor(action.ActionMethod))
{
return;
}
+ // 根据选择器是否存在执行不同的配置
if (!action.Selectors.Any())
{
AddAbpServiceSelector(rootPath, controllerName, action, configuration);
@@ -41,56 +63,92 @@ namespace Yi.Framework.AspNetCore.Mvc
}
}
-
- protected override void AddAbpServiceSelector(string rootPath, string controllerName, ActionModel action, ConventionalControllerSetting? configuration)
- {
- base.AddAbpServiceSelector(rootPath, controllerName, action, configuration);
- }
-
- protected override void NormalizeSelectorRoutes(string rootPath, string controllerName, ActionModel action, ConventionalControllerSetting? configuration)
+ ///
+ /// 规范化选择器路由
+ ///
+ protected override void NormalizeSelectorRoutes(
+ string rootPath,
+ string controllerName,
+ ActionModel action,
+ ConventionalControllerSetting? configuration)
{
foreach (var selector in action.Selectors)
{
- var httpMethod = selector.ActionConstraints
- .OfType()
- .FirstOrDefault()?
- .HttpMethods?
- .FirstOrDefault();
-
- if (httpMethod == null)
- {
- httpMethod = SelectHttpMethod(action, configuration);
- }
-
- if (selector.AttributeRouteModel == null)
- {
- selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel(rootPath, controllerName, action, httpMethod, configuration);
- }
- else
- {
-
- var template = selector.AttributeRouteModel.Template;
- if (!template.StartsWith("/"))
- {
- var route = $"{rootPath}/{template}";
- selector.AttributeRouteModel.Template = route;
-
- }
-
- }
-
-
-
- if (!selector.ActionConstraints.OfType().Any())
- {
- selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod }));
- }
+ // 获取HTTP方法约束
+ var httpMethod = GetOrCreateHttpMethod(selector, action, configuration);
+ // 处理路由模板
+ ConfigureRouteTemplate(selector, rootPath, controllerName, action, httpMethod, configuration);
+ // 确保HTTP方法约束存在
+ EnsureHttpMethodConstraint(selector, httpMethod);
}
}
+ ///
+ /// 获取或创建HTTP方法
+ ///
+ private string GetOrCreateHttpMethod(
+ SelectorModel selector,
+ ActionModel action,
+ ConventionalControllerSetting? configuration)
+ {
+ return selector.ActionConstraints
+ .OfType()
+ .FirstOrDefault()?
+ .HttpMethods?
+ .FirstOrDefault()
+ ?? SelectHttpMethod(action, configuration);
+ }
+ ///
+ /// 配置路由模板
+ ///
+ private void ConfigureRouteTemplate(
+ SelectorModel selector,
+ string rootPath,
+ string controllerName,
+ ActionModel action,
+ string httpMethod,
+ ConventionalControllerSetting? configuration)
+ {
+ if (selector.AttributeRouteModel == null)
+ {
+ selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel(
+ rootPath,
+ controllerName,
+ action,
+ httpMethod,
+ configuration);
+ }
+ else
+ {
+ NormalizeAttributeRouteTemplate(selector, rootPath);
+ }
+ }
+ ///
+ /// 规范化特性路由模板
+ ///
+ private void NormalizeAttributeRouteTemplate(SelectorModel selector, string rootPath)
+ {
+ var template = selector.AttributeRouteModel.Template;
+ if (!template.StartsWith("/"))
+ {
+ selector.AttributeRouteModel.Template = $"{rootPath}/{template}";
+ }
+ }
+
+ ///
+ /// 确保HTTP方法约束存在
+ ///
+ private void EnsureHttpMethodConstraint(SelectorModel selector, string httpMethod)
+ {
+ if (!selector.ActionConstraints.OfType().Any())
+ {
+ selector.ActionConstraints.Add(
+ new HttpMethodActionConstraint(new[] { httpMethod }));
+ }
+ }
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RealIpHttpContextWebClientInfoProvider.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RealIpHttpContextWebClientInfoProvider.cs
index d00fd95c..f338509b 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RealIpHttpContextWebClientInfoProvider.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RealIpHttpContextWebClientInfoProvider.cs
@@ -5,32 +5,53 @@ using Volo.Abp.AspNetCore.WebClientInfo;
namespace Yi.Framework.AspNetCore;
+///
+/// 真实IP地址提供程序,支持代理服务器场景
+///
public class RealIpHttpContextWebClientInfoProvider : HttpContextWebClientInfoProvider
{
- public RealIpHttpContextWebClientInfoProvider(ILogger logger,
- IHttpContextAccessor httpContextAccessor) : base(logger, httpContextAccessor)
+ private const string XForwardedForHeader = "X-Forwarded-For";
+
+ ///
+ /// 初始化真实IP地址提供程序的新实例
+ ///
+ public RealIpHttpContextWebClientInfoProvider(
+ ILogger logger,
+ IHttpContextAccessor httpContextAccessor)
+ : base(logger, httpContextAccessor)
{
}
+ ///
+ /// 获取客户端IP地址,优先从X-Forwarded-For头部获取
+ ///
+ /// 客户端IP地址
protected override string? GetClientIpAddress()
{
try
{
var httpContext = HttpContextAccessor.HttpContext;
-
- var headers = httpContext?.Request?.Headers;
-
- if (headers != null && headers.ContainsKey("X-Forwarded-For"))
+ if (httpContext == null)
{
- httpContext.Connection.RemoteIpAddress =
- IPAddress.Parse(headers["X-Forwarded-For"].FirstOrDefault());
+ return null;
}
- return httpContext?.Connection?.RemoteIpAddress?.ToString();
+ var headers = httpContext.Request?.Headers;
+ if (headers != null && headers.ContainsKey(XForwardedForHeader))
+ {
+ // 从X-Forwarded-For获取真实客户端IP
+ var forwardedIp = headers[XForwardedForHeader].FirstOrDefault();
+ if (!string.IsNullOrEmpty(forwardedIp))
+ {
+ httpContext.Connection.RemoteIpAddress = IPAddress.Parse(forwardedIp);
+ }
+ }
+
+ return httpContext.Connection?.RemoteIpAddress?.ToString();
}
catch (Exception ex)
{
- Logger.LogException(ex, LogLevel.Warning);
+ Logger.LogWarning(ex, "获取客户端IP地址时发生异常");
return null;
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RemoteServiceSuccessInfo.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RemoteServiceSuccessInfo.cs
index c008f162..daa9cf35 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RemoteServiceSuccessInfo.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RemoteServiceSuccessInfo.cs
@@ -1,49 +1,55 @@
namespace Yi.Framework.AspNetCore
{
+ ///
+ /// 远程服务成功响应信息
+ ///
[Serializable]
public class RemoteServiceSuccessInfo
{
///
- /// Creates a new instance of .
+ /// 获取或设置响应代码
+ ///
+ public string? Code { get; private set; }
+
+ ///
+ /// 获取或设置响应消息
+ ///
+ public string? Message { get; private set; }
+
+ ///
+ /// 获取或设置详细信息
+ ///
+ public string? Details { get; private set; }
+
+ ///
+ /// 获取或设置响应数据
+ ///
+ public object? Data { get; private set; }
+
+ ///
+ /// 初始化远程服务成功响应信息的新实例
///
public RemoteServiceSuccessInfo()
{
}
///
- /// Creates a new instance of .
+ /// 使用指定参数初始化远程服务成功响应信息的新实例
///
- /// Error code
- /// Error details
- /// Error message
- /// Error data
- public RemoteServiceSuccessInfo(string message, string? details = null, string? code = null, object? data = null)
+ /// 响应消息
+ /// 详细信息
+ /// 响应代码
+ /// 响应数据
+ public RemoteServiceSuccessInfo(
+ string message,
+ string? details = null,
+ string? code = null,
+ object? data = null)
{
Message = message;
Details = details;
Code = code;
Data = data;
}
-
- ///
- /// code.
- ///
- public string? Code { get; set; }
-
- ///
- /// message.
- ///
- public string? Message { get; set; }
-
- ///
- /// details.
- ///
- public string? Details { get; set; }
-
- ///
- /// data.
- ///
- public object? Data { get; set; }
-
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs
index 006a3763..36cdb0d9 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs
@@ -19,15 +19,24 @@ using Yi.Framework.Core;
namespace Yi.Framework.AspNetCore
{
- [DependsOn(typeof(YiFrameworkCoreModule)
- )]
+ ///
+ /// Yi框架ASP.NET Core模块
+ ///
+ [DependsOn(typeof(YiFrameworkCoreModule))]
public class YiFrameworkAspNetCoreModule : AbpModule
{
+ ///
+ /// 配置服务后的处理
+ ///
public override void PostConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
- services.Replace(new ServiceDescriptor(typeof(IWebClientInfoProvider),
- typeof(RealIpHttpContextWebClientInfoProvider), ServiceLifetime.Transient));
+
+ // 替换默认的WebClientInfoProvider为支持代理的实现
+ services.Replace(new ServiceDescriptor(
+ typeof(IWebClientInfoProvider),
+ typeof(RealIpHttpContextWebClientInfoProvider),
+ ServiceLifetime.Transient));
}
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/UnitOfWorkHangfireFilter.cs b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/UnitOfWorkHangfireFilter.cs
index 47748c22..ad818576 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/UnitOfWorkHangfireFilter.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/UnitOfWorkHangfireFilter.cs
@@ -5,40 +5,72 @@ using Volo.Abp.Uow;
namespace Yi.Framework.BackgroundWorkers.Hangfire;
-public class UnitOfWorkHangfireFilter : IServerFilter, ISingletonDependency
+///
+/// Hangfire 工作单元过滤器
+/// 用于管理后台任务的事务处理
+///
+public sealed class UnitOfWorkHangfireFilter : IServerFilter, ISingletonDependency
{
- private const string CurrentJobUow = "HangfireUnitOfWork";
+ private const string UnitOfWorkItemKey = "HangfireUnitOfWork";
private readonly IUnitOfWorkManager _unitOfWorkManager;
+ ///
+ /// 初始化工作单元过滤器
+ ///
+ /// 工作单元管理器
public UnitOfWorkHangfireFilter(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
+ ///
+ /// 任务执行前的处理
+ ///
+ /// 执行上下文
public void OnPerforming(PerformingContext context)
{
+ // 开启一个工作单元并存储到上下文中
var uow = _unitOfWorkManager.Begin();
- context.Items.Add(CurrentJobUow, uow);
+ context.Items.Add(UnitOfWorkItemKey, uow);
}
+ ///
+ /// 任务执行后的处理
+ ///
+ /// 执行上下文
public void OnPerformed(PerformedContext context)
{
- AsyncHelper.RunSync(()=>OnPerformedAsync(context));
+ AsyncHelper.RunSync(() => OnPerformedAsync(context));
}
+ ///
+ /// 任务执行后的异步处理
+ ///
+ /// 执行上下文
private async Task OnPerformedAsync(PerformedContext context)
{
- if (context.Items.TryGetValue(CurrentJobUow, out var obj)
- && obj is IUnitOfWork uow)
+ if (!context.Items.TryGetValue(UnitOfWorkItemKey, out var obj) ||
+ obj is not IUnitOfWork uow)
{
+ return;
+ }
+
+ try
+ {
+ // 如果没有异常且工作单元未完成,则提交事务
if (context.Exception == null && !uow.IsCompleted)
{
await uow.CompleteAsync();
}
else
{
+ // 否则回滚事务
await uow.RollbackAsync();
}
+ }
+ finally
+ {
+ // 确保工作单元被释放
uow.Dispose();
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj
index ee6c5ed7..4706bcf7 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj
+++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj
@@ -10,6 +10,7 @@
+
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs
index d0a44ce1..6663358a 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs
@@ -2,53 +2,82 @@
using Hangfire;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.BackgroundJobs.Hangfire;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.DynamicProxy;
namespace Yi.Framework.BackgroundWorkers.Hangfire;
-[DependsOn(typeof(AbpBackgroundWorkersHangfireModule))]
-public class YiFrameworkBackgroundWorkersHangfireModule : AbpModule
+///
+/// Hangfire 后台任务模块
+///
+[DependsOn(typeof(AbpBackgroundWorkersHangfireModule),
+ typeof(AbpBackgroundJobsHangfireModule))]
+public sealed class YiFrameworkBackgroundWorkersHangfireModule : AbpModule
{
+ ///
+ /// 配置服务前的预处理
+ ///
+ /// 服务配置上下文
public override void PreConfigureServices(ServiceConfigurationContext context)
{
+ // 添加 Hangfire 后台任务约定注册器
context.Services.AddConventionalRegistrar(new YiHangfireConventionalRegistrar());
}
+ ///
+ /// 应用程序初始化
+ ///
+ /// 应用程序初始化上下文
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
{
- //定时任务自动注入,Abp默认只有在Quartz才实现
+ // 获取后台任务管理器和所有 Hangfire 后台任务
var backgroundWorkerManager = context.ServiceProvider.GetRequiredService();
- var works = context.ServiceProvider.GetServices();
+ var workers = context.ServiceProvider.GetServices();
+ // 获取配置
var configuration = context.ServiceProvider.GetRequiredService();
- //【特殊,为了兼容内存模式,由于内存模式任务,不能使用队列】
- bool.TryParse(configuration["Redis:IsEnabled"], out var redisEnabled);
- foreach (var work in works)
+
+ // 检查是否启用 Redis
+ var isRedisEnabled = configuration.GetValue("Redis:IsEnabled");
+
+ foreach (var worker in workers)
{
- //如果为空,默认使用服务器本地上海时间
- work.TimeZone = TimeZoneInfo.Local;
- if (redisEnabled)
+ // 设置时区为本地时区(上海)
+ worker.TimeZone = TimeZoneInfo.Local;
+
+ if (isRedisEnabled)
{
- await backgroundWorkerManager.AddAsync(work);
+ // Redis 模式:使用 ABP 后台任务管理器
+ await backgroundWorkerManager.AddAsync(worker);
}
else
{
- object unProxyWorker = ProxyHelper.UnProxy((object)work);
- RecurringJob.AddOrUpdate(work.RecurringJobId,
- (Expression>)(() =>
- ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(default(CancellationToken))),
- work.CronExpression, new RecurringJobOptions()
+ // 内存模式:直接使用 Hangfire
+ var unProxyWorker = ProxyHelper.UnProxy(worker);
+
+ // 添加或更新循环任务
+ RecurringJob.AddOrUpdate(
+ worker.RecurringJobId,
+ (Expression>)(() =>
+ ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(default)),
+ worker.CronExpression,
+ new RecurringJobOptions
{
- TimeZone = work.TimeZone
+ TimeZone = worker.TimeZone
});
}
}
}
+ ///
+ /// 应用程序初始化前的预处理
+ ///
+ /// 应用程序初始化上下文
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
{
+ // 添加工作单元过滤器
var services = context.ServiceProvider;
GlobalJobFilters.Filters.Add(services.GetRequiredService());
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs
index f8f99bad..4560f9a4 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs
@@ -3,18 +3,32 @@ using Volo.Abp.DependencyInjection;
namespace Yi.Framework.BackgroundWorkers.Hangfire;
-public class YiHangfireConventionalRegistrar : DefaultConventionalRegistrar
+///
+/// Hangfire 后台任务约定注册器
+///
+public sealed class YiHangfireConventionalRegistrar : DefaultConventionalRegistrar
{
+ ///
+ /// 检查类型是否禁用约定注册
+ ///
+ /// 要检查的类型
+ /// 如果类型不是 IHangfireBackgroundWorker 或已被禁用则返回 true
protected override bool IsConventionalRegistrationDisabled(Type type)
{
- return !typeof(IHangfireBackgroundWorker).IsAssignableFrom(type) || base.IsConventionalRegistrationDisabled(type);
+ return !typeof(IHangfireBackgroundWorker).IsAssignableFrom(type) ||
+ base.IsConventionalRegistrationDisabled(type);
}
+ ///
+ /// 获取要暴露的服务类型列表
+ ///
+ /// 实现类型
+ /// 服务类型列表
protected override List GetExposedServiceTypes(Type type)
{
- return new List()
- {
- typeof(IHangfireBackgroundWorker)
- };
+ return new List
+ {
+ typeof(IHangfireBackgroundWorker)
+ };
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs
index 4c7c3bb8..f7235a67 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs
@@ -6,116 +6,141 @@ using Volo.Abp.Users;
namespace Yi.Framework.BackgroundWorkers.Hangfire;
-public class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, ITransientDependency
+///
+/// Hangfire 仪表盘的令牌认证过滤器
+///
+public sealed class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, ITransientDependency
{
- private const string Bearer = "Bearer: ";
- private string RequireUser { get; set; } = "cc";
- private TimeSpan ExpiresTime { get; set; } = TimeSpan.FromMinutes(10);
- private IServiceProvider _serviceProvider;
+ private const string BearerPrefix = "Bearer ";
+ private const string TokenCookieKey = "Token";
+ private const string HtmlContentType = "text/html";
+
+ private readonly IServiceProvider _serviceProvider;
+ private string _requiredUsername = "cc";
+ private TimeSpan _tokenExpiration = TimeSpan.FromMinutes(10);
+ ///
+ /// 初始化令牌认证过滤器
+ ///
+ /// 服务提供者
public YiTokenAuthorizationFilter(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
- public YiTokenAuthorizationFilter SetRequireUser(string userName)
+ ///
+ /// 设置需要的用户名
+ ///
+ /// 允许访问的用户名
+ /// 当前实例,支持链式调用
+ public YiTokenAuthorizationFilter SetRequiredUsername(string username)
{
- RequireUser = userName;
+ _requiredUsername = username ?? throw new ArgumentNullException(nameof(username));
return this;
}
- public YiTokenAuthorizationFilter SetExpiresTime(TimeSpan expiresTime)
+ ///
+ /// 设置令牌过期时间
+ ///
+ /// 过期时间间隔
+ /// 当前实例,支持链式调用
+ public YiTokenAuthorizationFilter SetTokenExpiration(TimeSpan expiration)
{
- ExpiresTime = expiresTime;
+ _tokenExpiration = expiration;
return this;
}
+ ///
+ /// 授权验证
+ ///
+ /// 仪表盘上下文
+ /// 是否通过授权
public bool Authorize(DashboardContext context)
{
var httpContext = context.GetHttpContext();
- var _currentUser = _serviceProvider.GetRequiredService();
- //如果验证通过,设置cookies
- if (_currentUser.IsAuthenticated)
+ var currentUser = _serviceProvider.GetRequiredService();
+
+ if (!currentUser.IsAuthenticated)
{
- var cookieOptions = new CookieOptions
- {
- Expires = DateTimeOffset.Now + ExpiresTime, // 设置 cookie 过期时间,10分钟
- };
-
-
- var authorization = httpContext.Request.Headers["Authorization"].ToString();
- if (!string.IsNullOrWhiteSpace(authorization))
- {
- var token = httpContext.Request.Headers["Authorization"].ToString().Substring(Bearer.Length - 1);
- httpContext.Response.Cookies.Append("Token", token, cookieOptions);
- }
-
- if (_currentUser.UserName == RequireUser)
- {
- return true;
- }
+ SetChallengeResponse(httpContext);
+ return false;
}
- SetChallengeResponse(httpContext);
- return false;
+ // 如果验证通过,设置 cookie
+ var authorization = httpContext.Request.Headers.Authorization.ToString();
+ if (!string.IsNullOrWhiteSpace(authorization) && authorization.StartsWith(BearerPrefix))
+ {
+ var token = authorization[BearerPrefix.Length..];
+ SetTokenCookie(httpContext, token);
+ }
+
+ return currentUser.UserName == _requiredUsername;
}
+ ///
+ /// 设置认证挑战响应
+ /// 当用户未认证时,返回一个包含令牌输入表单的HTML页面
+ ///
+ /// HTTP 上下文
private void SetChallengeResponse(HttpContext httpContext)
{
httpContext.Response.StatusCode = 401;
- httpContext.Response.ContentType = "text/html; charset=utf-8";
- string html = """
-
-
-
-
-
- Token 输入
-
-
-
- Yi-hangfire
- 输入您的Token,我们将验证您是否为管理员
-
-
-
-
- """;
+ httpContext.Response.ContentType = HtmlContentType;
+
+ var html = @"
+
+
+ Hangfire Dashboard Authorization
+
+
+
+
+
Authorization Required
+
+
+
+
+
+
+
+ ";
+
httpContext.Response.WriteAsync(html);
}
+ ///
+ /// 设置令牌 Cookie
+ ///
+ /// HTTP 上下文
+ /// 令牌值
+ private void SetTokenCookie(HttpContext httpContext, string token)
+ {
+ var cookieOptions = new CookieOptions
+ {
+ Expires = DateTimeOffset.Now.Add(_tokenExpiration),
+ HttpOnly = true,
+ Secure = httpContext.Request.IsHttps,
+ SameSite = SameSiteMode.Lax
+ };
+
+ httpContext.Response.Cookies.Append(TokenCookieKey, token, cookieOptions);
+ }
+
public Task AuthorizeAsync(DashboardContext context)
{
return Task.FromResult(Authorize(context));
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs
index e3e0e22e..8ead64aa 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs
@@ -10,28 +10,43 @@ using Volo.Abp.MultiTenancy;
namespace Yi.Framework.Caching.FreeRedis
{
- [Dependency(ReplaceServices =true)]
+ ///
+ /// 缓存键标准化处理器
+ /// 用于处理缓存键的格式化和多租户支持
+ ///
+ [Dependency(ReplaceServices = true)]
public class YiDistributedCacheKeyNormalizer : IDistributedCacheKeyNormalizer, ITransientDependency
{
- protected ICurrentTenant CurrentTenant { get; }
-
- protected AbpDistributedCacheOptions DistributedCacheOptions { get; }
+ private readonly ICurrentTenant _currentTenant;
+ private readonly AbpDistributedCacheOptions _distributedCacheOptions;
+ ///
+ /// 构造函数
+ ///
+ /// 当前租户服务
+ /// 分布式缓存配置选项
public YiDistributedCacheKeyNormalizer(
ICurrentTenant currentTenant,
IOptions distributedCacheOptions)
{
- CurrentTenant = currentTenant;
- DistributedCacheOptions = distributedCacheOptions.Value;
+ _currentTenant = currentTenant;
+ _distributedCacheOptions = distributedCacheOptions.Value;
}
+ ///
+ /// 标准化缓存键
+ ///
+ /// 缓存键标准化参数
+ /// 标准化后的缓存键
public virtual string NormalizeKey(DistributedCacheKeyNormalizeArgs args)
{
- var normalizedKey = $"{DistributedCacheOptions.KeyPrefix}{args.Key}";
+ // 添加全局缓存前缀
+ var normalizedKey = $"{_distributedCacheOptions.KeyPrefix}{args.Key}";
- //if (!args.IgnoreMultiTenancy && CurrentTenant.Id.HasValue)
+ //todo 多租户支持已注释,如需启用取消注释即可
+ //if (!args.IgnoreMultiTenancy && _currentTenant.Id.HasValue)
//{
- // normalizedKey = $"t:{CurrentTenant.Id.Value},{normalizedKey}";
+ // normalizedKey = $"t:{_currentTenant.Id.Value},{normalizedKey}";
//}
return normalizedKey;
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs
index 85b65e44..07076abc 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs
@@ -1,5 +1,6 @@
using FreeRedis;
using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Caching;
@@ -7,26 +8,57 @@ using Volo.Abp.Caching;
namespace Yi.Framework.Caching.FreeRedis
{
///
- /// 此模块得益于FreeRedis作者支持IDistributedCache,使用湿滑
+ /// FreeRedis缓存模块
+ /// 提供基于FreeRedis的分布式缓存实现
///
[DependsOn(typeof(AbpCachingModule))]
public class YiFrameworkCachingFreeRedisModule : AbpModule
{
+ private const string RedisEnabledKey = "Redis:IsEnabled";
+ private const string RedisConfigurationKey = "Redis:Configuration";
+
+ ///
+ /// 配置服务
+ ///
+ /// 服务配置上下文
public override void ConfigureServices(ServiceConfigurationContext context)
{
-
var configuration = context.Services.GetConfiguration();
- var redisEnabled = configuration["Redis:IsEnabled"];
- if (redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled))
+ // 检查Redis是否启用
+ if (!IsRedisEnabled(configuration))
{
- var redisConfiguration = configuration["Redis:Configuration"];
- RedisClient redisClient = new RedisClient(redisConfiguration);
-
- context.Services.AddSingleton(redisClient);
- context.Services.Replace(ServiceDescriptor.Singleton(new
- DistributedCache(redisClient)));
+ return;
}
+
+ // 注册Redis服务
+ RegisterRedisServices(context, configuration);
+ }
+
+ ///
+ /// 检查Redis是否启用
+ ///
+ /// 配置
+ /// 是否启用Redis
+ private static bool IsRedisEnabled(IConfiguration configuration)
+ {
+ var redisEnabled = configuration[RedisEnabledKey];
+ return redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled);
+ }
+
+ ///
+ /// 注册Redis相关服务
+ ///
+ /// 服务配置上下文
+ /// 配置
+ private static void RegisterRedisServices(ServiceConfigurationContext context, IConfiguration configuration)
+ {
+ var redisConfiguration = configuration[RedisConfigurationKey];
+ var redisClient = new RedisClient(redisConfiguration);
+
+ context.Services.AddSingleton(redisClient);
+ context.Services.Replace(ServiceDescriptor.Singleton(
+ new DistributedCache(redisClient)));
}
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IOrderNum.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IOrderNum.cs
index aecb1d6e..e564b440 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IOrderNum.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IOrderNum.cs
@@ -6,8 +6,21 @@ using System.Threading.Tasks;
namespace Yi.Framework.Core.Data
{
+ ///
+ /// 排序接口
+ ///
+ ///
+ /// 实现此接口的实体类将支持排序功能
+ /// 通常用于列表数据的展示顺序控制
+ ///
public interface IOrderNum
{
+ ///
+ /// 排序号
+ ///
+ ///
+ /// 数字越小越靠前,默认为0
+ ///
int OrderNum { get; set; }
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IState.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IState.cs
index d5abcea9..e910ad5f 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IState.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IState.cs
@@ -6,8 +6,21 @@ using System.Threading.Tasks;
namespace Yi.Framework.Core.Data
{
+ ///
+ /// 状态接口
+ ///
+ ///
+ /// 实现此接口的实体类将支持启用/禁用状态管理
+ /// 用于控制数据记录的可用状态
+ ///
public interface IState
{
- public bool State { get; set; }
+ ///
+ /// 状态标识
+ ///
+ ///
+ /// true表示启用,false表示禁用
+ ///
+ bool State { get; set; }
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs
index 193f7909..1eb618cd 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs
@@ -7,14 +7,37 @@ using System.Threading.Tasks;
namespace Yi.Framework.Core.Enums
{
///
- /// 定义公共文件路径
+ /// 文件类型枚举
///
+ ///
+ /// 用于定义系统支持的文件类型分类
+ /// 主要用于文件上传和存储时的类型区分
+ ///
public enum FileTypeEnum
{
- file,
- image,
- thumbnail,
- excel,
- temp
+ ///
+ /// 普通文件
+ ///
+ file = 0,
+
+ ///
+ /// 图片文件
+ ///
+ image = 1,
+
+ ///
+ /// 缩略图文件
+ ///
+ thumbnail = 2,
+
+ ///
+ /// Excel文件
+ ///
+ excel = 3,
+
+ ///
+ /// 临时文件
+ ///
+ temp = 4
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/OrderByEnum.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/OrderByEnum.cs
index b1edac3a..70fbb6b8 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/OrderByEnum.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/OrderByEnum.cs
@@ -6,9 +6,23 @@ using System.Threading.Tasks;
namespace Yi.Framework.Core.Enums
{
+ ///
+ /// 排序方向枚举
+ ///
+ ///
+ /// 用于定义数据查询时的排序方向
+ /// 常用于列表数据排序
+ ///
public enum OrderByEnum
{
- Asc,
- Desc
+ ///
+ /// 升序排列
+ ///
+ Asc = 0,
+
+ ///
+ /// 降序排列
+ ///
+ Desc = 1
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs
index 13439675..f2c2613a 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs
@@ -6,67 +6,91 @@ using System.Threading.Tasks;
namespace Yi.Framework.Core.Enums
{
+ ///
+ /// 查询操作符枚举
+ ///
+ ///
+ /// 定义查询条件中支持的操作符类型
+ /// 用于构建动态查询条件
+ ///
public enum QueryOperatorEnum
{
///
- /// 相等
+ /// 等于
///
- Equal,
+ Equal = 0,
+
///
- /// 匹配
+ /// 模糊匹配
///
- Like,
+ Like = 1,
+
///
/// 大于
///
- GreaterThan,
+ GreaterThan = 2,
+
///
/// 大于或等于
///
- GreaterThanOrEqual,
+ GreaterThanOrEqual = 3,
+
///
/// 小于
///
- LessThan,
+ LessThan = 4,
+
///
/// 小于或等于
///
- LessThanOrEqual,
+ LessThanOrEqual = 5,
+
///
- /// 等于集合
+ /// 在指定集合中
///
- In,
+ In = 6,
+
///
- /// 不等于集合
+ /// 不在指定集合中
///
- NotIn,
+ NotIn = 7,
+
///
- /// 左边匹配
+ /// 左侧模糊匹配
///
- LikeLeft,
+ LikeLeft = 8,
+
///
- /// 右边匹配
+ /// 右侧模糊匹配
///
- LikeRight,
+ LikeRight = 9,
+
///
- /// 不相等
+ /// 不等于
///
- NoEqual,
+ NoEqual = 10,
+
///
- /// 为空或空
+ /// 为null或空
///
- IsNullOrEmpty,
+ IsNullOrEmpty = 11,
+
///
- /// 不为空
+ /// 不为null
///
- IsNot,
+ IsNot = 12,
+
///
/// 不匹配
///
- NoLike,
+ NoLike = 13,
+
///
- /// 时间段 值用 "|" 隔开
+ /// 日期范围
///
- DateRange
+ ///
+ /// 使用"|"分隔起始和结束日期
+ ///
+ DateRange = 14
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs
index e4197867..bb84b128 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs
@@ -6,26 +6,33 @@ using System.Threading.Tasks;
namespace Yi.Framework.Core.Enums
{
+ ///
+ /// API返回状态码枚举
+ ///
+ ///
+ /// 定义API接口统一的返回状态码
+ /// 遵循HTTP状态码规范
+ ///
public enum ResultCodeEnum
{
///
- /// 操作成功。
+ /// 操作成功
///
Success = 200,
///
- /// 操作不成功
- ///
- NotSuccess = 500,
-
- ///
- /// 无权限
+ /// 未授权访问
///
NoPermission = 401,
///
- /// 被拒绝
+ /// 访问被拒绝
///
- Denied = 403
+ Denied = 403,
+
+ ///
+ /// 操作失败
+ ///
+ NotSuccess = 500
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Extensions/HttpContextExtensions.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Extensions/HttpContextExtensions.cs
index 293d3a83..7e0b3785 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Extensions/HttpContextExtensions.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Extensions/HttpContextExtensions.cs
@@ -4,110 +4,131 @@ using Microsoft.AspNetCore.Http;
namespace Yi.Framework.Core.Extensions
{
+ ///
+ /// HttpContext扩展方法类
+ ///
public static class HttpContextExtensions
{
///
- /// 设置文件下载名称
+ /// 设置内联文件下载响应头
///
- ///
- ///
+ /// HTTP上下文
+ /// 文件名
public static void FileInlineHandle(this HttpContext httpContext, string fileName)
{
- string encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));
- httpContext.Response.Headers.Add("Content-Disposition", "inline;filename=" + encodeFilename);
-
+ var encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.UTF8);
+ httpContext.Response.Headers.Add("Content-Disposition", $"inline;filename={encodeFilename}");
}
///
- /// 设置文件附件名称
+ /// 设置附件下载响应头
///
- ///
- ///
+ /// HTTP上下文
+ /// 文件名
public static void FileAttachmentHandle(this HttpContext httpContext, string fileName)
{
- string encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));
- httpContext.Response.Headers.Add("Content-Disposition", "attachment;filename=" + encodeFilename);
-
+ var encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.UTF8);
+ httpContext.Response.Headers.Add("Content-Disposition", $"attachment;filename={encodeFilename}");
}
///
- /// 获取语言种类
+ /// 获取客户端首选语言
///
- ///
- ///
+ /// HTTP上下文
+ /// 语言代码,默认返回zh-CN
public static string GetLanguage(this HttpContext httpContext)
{
- string res = "zh-CN";
- var str = httpContext.Request.Headers["Accept-Language"].FirstOrDefault();
- if (str is not null)
- {
- res = str.Split(",")[0];
- }
- return res;
-
+ const string defaultLanguage = "zh-CN";
+ var acceptLanguage = httpContext.Request.Headers["Accept-Language"].FirstOrDefault();
+
+ return string.IsNullOrEmpty(acceptLanguage)
+ ? defaultLanguage
+ : acceptLanguage.Split(',')[0];
}
///
- /// 判断是否为异步请求
+ /// 判断是否为Ajax请求
///
- ///
- ///
+ /// HTTP请求
+ /// 是否为Ajax请求
public static bool IsAjaxRequest(this HttpRequest request)
{
- string header = request.Headers["X-Requested-With"];
- return "XMLHttpRequest".Equals(header);
+ const string ajaxHeader = "XMLHttpRequest";
+ return ajaxHeader.Equals(request.Headers["X-Requested-With"],
+ StringComparison.OrdinalIgnoreCase);
}
+
///
- /// 获取客户端IP
+ /// 获取客户端IP地址
///
- ///
- ///
+ /// HTTP上下文
+ /// 客户端IP地址
public static string GetClientIp(this HttpContext context)
{
- if (context == null) return "";
- var result = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
- if (string.IsNullOrEmpty(result))
+ const string localhost = "127.0.0.1";
+ if (context == null) return string.Empty;
+
+ // 尝试获取X-Forwarded-For头
+ var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
+
+ // 如果没有代理头,则获取远程IP
+ if (string.IsNullOrEmpty(ip))
{
- result = context.Connection.RemoteIpAddress?.ToString();
+ ip = context.Connection.RemoteIpAddress?.ToString();
}
- if (string.IsNullOrEmpty(result) || result.Contains("::1"))
- result = "127.0.0.1";
- result = result.Replace("::ffff:", "127.0.0.1");
- //如果有端口号,删除端口号
- result = Regex.Replace(result, @":\d{1,5}$", "");
- //Ip规则校验
- var regResult =
- Regex.IsMatch(result, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$")
- || Regex.IsMatch(result, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?):\d{1,5}$");
+ // 处理特殊IP
+ if (string.IsNullOrEmpty(ip) || ip.Contains("::1"))
+ {
+ return localhost;
+ }
- result = regResult ? result : "127.0.0.1";
- return result;
+ // 清理IPv6格式
+ ip = ip.Replace("::ffff:", localhost);
+
+ // 移除端口号
+ ip = Regex.Replace(ip, @":\d{1,5}$", "");
+
+ // 验证IP格式
+ var isValidIp = Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$") ||
+ Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?):\d{1,5}$");
+
+ return isValidIp ? ip : localhost;
}
///
- /// 获取浏览器标识
+ /// 获取User-Agent信息
///
- ///
- ///
+ /// HTTP上下文
+ /// User-Agent字符串
public static string GetUserAgent(this HttpContext context)
{
- return context.Request.Headers["User-Agent"];
+ return context.Request.Headers["User-Agent"].ToString();
}
+ ///
+ /// 获取用户权限声明值
+ ///
+ /// HTTP上下文
+ /// 权限声明名称
+ /// 权限值数组
public static string[]? GetUserPermissions(this HttpContext context, string permissionsName)
{
- return context.User.Claims.Where(x => x.Type == permissionsName).Select(x => x.Value).ToArray();
+ return context.User.Claims
+ .Where(x => x.Type == permissionsName)
+ .Select(x => x.Value)
+ .ToArray();
}
///
- /// 判断是否是 WebSocket 请求
+ /// 判断是否为WebSocket请求
///
- ///
- ///
+ /// HTTP上下文
+ /// 是否为WebSocket请求
public static bool IsWebSocketRequest(this HttpContext context)
{
- return context.WebSockets.IsWebSocketRequest || context.Request.Path == "/ws";
+ return context.WebSockets.IsWebSocketRequest ||
+ context.Request.Path == "/ws";
}
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Json/DatetimeJsonConverter.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Json/DatetimeJsonConverter.cs
index e4732065..c46c54d8 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Json/DatetimeJsonConverter.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Json/DatetimeJsonConverter.cs
@@ -3,25 +3,48 @@ using System.Text.Json.Serialization;
namespace Yi.Framework.Core.Json;
+///
+/// DateTime JSON序列化转换器
+///
public class DatetimeJsonConverter : JsonConverter
{
- private string _format;
- public DatetimeJsonConverter(string format="yyyy-MM-dd HH:mm:ss")
+ private readonly string _dateFormat;
+
+ ///
+ /// 初始化DateTime转换器
+ ///
+ /// 日期格式化字符串,默认为yyyy-MM-dd HH:mm:ss
+ public DatetimeJsonConverter(string format = "yyyy-MM-dd HH:mm:ss")
{
- _format = format;
+ _dateFormat = format;
}
+ ///
+ /// 从JSON读取DateTime值
+ ///
+ /// JSON读取器
+ /// 目标类型
+ /// JSON序列化选项
+ /// DateTime值
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
- if(reader.TokenType==JsonTokenType.String)
+ if (reader.TokenType == JsonTokenType.String)
{
- if (DateTime.TryParse(reader.GetString(), out DateTime dateTime)) return dateTime;
+ return DateTime.TryParse(reader.GetString(), out DateTime dateTime)
+ ? dateTime
+ : reader.GetDateTime();
}
return reader.GetDateTime();
}
+ ///
+ /// 将DateTime写入JSON
+ ///
+ /// JSON写入器
+ /// DateTime值
+ /// JSON序列化选项
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value.ToString(_format));
+ writer.WriteStringValue(value.ToString(_dateFormat));
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Modularity/YiModuleManager.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Modularity/YiModuleManager.cs
index e3b2fc4b..b83d3ad3 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/Modularity/YiModuleManager.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Modularity/YiModuleManager.cs
@@ -8,52 +8,81 @@ using Volo.Abp.Modularity;
namespace Yi.Framework.Core.Modularity;
-[Dependency(ReplaceServices =true)]
+///
+/// Yi框架模块管理器
+///
+[Dependency(ReplaceServices = true)]
public class YiModuleManager : ModuleManager, IModuleManager, ISingletonDependency
{
private readonly IModuleContainer _moduleContainer;
private readonly IEnumerable _lifecycleContributors;
private readonly ILogger _logger;
- public YiModuleManager(IModuleContainer moduleContainer, ILogger logger, IOptions options, IServiceProvider serviceProvider) : base(moduleContainer, logger, options, serviceProvider)
+ ///
+ /// 初始化模块管理器
+ ///
+ public YiModuleManager(
+ IModuleContainer moduleContainer,
+ ILogger logger,
+ IOptions options,
+ IServiceProvider serviceProvider)
+ : base(moduleContainer, logger, options, serviceProvider)
{
_moduleContainer = moduleContainer;
_logger = logger;
- _lifecycleContributors = options.Value.Contributors.Select(serviceProvider.GetRequiredService).Cast().ToArray();
+ _lifecycleContributors = options.Value.Contributors
+ .Select(serviceProvider.GetRequiredService)
+ .Cast()
+ .ToArray();
}
+ ///
+ /// 初始化所有模块
+ ///
+ /// 应用程序初始化上下文
public override async Task InitializeModulesAsync(ApplicationInitializationContext context)
{
-
_logger.LogDebug("==========模块Initialize初始化统计-跳过0ms模块==========");
- var total = 0;
- var watch =new Stopwatch();
- long totalTime = 0;
+
+ var moduleCount = 0;
+ var stopwatch = new Stopwatch();
+ var totalTime = 0L;
+
foreach (var contributor in _lifecycleContributors)
{
foreach (var module in _moduleContainer.Modules)
{
try
{
- watch.Restart();
+ stopwatch.Restart();
await contributor.InitializeAsync(context, module.Instance);
- watch.Stop();
- totalTime += watch.ElapsedMilliseconds;
- total++;
- if (watch.ElapsedMilliseconds > 1)
+ stopwatch.Stop();
+
+ totalTime += stopwatch.ElapsedMilliseconds;
+ moduleCount++;
+
+ // 仅记录耗时超过1ms的模块
+ if (stopwatch.ElapsedMilliseconds > 1)
{
- _logger.LogDebug($"耗时-{watch.ElapsedMilliseconds}ms,已加载模块-{module.Assembly.GetName().Name}");
+ _logger.LogDebug(
+ "耗时-{Time}ms,已加载模块-{ModuleName}",
+ stopwatch.ElapsedMilliseconds,
+ module.Assembly.GetName().Name);
}
-
}
catch (Exception ex)
{
- throw new AbpInitializationException($"An error occurred during the initialize {contributor.GetType().FullName} phase of the module {module.Type.AssemblyQualifiedName}: {ex.Message}. See the inner exception for details.", ex);
+ throw new AbpInitializationException(
+ $"模块 {module.Type.AssemblyQualifiedName} 在 {contributor.GetType().FullName} 阶段初始化失败: {ex.Message}",
+ ex);
}
}
}
-
- _logger.LogInformation($"==========【{total}】个模块初始化执行完毕,总耗时【{totalTime}ms】==========");
+
+ _logger.LogInformation(
+ "==========【{Count}】个模块初始化执行完毕,总耗时【{Time}ms】==========",
+ moduleCount,
+ totalTime);
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/YiFrameworkCoreModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/YiFrameworkCoreModule.cs
index 653c3911..576c20c8 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Core/YiFrameworkCoreModule.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/YiFrameworkCoreModule.cs
@@ -2,8 +2,28 @@
namespace Yi.Framework.Core
{
- public class YiFrameworkCoreModule:AbpModule
+ ///
+ /// Yi框架核心模块
+ ///
+ ///
+ /// 提供框架的基础功能和核心服务
+ ///
+ public class YiFrameworkCoreModule : AbpModule
{
+ ///
+ /// 配置服务
+ ///
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ base.ConfigureServices(context);
+ }
+ ///
+ /// 应用程序初始化
+ ///
+ public override void OnApplicationInitialization(ApplicationInitializationContext context)
+ {
+ base.OnApplicationInitialization(context);
+ }
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IDeletesAppService.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IDeletesAppService.cs
index e5e3fc95..a25addd2 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IDeletesAppService.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IDeletesAppService.cs
@@ -3,8 +3,17 @@ using Volo.Abp.Application.Services;
namespace Yi.Framework.Ddd.Application.Contracts
{
- public interface IDeletesAppService : IDeleteAppService< TKey> , IApplicationService, IRemoteService
+ ///
+ /// 批量删除服务接口
+ ///
+ /// 主键类型
+ public interface IDeletesAppService : IDeleteAppService, IApplicationService, IRemoteService
{
+ ///
+ /// 批量删除实体
+ ///
+ /// 要删除的实体ID集合
+ /// 删除操作的异步任务
Task DeleteAsync(IEnumerable ids);
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IPageTimeResultRequestDto.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IPageTimeResultRequestDto.cs
index a2e816fd..b0223a39 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IPageTimeResultRequestDto.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IPageTimeResultRequestDto.cs
@@ -2,9 +2,19 @@
namespace Yi.Framework.Ddd.Application.Contracts
{
+ ///
+ /// 带时间范围的分页查询请求接口
+ ///
public interface IPageTimeResultRequestDto : IPagedAndSortedResultRequest
{
+ ///
+ /// 查询开始时间
+ ///
DateTime? StartTime { get; set; }
+
+ ///
+ /// 查询结束时间
+ ///
DateTime? EndTime { get; set; }
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IPagedAllResultRequestDto.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IPagedAllResultRequestDto.cs
index 283b4530..2b5ea40a 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IPagedAllResultRequestDto.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IPagedAllResultRequestDto.cs
@@ -2,6 +2,9 @@
namespace Yi.Framework.Ddd.Application.Contracts
{
+ ///
+ /// 分页查询请求接口,包含时间范围和排序功能
+ ///
public interface IPagedAllResultRequestDto : IPageTimeResultRequestDto, IPagedAndSortedResultRequest
{
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IYiCrudAppService.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IYiCrudAppService.cs
index 71e1fc89..3afe3988 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IYiCrudAppService.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IYiCrudAppService.cs
@@ -7,24 +7,47 @@ using Volo.Abp.Application.Services;
namespace Yi.Framework.Ddd.Application.Contracts
{
+ ///
+ /// Yi框架CRUD服务基础接口
+ ///
+ /// 实体DTO类型
+ /// 主键类型
public interface IYiCrudAppService : ICrudAppService
{
}
+ ///
+ /// Yi框架CRUD服务接口(带查询输入)
+ ///
+ /// 实体DTO类型
+ /// 主键类型
+ /// 查询输入类型
public interface IYiCrudAppService : ICrudAppService
{
}
+ ///
+ /// Yi框架CRUD服务接口(带查询输入和创建输入)
+ ///
+ /// 实体DTO类型
+ /// 主键类型
+ /// 查询输入类型
+ /// 创建输入类型
public interface IYiCrudAppService : ICrudAppService
{
}
+ ///
+ /// Yi框架CRUD服务接口(带查询、创建和更新输入)
+ ///
public interface IYiCrudAppService : ICrudAppService
{
}
+ ///
+ /// Yi框架完整CRUD服务接口(包含所有操作和批量删除功能)
+ ///
public interface IYiCrudAppService : ICrudAppService, IDeletesAppService
{
-
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/PagedAllResultRequestDto.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/PagedAllResultRequestDto.cs
index c9757489..24e1c65f 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/PagedAllResultRequestDto.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/PagedAllResultRequestDto.cs
@@ -2,48 +2,50 @@
namespace Yi.Framework.Ddd.Application.Contracts
{
+ ///
+ /// 分页查询请求DTO,包含时间范围和自定义排序功能
+ ///
public class PagedAllResultRequestDto : PagedAndSortedResultRequestDto, IPagedAllResultRequestDto
{
///
- /// 查询开始时间条件
+ /// 查询开始时间
///
public DateTime? StartTime { get; set; }
///
- /// 查询结束时间条件
+ /// 查询结束时间
///
public DateTime? EndTime { get; set; }
///
- /// 排序列名,字段名对应前端
+ /// 排序列名
///
public string? OrderByColumn { get; set; }
///
- /// 是否顺序,字段名对应前端
+ /// 排序方向(ascending/descending)
///
public string? IsAsc { get; set; }
///
- /// 是否顺序
+ /// 是否为升序排序
///
- public bool CanAsc => IsAsc?.ToLower() == "ascending" ? true : false;
+ public bool IsAscending => string.Equals(IsAsc, "ascending", StringComparison.OrdinalIgnoreCase);
- private string _sorting;
+ private string? _sorting;
- //排序引用
- public new string? Sorting
+ ///
+ /// 排序表达式
+ ///
+ public override string? Sorting
{
get
{
- if (!OrderByColumn.IsNullOrWhiteSpace())
+ if (!string.IsNullOrWhiteSpace(OrderByColumn))
{
- return $"{OrderByColumn} {(CanAsc ? "ASC" : "DESC")}";
- }
- else
- {
- return _sorting;
+ return $"{OrderByColumn} {(IsAscending ? "ASC" : "DESC")}";
}
+ return _sorting;
}
set => _sorting = value;
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/YiFrameworkDddApplicationContractsModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/YiFrameworkDddApplicationContractsModule.cs
index 63e7758f..c231fec5 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/YiFrameworkDddApplicationContractsModule.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/YiFrameworkDddApplicationContractsModule.cs
@@ -3,6 +3,9 @@ using Volo.Abp.Modularity;
namespace Yi.Framework.Ddd.Application.Contracts
{
+ ///
+ /// Yi框架DDD应用层契约模块
+ ///
[DependsOn(typeof(AbpDddApplicationContractsModule))]
public class YiFrameworkDddApplicationContractsModule : AbpModule
{
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiCacheCrudAppService.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiCacheCrudAppService.cs
index d10cdd82..ed2d54ab 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiCacheCrudAppService.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiCacheCrudAppService.cs
@@ -6,11 +6,19 @@ using Volo.Abp.MultiTenancy;
namespace Yi.Framework.Ddd.Application
{
- public abstract class YiCacheCrudAppService : YiCrudAppService
- where TEntity : class, IEntity
- where TEntityDto : IEntityDto
+ ///
+ /// 带缓存的CRUD应用服务基类
+ ///
+ /// 实体类型
+ /// 实体DTO类型
+ /// 主键类型
+ public abstract class YiCacheCrudAppService
+ : YiCrudAppService
+ where TEntity : class, IEntity
+ where TEntityDto : IEntityDto
{
- protected YiCacheCrudAppService(IRepository repository) : base(repository)
+ protected YiCacheCrudAppService(IRepository repository)
+ : base(repository)
{
}
}
@@ -47,73 +55,92 @@ namespace Yi.Framework.Ddd.Application
}
+ ///
+ /// 完整的带缓存CRUD应用服务实现
+ ///
public abstract class YiCacheCrudAppService
: YiCrudAppService
- where TEntity : class, IEntity
- where TGetOutputDto : IEntityDto
- where TGetListOutputDto : IEntityDto
+ where TEntity : class, IEntity
+ where TGetOutputDto : IEntityDto
+ where TGetListOutputDto : IEntityDto
{
- protected IDistributedCache Cache => LazyServiceProvider.LazyGetRequiredService>();
+ ///
+ /// 分布式缓存访问器
+ ///
+ private IDistributedCache EntityCache =>
+ LazyServiceProvider.LazyGetRequiredService>();
- protected string GetCacheKey(TKey id) => typeof(TEntity).Name + ":" + CurrentTenant.Id ?? Guid.Empty + ":" + id.ToString();
- protected YiCacheCrudAppService(IRepository repository) : base(repository)
+ ///
+ /// 获取缓存键
+ ///
+ protected virtual string GenerateCacheKey(TKey id) =>
+ $"{typeof(TEntity).Name}:{CurrentTenant.Id ?? Guid.Empty}:{id}";
+
+ protected YiCacheCrudAppService(IRepository repository)
+ : base(repository)
{
}
- public override async Task UpdateAsync(TKey id, TUpdateInput input)
+ ///
+ /// 更新实体并清除缓存
+ ///
+ public override async Task UpdateAsync(TKey id, TUpdateInput input)
{
- var output = await base.UpdateAsync(id, input);
- await Cache.RemoveAsync(GetCacheKey(id));
- return output;
+ var result = await base.UpdateAsync(id, input);
+ await EntityCache.RemoveAsync(GenerateCacheKey(id));
+ return result;
}
- public override async Task> GetListAsync(TGetListInput input)
+ ///
+ /// 获取实体列表(需要继承实现具体的缓存策略)
+ ///
+ public override Task> GetListAsync(TGetListInput input)
{
- //两种方式:
- //1:全表缓存,使用缓存直接查询
- //2:非全部缓存,查询到的数据直接添加到缓存
-
- //判断是否该实体为全表缓存
- throw new NotImplementedException();
-
- //IDistributedCache 有局限性,条件查询无法进行缓存了
- //if (true)
- //{
- // return await GetListByCacheAsync(input);
- //}
- //else
- //{
- // return await GetListByDbAsync(input);
- //}
-
+ // 建议实现两种缓存策略:
+ // 1. 全表缓存: 适用于数据量小且变动不频繁的场景
+ // 2. 按需缓存: 仅缓存常用数据,适用于大数据量场景
+ throw new NotImplementedException("请实现具体的缓存查询策略");
}
- protected virtual async Task> GetListByDbAsync(TGetListInput input)
+ ///
+ /// 从数据库获取实体列表
+ ///
+ protected virtual Task> GetListFromDatabaseAsync(
+ TGetListInput input)
{
- //如果不是全表缓存,可以走这个啦
- throw new NotImplementedException();
- }
- protected virtual async Task> GetListByCacheAsync(TGetListInput input)
- {
- //如果是全表缓存,可以走这个啦
throw new NotImplementedException();
}
+ ///
+ /// 从缓存获取实体列表
+ ///
+ protected virtual Task> GetListFromCacheAsync(
+ TGetListInput input)
+ {
+ throw new NotImplementedException();
+ }
+ ///
+ /// 获取单个实体(优先从缓存获取)
+ ///
protected override async Task GetEntityByIdAsync(TKey id)
{
- var output = await Cache.GetOrAddAsync(GetCacheKey(id), async () => await base.GetEntityByIdAsync(id));
- return output!;
+ return (await EntityCache.GetOrAddAsync(
+ GenerateCacheKey(id),
+ async () => await base.GetEntityByIdAsync(id)))!;
}
- public override async Task DeleteAsync(IEnumerable id)
+ ///
+ /// 批量删除实体并清除缓存
+ ///
+ public override async Task DeleteAsync(IEnumerable ids)
{
- await base.DeleteAsync(id);
- foreach (var itemId in id)
- {
- await Cache.RemoveAsync(GetCacheKey(itemId));
- }
-
+ await base.DeleteAsync(ids);
+
+ // 批量清除缓存
+ var tasks = ids.Select(id =>
+ EntityCache.RemoveAsync(GenerateCacheKey(id)));
+ await Task.WhenAll(tasks);
}
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiCrudAppService.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiCrudAppService.cs
index b2d1475c..3ead8bcc 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiCrudAppService.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiCrudAppService.cs
@@ -8,183 +8,244 @@ using Volo.Abp.Domain.Repositories;
namespace Yi.Framework.Ddd.Application
{
- public abstract class
- YiCrudAppService : YiCrudAppService
+ ///
+ /// CRUD应用服务基类 - 基础版本
+ ///
+ public abstract class YiCrudAppService
+ : YiCrudAppService
where TEntity : class, IEntity
where TEntityDto : IEntityDto
{
- protected YiCrudAppService(IRepository repository) : base(repository)
+ protected YiCrudAppService(IRepository repository)
+ : base(repository)
{
}
}
+ ///
+ /// CRUD应用服务基类 - 支持自定义查询输入
+ ///
public abstract class YiCrudAppService
: YiCrudAppService
where TEntity : class, IEntity
where TEntityDto : IEntityDto
{
- protected YiCrudAppService(IRepository repository) : base(repository)
+ protected YiCrudAppService(IRepository repository)
+ : base(repository)
{
}
}
-
+ ///
+ /// CRUD应用服务基类 - 支持自定义创建输入
+ ///
public abstract class YiCrudAppService
: YiCrudAppService
where TEntity : class, IEntity
where TEntityDto : IEntityDto
{
- protected YiCrudAppService(IRepository repository) : base(repository)
+ protected YiCrudAppService(IRepository repository)
+ : base(repository)
{
}
}
+ ///
+ /// CRUD应用服务基类 - 支持自定义更新输入
+ ///
public abstract class YiCrudAppService
: YiCrudAppService
where TEntity : class, IEntity
where TEntityDto : IEntityDto
{
- protected YiCrudAppService(IRepository repository) : base(repository)
+ protected YiCrudAppService(IRepository repository)
+ : base(repository)
{
}
}
-
- public abstract class YiCrudAppService
+ ///
+ /// CRUD应用服务基类 - 完整实现
+ ///
+ public abstract class YiCrudAppService
: CrudAppService
where TEntity : class, IEntity
where TGetOutputDto : IEntityDto
where TGetListOutputDto : IEntityDto
{
- protected YiCrudAppService(IRepository repository) : base(repository)
+ ///
+ /// 临时文件存储路径
+ ///
+ private const string TempFilePath = "/wwwroot/temp";
+
+ protected YiCrudAppService(IRepository repository)
+ : base(repository)
{
}
+ ///
+ /// 更新实体
+ ///
+ /// 实体ID
+ /// 更新输入
+ /// 更新后的实体DTO
public override async Task UpdateAsync(TKey id, TUpdateInput input)
{
+ // 检查更新权限
await CheckUpdatePolicyAsync();
+ // 获取并验证实体
var entity = await GetEntityByIdAsync(id);
- await CheckUpdateInputDtoAsync(entity,input);
+
+ // 检查更新输入
+ await CheckUpdateInputDtoAsync(entity, input);
+ // 映射并更新实体
await MapToEntityAsync(input, entity);
await Repository.UpdateAsync(entity, autoSave: true);
return await MapToGetOutputDtoAsync(entity);
}
- protected virtual Task CheckUpdateInputDtoAsync(TEntity entity,TUpdateInput input)
+ ///
+ /// 检查更新输入数据的有效性
+ ///
+ protected virtual Task CheckUpdateInputDtoAsync(TEntity entity, TUpdateInput input)
{
return Task.CompletedTask;
}
+ ///
+ /// 创建实体
+ ///
+ /// 创建输入
+ /// 创建后的实体DTO
public override async Task CreateAsync(TCreateInput input)
{
+ // 检查创建权限
await CheckCreatePolicyAsync();
+
+ // 检查创建输入
await CheckCreateInputDtoAsync(input);
+
+ // 映射到实体
var entity = await MapToEntityAsync(input);
+ // 设置租户ID
TryToSetTenantId(entity);
+ // 插入实体
await Repository.InsertAsync(entity, autoSave: true);
return await MapToGetOutputDtoAsync(entity);
}
+ ///
+ /// 检查创建输入数据的有效性
+ ///
protected virtual Task CheckCreateInputDtoAsync(TCreateInput input)
{
return Task.CompletedTask;
}
///
- /// 多查
+ /// 获取实体列表
///
- ///
- ///
+ /// 查询输入
+ /// 分页结果
public override async Task> GetListAsync(TGetListInput input)
{
- List? entites = null;
- //区分多查还是批量查
+ List entities;
+
+ // 根据输入类型决定查询方式
if (input is IPagedResultRequest pagedInput)
{
- entites = await Repository.GetPagedListAsync(pagedInput.SkipCount, pagedInput.MaxResultCount,
- string.Empty);
+ // 分页查询
+ entities = await Repository.GetPagedListAsync(
+ pagedInput.SkipCount,
+ pagedInput.MaxResultCount,
+ string.Empty
+ );
}
else
{
- entites = await Repository.GetListAsync();
+ // 查询全部
+ entities = await Repository.GetListAsync();
}
- var total = await Repository.GetCountAsync();
- var output = await MapToGetListOutputDtosAsync(entites);
- return new PagedResultDto(total, output);
- //throw new NotImplementedException($"【{typeof(TEntity)}】实体的CrudAppService,查询为具体业务,通用查询几乎无实际场景,请重写实现!");
+ // 获取总数并映射结果
+ var totalCount = await Repository.GetCountAsync();
+ var dtos = await MapToGetListOutputDtosAsync(entities);
+
+ return new PagedResultDto(totalCount, dtos);
}
///
- /// 多删
+ /// 批量删除实体
///
- ///
- ///
+ /// 实体ID集合
[RemoteService(isEnabled: true)]
- public virtual async Task DeleteAsync(IEnumerable id)
+ public virtual async Task DeleteAsync(IEnumerable ids)
{
- await Repository.DeleteManyAsync(id);
+ await Repository.DeleteManyAsync(ids);
}
///
- /// 偷梁换柱
+ /// 单个删除实体(禁用远程访问)
///
- ///
- ///
[RemoteService(isEnabled: false)]
public override Task DeleteAsync(TKey id)
{
return base.DeleteAsync(id);
}
-
///
- /// 导出excel
+ /// 导出Excel
///
- ///
- ///
+ /// 查询条件
+ /// Excel文件
public virtual async Task GetExportExcelAsync(TGetListInput input)
{
+ // 重置分页参数以获取全部数据
if (input is IPagedResultRequest paged)
{
paged.SkipCount = 0;
paged.MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount;
}
- var output = await this.GetListAsync(input);
- var dirPath = $"/wwwroot/temp";
+ // 获取数据
+ var output = await GetListAsync(input);
- var fileName = $"{typeof(TEntity).Name}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}_{Guid.NewGuid()}";
- var filePath = $"{dirPath}/{fileName}.xlsx";
- if (!Directory.Exists(dirPath))
+ // 确保临时目录存在
+ if (!Directory.Exists(TempFilePath))
{
- Directory.CreateDirectory(dirPath);
+ Directory.CreateDirectory(TempFilePath);
}
- MiniExcel.SaveAs(filePath, output.Items);
+ // 生成文件名和路径
+ var fileName = GenerateExcelFileName();
+ var filePath = Path.Combine(TempFilePath, fileName);
+
+ // 保存Excel文件
+ await MiniExcel.SaveAsAsync(filePath, output.Items);
+
return new PhysicalFileResult(filePath, "application/vnd.ms-excel");
}
///
- /// 导入excle
+ /// 生成Excel文件名
///
- ///
- ///
- public virtual async Task PostImportExcelAsync(List input)
+ private string GenerateExcelFileName()
{
- var entities = input.Select(x => MapToEntity(x)).ToList();
- //安全起见,该接口需要自己实现
- throw new NotImplementedException();
- //await Repository.DeleteManyAsync(entities.Select(x => x.Id));
- //await Repository.InsertManyAsync(entities);
+ return $"{typeof(TEntity).Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{Guid.NewGuid()}.xlsx";
+ }
+
+ ///
+ /// 导入Excel(需要实现类重写此方法)
+ ///
+ public virtual Task PostImportExcelAsync(List input)
+ {
+ throw new NotImplementedException("请在实现类中重写此方法以支持Excel导入");
}
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiFrameworkDddApplicationModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiFrameworkDddApplicationModule.cs
index e2781601..d4657568 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiFrameworkDddApplicationModule.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application/YiFrameworkDddApplicationModule.cs
@@ -6,14 +6,34 @@ using Yi.Framework.Ddd.Application.Contracts;
namespace Yi.Framework.Ddd.Application
{
- [DependsOn(typeof(AbpDddApplicationModule),
- typeof(YiFrameworkDddApplicationContractsModule))]
+ ///
+ /// Yi框架DDD应用层模块
+ ///
+ [DependsOn(
+ typeof(AbpDddApplicationModule),
+ typeof(YiFrameworkDddApplicationContractsModule)
+ )]
public class YiFrameworkDddApplicationModule : AbpModule
{
+ ///
+ /// 应用程序初始化配置
+ ///
+ /// 应用程序初始化上下文
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
- //分页限制
+ // 配置分页查询的默认值和最大值限制
+ ConfigureDefaultPagingSettings();
+ }
+
+ ///
+ /// 配置默认分页设置
+ ///
+ private void ConfigureDefaultPagingSettings()
+ {
+ // 设置默认每页显示记录数
LimitedResultRequestDto.DefaultMaxResultCount = 10;
+
+ // 设置最大允许的每页记录数
LimitedResultRequestDto.MaxMaxResultCount = 10000;
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Mapster/MapsterAutoObjectMappingProvider.cs b/Yi.Abp.Net8/framework/Yi.Framework.Mapster/MapsterAutoObjectMappingProvider.cs
index 3c6b73eb..60660b35 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Mapster/MapsterAutoObjectMappingProvider.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Mapster/MapsterAutoObjectMappingProvider.cs
@@ -8,17 +8,37 @@ using Volo.Abp.ObjectMapping;
namespace Yi.Framework.Mapster
{
+ ///
+ /// Mapster自动对象映射提供程序
+ /// 实现IAutoObjectMappingProvider接口,提供对象间的自动映射功能
+ ///
public class MapsterAutoObjectMappingProvider : IAutoObjectMappingProvider
{
+ ///
+ /// 将源对象映射到目标类型
+ ///
+ /// 源类型
+ /// 目标类型
+ /// 源对象
+ /// 映射后的目标类型实例
public TDestination Map(object source)
{
- var sss = typeof(TDestination).Name;
+ // 使用Mapster的Adapt方法进行对象映射
return source.Adapt();
}
+ ///
+ /// 将源对象映射到现有的目标对象
+ ///
+ /// 源类型
+ /// 目标类型
+ /// 源对象
+ /// 目标对象
+ /// 映射后的目标对象
public TDestination Map(TSource source, TDestination destination)
{
- return source.Adapt(destination);
+ // 使用Mapster的Adapt方法进行对象映射,保留目标对象的实例
+ return source.Adapt(destination);
}
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Mapster/MapsterObjectMapper.cs b/Yi.Abp.Net8/framework/Yi.Framework.Mapster/MapsterObjectMapper.cs
index 7cbe8804..11b9b5e1 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Mapster/MapsterObjectMapper.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Mapster/MapsterObjectMapper.cs
@@ -7,18 +7,51 @@ using Volo.Abp.ObjectMapping;
namespace Yi.Framework.Mapster
{
+ ///
+ /// Mapster对象映射器
+ /// 实现IObjectMapper接口,提供对象映射功能
+ ///
public class MapsterObjectMapper : IObjectMapper
{
- public IAutoObjectMappingProvider AutoObjectMappingProvider => throw new NotImplementedException();
+ private readonly IAutoObjectMappingProvider _autoObjectMappingProvider;
- public TDestination Map(TSource source)
+ ///
+ /// 构造函数
+ ///
+ /// 自动对象映射提供程序
+ public MapsterObjectMapper(IAutoObjectMappingProvider autoObjectMappingProvider)
{
- throw new NotImplementedException();
+ _autoObjectMappingProvider = autoObjectMappingProvider;
}
+ ///
+ /// 获取自动对象映射提供程序
+ ///
+ public IAutoObjectMappingProvider AutoObjectMappingProvider => _autoObjectMappingProvider;
+
+ ///
+ /// 将源对象映射到目标类型
+ ///
+ /// 源类型
+ /// 目标类型
+ /// 源对象
+ /// 映射后的目标类型实例
+ public TDestination Map(TSource source)
+ {
+ return AutoObjectMappingProvider.Map(source);
+ }
+
+ ///
+ /// 将源对象映射到现有的目标对象
+ ///
+ /// 源类型
+ /// 目标类型
+ /// 源对象
+ /// 目标对象
+ /// 映射后的目标对象
public TDestination Map(TSource source, TDestination destination)
{
- throw new NotImplementedException();
+ return AutoObjectMappingProvider.Map(source, destination);
}
}
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Mapster/YiFrameworkMapsterModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.Mapster/YiFrameworkMapsterModule.cs
index 5df08b25..78f93dd1 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.Mapster/YiFrameworkMapsterModule.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.Mapster/YiFrameworkMapsterModule.cs
@@ -1,21 +1,31 @@
-using MapsterMapper;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectMapping;
using Yi.Framework.Core;
namespace Yi.Framework.Mapster
{
- [DependsOn(typeof(YiFrameworkCoreModule),
-
+ ///
+ /// Yi框架Mapster模块
+ /// 用于配置和注册Mapster相关服务
+ ///
+ [DependsOn(
+ typeof(YiFrameworkCoreModule),
typeof(AbpObjectMappingModule)
- )]
+ )]
public class YiFrameworkMapsterModule : AbpModule
{
+ ///
+ /// 配置服务
+ ///
+ /// 服务配置上下文
public override void ConfigureServices(ServiceConfigurationContext context)
{
- context.Services.AddTransient();
+ var services = context.Services;
+
+ // 注册Mapster相关服务
+ services.AddTransient();
+ services.AddTransient();
}
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs
index 6533950c..6f48f14d 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs
@@ -3,10 +3,14 @@ using ArgumentException = System.ArgumentException;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
+ ///
+ /// 数据库连接配置选项
+ ///
public class DbConnOptions
{
///
- /// 连接字符串(如果开启多租户,也就是默认库了),必填
+ /// 主数据库连接字符串
+ /// 如果开启多租户,此为默认租户数据库
///
public string? Url { get; set; }
@@ -16,42 +20,42 @@ namespace Yi.Framework.SqlSugarCore.Abstractions
public DbType? DbType { get; set; }
///
- /// 开启种子数据
+ /// 是否启用种子数据初始化
///
public bool EnabledDbSeed { get; set; } = false;
///
- /// 开启驼峰转下划线
+ /// 是否启用驼峰命名转下划线命名
///
public bool EnableUnderLine { get; set; } = false;
///
- /// 开启codefirst
+ /// 是否启用Code First模式
///
public bool EnabledCodeFirst { get; set; } = false;
///
- /// 开启sql日志
+ /// 是否启用SQL日志记录
///
public bool EnabledSqlLog { get; set; } = true;
///
- /// 实体程序集
+ /// 实体类所在程序集名称列表
///
public List? EntityAssembly { get; set; }
///
- /// 开启读写分离
+ /// 是否启用读写分离
///
public bool EnabledReadWrite { get; set; } = false;
///
- /// 读写分离
+ /// 只读数据库连接字符串列表
///
public List? ReadUrl { get; set; }
///
- /// 开启Saas多租户
+ /// 是否启用SaaS多租户
///
public bool EnabledSaasMultiTenancy { get; set; } = false;
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DefaultTenantTableAttribute.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DefaultTenantTableAttribute.cs
index 2b2519ef..85684833 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DefaultTenantTableAttribute.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DefaultTenantTableAttribute.cs
@@ -4,10 +4,13 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace Yi.Framework.SqlSugarCore.Abstractions
+namespace Yi.Framework.SqlSugarCore.Abstractions;
+
+///
+/// 默认租户表特性
+/// 标记此特性的实体类将在默认租户数据库中创建表
+///
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
+public sealed class DefaultTenantTableAttribute : Attribute
{
- [AttributeUsage(AttributeTargets.Class)]
- public class DefaultTenantTableAttribute : Attribute
- {
- }
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContext.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContext.cs
index cb736291..e1a509b1 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContext.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContext.cs
@@ -8,15 +8,18 @@ using Volo.Abp.DependencyInjection;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
+ ///
+ /// SqlSugar数据库上下文接口
+ ///
public interface ISqlSugarDbContext
{
///
- /// SqlSugarDb
+ /// 获取SqlSugar客户端实例
///
ISqlSugarClient SqlSugarClient { get; }
///
- /// 数据库备份
+ /// 执行数据库备份
///
void BackupDataBase();
}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContextDependencies.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContextDependencies.cs
index f41bb88d..5d65e90c 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContextDependencies.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContextDependencies.cs
@@ -3,19 +3,55 @@ using SqlSugar;
namespace Yi.Framework.SqlSugarCore.Abstractions;
+///
+/// SqlSugar数据库上下文依赖接口
+/// 定义数据库操作的各个生命周期钩子
+///
public interface ISqlSugarDbContextDependencies
{
///
- /// 执行顺序
+ /// 获取执行顺序
///
int ExecutionOrder { get; }
+ ///
+ /// SqlSugar客户端配置时触发
+ ///
+ /// SqlSugar客户端实例
void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient);
+
+ ///
+ /// 数据执行后触发
+ ///
+ /// 原始值
+ /// 实体信息
void DataExecuted(object oldValue, DataAfterModel entityInfo);
+
+ ///
+ /// 数据执行前触发
+ ///
+ /// 原始值
+ /// 实体信息
void DataExecuting(object oldValue, DataFilterModel entityInfo);
- void OnLogExecuting(string sql, SugarParameter[] pars);
- void OnLogExecuted(string sql, SugarParameter[] pars);
+ ///
+ /// SQL执行前触发
+ ///
+ /// SQL语句
+ /// SQL参数
+ void OnLogExecuting(string sql, SugarParameter[] parameters);
+
+ ///
+ /// SQL执行后触发
+ ///
+ /// SQL语句
+ /// SQL参数
+ void OnLogExecuted(string sql, SugarParameter[] parameters);
+ ///
+ /// 实体服务配置
+ ///
+ /// 属性信息
+ /// 实体列信息
void EntityService(PropertyInfo propertyInfo, EntityColumnInfo entityColumnInfo);
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarRepository.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarRepository.cs
index d581f813..06c00009 100644
--- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarRepository.cs
+++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarRepository.cs
@@ -6,84 +6,242 @@ using Volo.Abp.Uow;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
-
- public interface ISqlSugarRepository:IRepository,IUnitOfWorkEnabled where TEntity : class, IEntity,new ()
+ ///
+ /// SqlSugar仓储接口
+ ///
+ /// 实体类型
+ public interface ISqlSugarRepository : IRepository, IUnitOfWorkEnabled
+ where TEntity : class, IEntity, new()
{
+ #region 数据库访问器
+
+ ///
+ /// 获取SqlSugar客户端实例
+ ///
ISqlSugarClient _Db { get; }
+
+ ///
+ /// 获取查询构造器
+ ///
ISugarQueryable _DbQueryable { get; }
+ ///
+ /// 异步获取数据库上下文
+ ///
Task GetDbContextAsync();
+
+ ///
+ /// 获取删除操作构造器
+ ///
Task> AsDeleteable();
- Task> AsInsertable(List insertObjs);
- Task> AsInsertable(TEntity insertObj);
- Task> AsInsertable(TEntity[] insertObjs);
+
+ ///
+ /// 获取插入操作构造器
+ ///
+ Task> AsInsertable(TEntity entity);
+
+ ///
+ /// 获取批量插入操作构造器
+ ///
+ Task> AsInsertable(List entities);
+
+ ///
+ /// 获取查询构造器
+ ///
Task> AsQueryable();
+
+ ///
+ /// 获取SqlSugar客户端
+ ///
Task AsSugarClient();
+
+ ///
+ /// 获取租户操作接口
+ ///
Task AsTenant();
- Task> AsUpdateable(List updateObjs);
- Task> AsUpdateable(TEntity updateObj);
+
+ ///
+ /// 获取更新操作构造器
+ ///
Task> AsUpdateable();
- Task> AsUpdateable(TEntity[] updateObjs);
- #region 单查
- //单查
+ ///
+ /// 获取实体更新操作构造器
+ ///
+ Task> AsUpdateable(TEntity entity);
+
+ ///
+ /// 获取批量更新操作构造器
+ ///
+ Task> AsUpdateable(List entities);
+
+ #endregion
+
+ #region 查询操作
+
+ ///
+ /// 根据主键获取实体
+ ///
Task GetByIdAsync(dynamic id);
- Task GetSingleAsync(Expression> whereExpression);
- Task GetFirstAsync(Expression> whereExpression);
- Task IsAnyAsync(Expression> whereExpression);
- Task CountAsync(Expression> whereExpression);
- #endregion
+ ///
+ /// 获取满足条件的单个实体
+ ///
+ Task GetSingleAsync(Expression> predicate);
+ ///
+ /// 获取满足条件的第一个实体
+ ///
+ Task GetFirstAsync(Expression> predicate);
- #region 多查
- //多查
+ ///
+ /// 判断是否存在满足条件的实体
+ ///
+ Task IsAnyAsync(Expression> predicate);
+
+ ///
+ /// 获取满足条件的实体数量
+ ///
+ Task CountAsync(Expression> predicate);
+
+ ///
+ /// 获取所有实体
+ ///
Task> GetListAsync();
- Task> GetListAsync(Expression> whereExpression);
+
+ ///
+ /// 获取满足条件的所有实体
+ ///
+ Task> GetListAsync(Expression> predicate);
+
#endregion
+ #region 分页查询
+
+ ///
+ /// 获取分页数据
+ ///
+ Task> GetPageListAsync(
+ Expression> predicate,
+ int pageIndex,
+ int pageSize);
+
+ ///
+ /// 获取排序的分页数据
+ ///
+ Task> GetPageListAsync(
+ Expression> predicate,
+ int pageIndex,
+ int pageSize,
+ Expression>? orderByExpression = null,
+ OrderByType orderByType = OrderByType.Asc);
- #region 分页查
- //分页查
- Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize);
- Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize, Expression>? orderByExpression = null, OrderByType orderByType = OrderByType.Asc);
#endregion
- #region 插入
- //插入
- Task InsertAsync(TEntity insertObj);
- Task InsertOrUpdateAsync(TEntity data);
- Task InsertOrUpdateAsync(List datas);
- Task InsertReturnIdentityAsync(TEntity insertObj);
- Task InsertReturnBigIdentityAsync(TEntity insertObj);
- Task InsertReturnSnowflakeIdAsync(TEntity insertObj);
- Task InsertReturnEntityAsync(TEntity insertObj);
- Task InsertRangeAsync(List insertObjs);
+ #region 插入操作
+
+ ///
+ /// 插入实体
+ ///
+ Task InsertAsync(TEntity entity);
+
+ ///
+ /// 插入或更新实体
+ ///
+ Task InsertOrUpdateAsync(TEntity entity);
+
+ ///
+ /// 批量插入或更新实体
+ ///
+ Task InsertOrUpdateAsync(List entities);
+
+ ///
+ /// 插入实体并返回自增主键
+ ///
+ Task InsertReturnIdentityAsync(TEntity entity);
+
+ ///
+ /// 插入实体并返回长整型自增主键
+ ///
+ Task InsertReturnBigIdentityAsync(TEntity entity);
+
+ ///
+ /// 插入实体并返回雪花ID
+ ///
+ Task InsertReturnSnowflakeIdAsync(TEntity entity);
+
+ ///
+ /// 插入实体并返回实体
+ ///
+ Task InsertReturnEntityAsync(TEntity entity);
+
+ ///
+ /// 批量插入实体
+ ///
+ Task InsertRangeAsync(List entities);
+
#endregion
+ #region 更新操作
+
+ ///
+ /// 更新实体
+ ///
+ Task UpdateAsync(TEntity entity);
+
+ ///
+ /// 批量更新实体
+ ///
+ Task UpdateRangeAsync(List entities);
+
+ ///
+ /// 条件更新指定列
+ ///
+ Task UpdateAsync(
+ Expression> columns,
+ Expression> predicate);
- #region 更新
- //更新
- Task UpdateAsync(TEntity updateObj);
- Task UpdateRangeAsync(List