mirror of
				https://github.com/nsnail/NetAdmin.git
				synced 2025-10-30 19:09:25 +08:00 
			
		
		
		
	refactor: ♻️ 业务代码项目文件名与框架代码项目文件名区分 (#196)
Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
		
							
								
								
									
										4
									
								
								.github/workflows/nightly-build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/nightly-build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -37,8 +37,8 @@ jobs: | ||||
|           path: ~/.nuget/packages | ||||
|           key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} | ||||
|           restore-keys: ${{ runner.os }}-nuget | ||||
|       - working-directory: ./src/backend/NetAdmin.AdmServer.Host | ||||
|         run: dotnet publish NetAdmin.AdmServer.Host.csproj -c Release | ||||
|       - working-directory: ./src/backend/YourSolution.AdmServer.Host | ||||
|         run: dotnet publish YourSolution.AdmServer.Host.csproj -c Release | ||||
|       - run: docker build -t nsnail/netadmin:nightly . | ||||
|       - uses: docker/login-action@v3 | ||||
|         with: | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -37,8 +37,8 @@ jobs: | ||||
|           path: ~/.nuget/packages | ||||
|           key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} | ||||
|           restore-keys: ${{ runner.os }}-nuget | ||||
|       - working-directory: ./src/backend/NetAdmin.AdmServer.Host | ||||
|         run: dotnet publish NetAdmin.AdmServer.Host.csproj -c Release | ||||
|       - working-directory: ./src/backend/YourSolution.AdmServer.Host | ||||
|         run: dotnet publish YourSolution.AdmServer.Host.csproj -c Release | ||||
|       - uses: actions/create-release@v1 | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|   | ||||
| @@ -32,6 +32,6 @@ | ||||
|         </PackageReference> | ||||
|     </ItemGroup> | ||||
|     <ItemGroup> | ||||
|         <Compile Include="../GlobalUsings.cs" Link="GlobalUsings.cs" /> | ||||
|         <Compile Include="$(SolutionDir)/src/backend/GlobalUsings.cs" Link="GlobalUsings.cs" /> | ||||
|     </ItemGroup> | ||||
| </Project> | ||||
| @@ -3,5 +3,5 @@ WORKDIR /app | ||||
| EXPOSE 8080 | ||||
| RUN apt update | ||||
| RUN apt install -y redis | ||||
| COPY ./dist/backend/NetAdmin.AdmServer.Host/bin/Release/net9.0/publish . | ||||
| ENTRYPOINT redis-server --daemonize yes && dotnet NetAdmin.AdmServer.Host.dll -is | ||||
| COPY ./dist/backend/YourSolution.AdmServer.Host/bin/Release/net9.0/publish . | ||||
| ENTRYPOINT redis-server --daemonize yes && dotnet YourSolution.AdmServer.Host.dll -is | ||||
							
								
								
									
										32
									
								
								NetAdmin.sln
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								NetAdmin.sln
									
									
									
									
									
								
							| @@ -70,29 +70,29 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{8E4C93BA | ||||
|         stylecop.analyzers.ruleset = build/stylecop.analyzers.ruleset | ||||
|     EndProjectSection | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Infrastructure", "src\backend\NetAdmin.Infrastructure\NetAdmin.Infrastructure.csproj", "{1E62C322-EE42-4699-A6F1-791C53EFA62D}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Infrastructure", "src\backend\NetAdmin\NetAdmin.Infrastructure\NetAdmin.Infrastructure.csproj", "{1E62C322-EE42-4699-A6F1-791C53EFA62D}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.AdmServer.Application", "src\backend\NetAdmin.AdmServer.Application\NetAdmin.AdmServer.Application.csproj", "{E38B2EB4-D7A5-4777-9236-3B348919DF23}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YourSolution.AdmServer.Application", "src\backend\YourSolution.AdmServer.Application\YourSolution.AdmServer.Application.csproj", "{E38B2EB4-D7A5-4777-9236-3B348919DF23}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.AdmServer.Host", "src\backend\NetAdmin.AdmServer.Host\NetAdmin.AdmServer.Host.csproj", "{CE895E44-EEC3-4ECE-A56A-8A82E7D863E3}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YourSolution.AdmServer.Host", "src\backend\YourSolution.AdmServer.Host\YourSolution.AdmServer.Host.csproj", "{CE895E44-EEC3-4ECE-A56A-8A82E7D863E3}" | ||||
| EndProject | ||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03.hosted-servers", "03.hosted-servers", "{12AE5B4B-CB1A-498E-83B8-04E201E31D86}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Domain", "src\backend\NetAdmin.Domain\NetAdmin.Domain.csproj", "{58509C57-09FA-4E3C-BC07-78E786A2A326}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Domain", "src\backend\NetAdmin\NetAdmin.Domain\NetAdmin.Domain.csproj", "{58509C57-09FA-4E3C-BC07-78E786A2A326}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Application", "src\backend\NetAdmin.Application\NetAdmin.Application.csproj", "{70C54E1B-2083-4196-AB68-34CAF0075D82}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Application", "src\backend\NetAdmin\NetAdmin.Application\NetAdmin.Application.csproj", "{70C54E1B-2083-4196-AB68-34CAF0075D82}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Host", "src\backend\NetAdmin.Host\NetAdmin.Host.csproj", "{91839A15-D08F-4848-A301-F793412BC688}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Host", "src\backend\NetAdmin\NetAdmin.Host\NetAdmin.Host.csproj", "{91839A15-D08F-4848-A301-F793412BC688}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Cache", "src\backend\NetAdmin.Cache\NetAdmin.Cache.csproj", "{91452C22-4B57-4F16-9AF6-42C7BF830504}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Cache", "src\backend\NetAdmin\NetAdmin.Cache\NetAdmin.Cache.csproj", "{91452C22-4B57-4F16-9AF6-42C7BF830504}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.AdmServer.Cache", "src\backend\NetAdmin.AdmServer.Cache\NetAdmin.AdmServer.Cache.csproj", "{7CB632D3-3635-4F8D-AFE7-F496D37D422B}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YourSolution.AdmServer.Cache", "src\backend\YourSolution.AdmServer.Cache\YourSolution.AdmServer.Cache.csproj", "{7CB632D3-3635-4F8D-AFE7-F496D37D422B}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Host", "src\backend\NetAdmin.SysComponent.Host\NetAdmin.SysComponent.Host.csproj", "{C2CC1596-3BEE-43EA-A9BE-4EDE5716296C}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Host", "src\backend\NetAdmin\NetAdmin.SysComponent.Host\NetAdmin.SysComponent.Host.csproj", "{C2CC1596-3BEE-43EA-A9BE-4EDE5716296C}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Cache", "src\backend\NetAdmin.SysComponent.Cache\NetAdmin.SysComponent.Cache.csproj", "{19872A4C-3C9A-4C62-A33B-74F5B8D6F77C}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Cache", "src\backend\NetAdmin\NetAdmin.SysComponent.Cache\NetAdmin.SysComponent.Cache.csproj", "{19872A4C-3C9A-4C62-A33B-74F5B8D6F77C}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Application", "src\backend\NetAdmin.SysComponent.Application\NetAdmin.SysComponent.Application.csproj", "{34650E82-D257-46DA-BD6B-DE307113347B}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Application", "src\backend\NetAdmin\NetAdmin.SysComponent.Application\NetAdmin.SysComponent.Application.csproj", "{34650E82-D257-46DA-BD6B-DE307113347B}" | ||||
| EndProject | ||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02.components", "02.components", "{3F23258D-8299-4992-9F51-2EE9B52CF9D2}" | ||||
| EndProject | ||||
| @@ -104,20 +104,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "05.tools", "05.tools", "{79 | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "src\backend\UnitTests\UnitTests.csproj", "{C7F27698-DA05-4ACD-B0D7-4791B3972002}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Tests", "src\backend\NetAdmin.Tests\NetAdmin.Tests.csproj", "{00604162-C444-478B-B773-3AB23C856CA7}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.Tests", "src\backend\NetAdmin\NetAdmin.Tests\NetAdmin.Tests.csproj", "{00604162-C444-478B-B773-3AB23C856CA7}" | ||||
| EndProject | ||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{E80A1018-C354-4A26-9029-8847BB9DA864}" | ||||
|     ProjectSection(SolutionItems) = preProject | ||||
|         README.md = docker/README.md | ||||
|     EndProjectSection | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Domain", "src\backend\NetAdmin.SysComponent.Domain\NetAdmin.SysComponent.Domain.csproj", "{51D6E603-0749-4A11-A78C-9E5BB127E03A}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Domain", "src\backend\NetAdmin\NetAdmin.SysComponent.Domain\NetAdmin.SysComponent.Domain.csproj", "{51D6E603-0749-4A11-A78C-9E5BB127E03A}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.AdmServer.Domain", "src\backend\NetAdmin.AdmServer.Domain\NetAdmin.AdmServer.Domain.csproj", "{932520DF-D312-415A-A128-1117F8221D68}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YourSolution.AdmServer.Domain", "src\backend\YourSolution.AdmServer.Domain\YourSolution.AdmServer.Domain.csproj", "{932520DF-D312-415A-A128-1117F8221D68}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.AdmServer.Infrastructure", "src\backend\NetAdmin.AdmServer.Infrastructure\NetAdmin.AdmServer.Infrastructure.csproj", "{C3DE6F6A-D1FC-4B8E-9033-980FBEBBD2BA}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YourSolution.AdmServer.Infrastructure", "src\backend\YourSolution.AdmServer.Infrastructure\YourSolution.AdmServer.Infrastructure.csproj", "{C3DE6F6A-D1FC-4B8E-9033-980FBEBBD2BA}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Infrastructure", "src\backend\NetAdmin.SysComponent.Infrastructure\NetAdmin.SysComponent.Infrastructure.csproj", "{48EE6FC4-B64A-40D3-B889-36837E067880}" | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetAdmin.SysComponent.Infrastructure", "src\backend\NetAdmin\NetAdmin.SysComponent.Infrastructure\NetAdmin.SysComponent.Infrastructure.csproj", "{48EE6FC4-B64A-40D3-B889-36837E067880}" | ||||
| EndProject | ||||
| Global | ||||
|     GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
|   | ||||
| @@ -34,7 +34,7 @@ redis-cli    # 连接测试 | ||||
| # 下载 redis for linux/mac:https://redis.io/download | ||||
|  | ||||
| # 4. 运行后端 WebApi | ||||
| dotnet run --project ./src/backend/NetAdmin.AdmServer.Host/NetAdmin.AdmServer.Host.csproj --urls http://[::]:5010 -is | ||||
| dotnet run --project ./src/backend/YourSolution.AdmServer.Host/YourSolution.AdmServer.Host.csproj --urls http://[::]:5010 -is | ||||
| # -i 插入种子数据 | ||||
| # -s 同步数据库结构 | ||||
| # 浏览器访问 http://localhost:5010 ,将看到Swagger(Knife4jUI)界面 | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| { | ||||
|   "version": "2.0.0", | ||||
|   "devDependencies": { | ||||
|     "cz-git": "^1.10.1", | ||||
|     "cz-git": "^1.11.0", | ||||
|     "commitizen": "^4.3.1", | ||||
|     "prettier": "^3.3.3", | ||||
|     "standard-version": "^9.5.0" | ||||
|   | ||||
| @@ -1,7 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|     <Import Project="$(SolutionDir)/build/code.quality.props"/> | ||||
|     <ItemGroup> | ||||
|         <ProjectReference Include="../NetAdmin.AdmServer.Application/NetAdmin.AdmServer.Application.csproj"/> | ||||
|         <ProjectReference Include="../NetAdmin.SysComponent.Cache/NetAdmin.SysComponent.Cache.csproj"/> | ||||
|     </ItemGroup> | ||||
| </Project> | ||||
| @@ -1,19 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|     <Import Project="$(SolutionDir)/build/code.quality.props"/> | ||||
|     <ItemGroup> | ||||
|         <ProjectReference Include="../NetAdmin.SysComponent.Infrastructure/NetAdmin.SysComponent.Infrastructure.csproj"/> | ||||
|     </ItemGroup> | ||||
|     <ItemGroup> | ||||
|         <None Include="$(SolutionDir)/assets/res/NetAdmin.AdmServer.Statements.ln"> | ||||
|             <Link>Languages/NetAdmin.AdmServer.Statements.ln</Link> | ||||
|         </None> | ||||
|         <None Include="$(SolutionDir)/assets/res/NetAdmin.AdmServer.Fields.ln"> | ||||
|             <Link>Languages/NetAdmin.AdmServer.Fields.ln</Link> | ||||
|         </None> | ||||
|     </ItemGroup> | ||||
|     <ItemGroup> | ||||
|         <None Update="*.json"> | ||||
|             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||
|         </None> | ||||
|     </ItemGroup> | ||||
| </Project> | ||||
| @@ -1,31 +0,0 @@ | ||||
| namespace NetAdmin.Application.Extensions; | ||||
|  | ||||
| /// <summary> | ||||
| ///     工作单元管理器扩展方法 | ||||
| /// </summary> | ||||
| public static class UnitOfWorkManagerExtensions | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     事务操作 | ||||
|     /// </summary> | ||||
|     public static async Task AtomicOperateAsync(this UnitOfWorkManager me, Func<Task> handle) | ||||
|     { | ||||
|         var       logger     = LogHelper.Get<UnitOfWorkManager>(); | ||||
|         using var unitOfWork = me.Begin(); | ||||
|         var       hashCode   = unitOfWork.GetHashCode(); | ||||
|         try { | ||||
|             #if DEBUG | ||||
|             logger?.Debug($"{Ln.开始事务}: {hashCode}"); | ||||
|             #endif | ||||
|             await handle().ConfigureAwait(false); | ||||
|             unitOfWork.Commit(); | ||||
|             logger?.Info($"{Ln.事务已提交}: {hashCode}"); | ||||
|         } | ||||
|         catch (Exception ex) { | ||||
|             logger?.Warn(ex); | ||||
|             unitOfWork.Rollback(); | ||||
|             logger?.Warn($"{Ln.事务已回滚}: {hashCode}"); | ||||
|             throw; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,65 +0,0 @@ | ||||
| using NetAdmin.Domain; | ||||
| using NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| namespace NetAdmin.Application.Modules; | ||||
|  | ||||
| /// <summary> | ||||
| ///     增删改查模块接口 | ||||
| /// </summary> | ||||
| /// <typeparam name="TCreateReq">创建请求类型</typeparam> | ||||
| /// <typeparam name="TCreateRsp">创建响应类型</typeparam> | ||||
| /// <typeparam name="TQueryReq">查询请求类型</typeparam> | ||||
| /// <typeparam name="TQueryRsp">查询响应类型</typeparam> | ||||
| /// <typeparam name="TDelReq">删除请求类型</typeparam> | ||||
| public interface ICrudModule<in TCreateReq, TCreateRsp, TQueryReq, TQueryRsp, TDelReq> | ||||
|     where TCreateReq : DataAbstraction, new() | ||||
|     where TCreateRsp : DataAbstraction | ||||
|     where TQueryReq : DataAbstraction, new() | ||||
|     where TQueryRsp : DataAbstraction | ||||
|     where TDelReq : DataAbstraction, new() | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     批量删除实体 | ||||
|     /// </summary> | ||||
|     Task<int> BulkDeleteAsync(BulkReq<TDelReq> req); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     实体计数 | ||||
|     /// </summary> | ||||
|     Task<long> CountAsync(QueryReq<TQueryReq> req); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     创建实体 | ||||
|     /// </summary> | ||||
|     Task<TCreateRsp> CreateAsync(TCreateReq req); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     删除实体 | ||||
|     /// </summary> | ||||
|     Task<int> DeleteAsync(TDelReq req); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     判断实体是否存在 | ||||
|     /// </summary> | ||||
|     Task<bool> ExistAsync(QueryReq<TQueryReq> req); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     导出实体 | ||||
|     /// </summary> | ||||
|     Task<IActionResult> ExportAsync(QueryReq<TQueryReq> req); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     获取单个实体 | ||||
|     /// </summary> | ||||
|     Task<TQueryRsp> GetAsync(TQueryReq req); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     分页查询实体 | ||||
|     /// </summary> | ||||
|     Task<PagedQueryRsp<TQueryRsp>> PagedQueryAsync(PagedQueryReq<TQueryReq> req); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     查询实体 | ||||
|     /// </summary> | ||||
|     Task<IEnumerable<TQueryRsp>> QueryAsync(QueryReq<TQueryReq> req); | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| using NetAdmin.Domain.Dto.Dependency; | ||||
| using NetAdmin.Domain.Dto.Tpl.Example; | ||||
|  | ||||
| namespace NetAdmin.Application.Modules.Tpl; | ||||
|  | ||||
| /// <summary> | ||||
| ///     示例模块 | ||||
| /// </summary> | ||||
| public interface IExampleModule : ICrudModule<CreateExampleReq, QueryExampleRsp // 创建类型 | ||||
|   , QueryExampleReq, QueryExampleRsp                                            // 查询类型 | ||||
|   , DelReq                                                                      // 删除类型 | ||||
| >; | ||||
| @@ -1,6 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|     <Import Project="$(SolutionDir)/build/code.quality.props"/> | ||||
|     <ItemGroup> | ||||
|         <ProjectReference Include="../NetAdmin.Domain/NetAdmin.Domain.csproj"/> | ||||
|     </ItemGroup> | ||||
| </Project> | ||||
| @@ -1,18 +0,0 @@ | ||||
| using NetAdmin.Domain.Contexts; | ||||
| using NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| namespace NetAdmin.Application.Repositories; | ||||
|  | ||||
| /// <summary> | ||||
| ///     基础仓储 | ||||
| /// </summary> | ||||
| public sealed class BasicRepository<TEntity, TPrimary>(IFreeSql fSql, UnitOfWorkManager uowManger, ContextUserToken userToken) | ||||
|     : DefaultRepository<TEntity, TPrimary>(fSql, uowManger) | ||||
|     where TEntity : EntityBase<TPrimary> // | ||||
|     where TPrimary : IEquatable<TPrimary> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     当前上下文关联的用户令牌 | ||||
|     /// </summary> | ||||
|     public ContextUserToken UserToken => userToken; | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| using NetAdmin.Domain.Contexts; | ||||
|  | ||||
| namespace NetAdmin.Application.Services; | ||||
|  | ||||
| /// <summary> | ||||
| ///     服务接口 | ||||
| /// </summary> | ||||
| public interface IService | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     服务编号 | ||||
|     /// </summary> | ||||
|     Guid ServiceId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     上下文用户令牌 | ||||
|     /// </summary> | ||||
|     ContextUserToken UserToken { get; set; } | ||||
| } | ||||
| @@ -1,43 +0,0 @@ | ||||
| using NetAdmin.Application.Repositories; | ||||
| using NetAdmin.Domain.DbMaps.Dependency; | ||||
| using StackExchange.Redis; | ||||
|  | ||||
| namespace NetAdmin.Application.Services; | ||||
|  | ||||
| /// <summary> | ||||
| ///     Redis Service Base | ||||
| /// </summary> | ||||
| /// <remarks> | ||||
| ///     Initializes a new instance of the <see cref="RedisService{TEntity, TPrimary, TLogger}" /> class. | ||||
| ///     Redis Service Base | ||||
| /// </remarks> | ||||
| public abstract class RedisService<TEntity, TPrimary, TLogger>(BasicRepository<TEntity, TPrimary> rpo) | ||||
|     : RepositoryService<TEntity, TPrimary, TLogger>(rpo) | ||||
|     where TEntity : EntityBase<TPrimary> // | ||||
|     where TPrimary : IEquatable<TPrimary> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Redis Database | ||||
|     /// </summary> | ||||
|     protected IDatabase RedisDatabase { get; } // | ||||
|         = App.GetService<IConnectionMultiplexer>() | ||||
|              .GetDatabase(App.GetOptions<RedisOptions>().Instances.First(x => x.Name == Chars.FLG_REDIS_INSTANCE_DATA_CACHE).Database); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     获取锁 | ||||
|     /// </summary> | ||||
|     protected Task<RedisLocker> GetLockerAsync(string lockerName) | ||||
|     { | ||||
|         return RedisLocker.GetLockerAsync(RedisDatabase, lockerName, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY) | ||||
|                                         , Numbers.MAX_LIMIT_RETRY_CNT_REDIS_LOCK, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY)); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     获取锁(仅获取一次) | ||||
|     /// </summary> | ||||
|     protected Task<RedisLocker> GetLockerOnceAsync(string lockerName) | ||||
|     { | ||||
|         return RedisLocker.GetLockerAsync(RedisDatabase, lockerName, TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_EXPIRY), 1 | ||||
|                                         , TimeSpan.FromSeconds(Numbers.SECS_REDIS_LOCK_RETRY_DELAY)); | ||||
|     } | ||||
| } | ||||
| @@ -1,159 +0,0 @@ | ||||
| using CsvHelper; | ||||
| using Microsoft.Net.Http.Headers; | ||||
| using NetAdmin.Application.Repositories; | ||||
| using NetAdmin.Domain; | ||||
| using NetAdmin.Domain.DbMaps.Dependency; | ||||
| using NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
| using NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| namespace NetAdmin.Application.Services; | ||||
|  | ||||
| /// <summary> | ||||
| ///     仓储服务基类 | ||||
| /// </summary> | ||||
| /// <typeparam name="TEntity">实体类型</typeparam> | ||||
| /// <typeparam name="TPrimary">主键类型</typeparam> | ||||
| /// <typeparam name="TLogger">日志类型</typeparam> | ||||
| public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicRepository<TEntity, TPrimary> rpo) : ServiceBase<TLogger> | ||||
|     where TEntity : EntityBase<TPrimary> // | ||||
|     where TPrimary : IEquatable<TPrimary> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     默认仓储 | ||||
|     /// </summary> | ||||
|     protected BasicRepository<TEntity, TPrimary> Rpo => rpo; | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     启用级联保存 | ||||
|     /// </summary> | ||||
|     protected bool EnableCascadeSave { | ||||
|         get => Rpo.DbContextOptions.EnableCascadeSave; | ||||
|         set => Rpo.DbContextOptions.EnableCascadeSave = value; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     导出实体 | ||||
|     /// </summary> | ||||
|     protected static async Task<IActionResult> ExportAsync<TQuery, TExport>( // | ||||
|         Func<QueryReq<TQuery>, ISelectGrouping<TEntity, TEntity>>            selector, QueryReq<TQuery> query, string fileName | ||||
|       , Expression<Func<ISelectGroupingAggregate<TEntity, TEntity>, object>> listExp = null) | ||||
|         where TQuery : DataAbstraction, new() | ||||
|     { | ||||
|         var list = await selector(query).Take(Numbers.MAX_LIMIT_EXPORT).ToListAsync(listExp).ConfigureAwait(false); | ||||
|         return await GetExportFileStreamAsync<TExport>(fileName, list).ConfigureAwait(false); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     导出实体 | ||||
|     /// </summary> | ||||
|     protected static async Task<IActionResult> ExportAsync<TQuery, TExport>( // | ||||
|         Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> query, string fileName, Expression<Func<TEntity, object>> listExp = null) | ||||
|         where TQuery : DataAbstraction, new() | ||||
|     { | ||||
|         var select = selector(query) | ||||
|             #if DBTYPE_SQLSERVER | ||||
|                      .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) | ||||
|             #endif | ||||
|             .Take(Numbers.MAX_LIMIT_EXPORT); | ||||
|  | ||||
|         object list = listExp == null ? await select.ToListAsync().ConfigureAwait(false) : await select.ToListAsync(listExp).ConfigureAwait(false); | ||||
|  | ||||
|         return await GetExportFileStreamAsync<TExport>(fileName, list).ConfigureAwait(false); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     更新实体 | ||||
|     /// </summary> | ||||
|     /// <param name="newValue">新的值</param> | ||||
|     /// <param name="includeFields">包含的属性</param> | ||||
|     /// <param name="excludeFields">排除的属性</param> | ||||
|     /// <param name="whereExp">查询表达式</param> | ||||
|     /// <param name="whereSql">查询sql</param> | ||||
|     /// <param name="ignoreVersion">是否忽略版本锁</param> | ||||
|     /// <returns>更新行数</returns> | ||||
|     protected Task<int> UpdateAsync(                         // | ||||
|         TEntity                         newValue             // | ||||
|       , IEnumerable<string>             includeFields        // | ||||
|       , string[]                        excludeFields = null // | ||||
|       , Expression<Func<TEntity, bool>> whereExp      = null // | ||||
|       , string                          whereSql      = null // | ||||
|       , bool                            ignoreVersion = false) | ||||
|     { | ||||
|         // 默认匹配主键 | ||||
|         whereExp ??= a => a.Id.Equals(newValue.Id); | ||||
|         var update = BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion).Where(whereExp).Where(whereSql); | ||||
|         return update.ExecuteAffrowsAsync(); | ||||
|     } | ||||
|  | ||||
|     #if DBTYPE_SQLSERVER | ||||
|     /// <summary> | ||||
|     ///     更新实体 | ||||
|     /// </summary> | ||||
|     /// <param name="newValue">新的值</param> | ||||
|     /// <param name="includeFields">包含的属性</param> | ||||
|     /// <param name="excludeFields">排除的属性</param> | ||||
|     /// <param name="whereExp">查询表达式</param> | ||||
|     /// <param name="whereSql">查询sql</param> | ||||
|     /// <param name="ignoreVersion">是否忽略版本锁</param> | ||||
|     /// <returns>更新后的实体列表</returns> | ||||
|     protected Task<List<TEntity>> UpdateReturnListAsync(     // | ||||
|         TEntity                         newValue             // | ||||
|       , IEnumerable<string>             includeFields        // | ||||
|       , string[]                        excludeFields = null // | ||||
|       , Expression<Func<TEntity, bool>> whereExp      = null // | ||||
|       , string                          whereSql      = null // | ||||
|       , bool                            ignoreVersion = false) | ||||
|     { | ||||
|         // 默认匹配主键 | ||||
|         whereExp ??= a => a.Id.Equals(newValue.Id); | ||||
|         return BuildUpdate(newValue, includeFields, excludeFields, ignoreVersion).Where(whereExp).Where(whereSql).ExecuteUpdatedAsync(); | ||||
|     } | ||||
|     #endif | ||||
|  | ||||
|     private static async Task<IActionResult> GetExportFileStreamAsync<TExport>(string fileName, object list) | ||||
|     { | ||||
|         var listTyped = list.Adapt<List<TExport>>(); | ||||
|         var stream    = new MemoryStream(); | ||||
|         var writer    = new StreamWriter(stream); | ||||
|         var csv       = new CsvWriter(writer, CultureInfo.InvariantCulture); | ||||
|         csv.WriteHeader<TExport>(); | ||||
|         await csv.NextRecordAsync().ConfigureAwait(false); | ||||
|  | ||||
|         foreach (var item in listTyped) { | ||||
|             csv.WriteRecord(item); | ||||
|             await csv.NextRecordAsync().ConfigureAwait(false); | ||||
|         } | ||||
|  | ||||
|         await csv.FlushAsync().ConfigureAwait(false); | ||||
|         _ = stream.Seek(0, SeekOrigin.Begin); | ||||
|  | ||||
|         App.HttpContext.Response.Headers.ContentDisposition | ||||
|             = new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) { | ||||
|                                                                                             FileNameStar | ||||
|                                                                                                 = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv" | ||||
|                                                                                         }.ToString(); | ||||
|  | ||||
|         return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM); | ||||
|     } | ||||
|  | ||||
|     private IUpdate<TEntity> BuildUpdate(        // | ||||
|         TEntity             entity               // | ||||
|       , IEnumerable<string> includeFields        // | ||||
|       , string[]            excludeFields = null // | ||||
|       , bool                ignoreVersion = false) | ||||
|     { | ||||
|         var updateExp = includeFields == null | ||||
|             ? Rpo.UpdateDiy.SetSource(entity) | ||||
|             : Rpo.UpdateDiy.SetDto(includeFields!.ToDictionary( | ||||
|                                        x => x, x => typeof(TEntity).GetProperty(x, BindingFlags.Public | BindingFlags.Instance)!.GetValue(entity))); | ||||
|         if (excludeFields != null) { | ||||
|             updateExp = updateExp.IgnoreColumns(excludeFields); | ||||
|         } | ||||
|  | ||||
|         if (!ignoreVersion && entity is IFieldVersion ver) { | ||||
|             updateExp = updateExp.Where($"{nameof(IFieldVersion.Version)} = @version", new { version = ver.Version }); | ||||
|         } | ||||
|  | ||||
|         return updateExp; | ||||
|     } | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| using NetAdmin.Domain.Contexts; | ||||
|  | ||||
| namespace NetAdmin.Application.Services; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public abstract class ServiceBase<TLogger> : ServiceBase | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="ServiceBase{TLogger}" /> class. | ||||
|     /// </summary> | ||||
|     protected ServiceBase() // | ||||
|     { | ||||
|         Logger = App.GetService<ILogger<TLogger>>(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     日志记录器 | ||||
|     /// </summary> | ||||
|     protected ILogger<TLogger> Logger { get; } | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| ///     服务基类 | ||||
| /// </summary> | ||||
| public abstract class ServiceBase : IScoped, IService | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="ServiceBase" /> class. | ||||
|     /// </summary> | ||||
|     protected ServiceBase() | ||||
|     { | ||||
|         UserToken = App.GetService<ContextUserToken>(); | ||||
|         ServiceId = Guid.NewGuid(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Guid ServiceId { get; init; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public ContextUserToken UserToken { get; set; } | ||||
| } | ||||
| @@ -1,8 +0,0 @@ | ||||
| using NetAdmin.Application.Modules.Tpl; | ||||
|  | ||||
| namespace NetAdmin.Application.Services.Tpl.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     示例服务 | ||||
| /// </summary> | ||||
| public interface IExampleService : IService, IExampleModule; | ||||
| @@ -1,128 +0,0 @@ | ||||
| using NetAdmin.Application.Repositories; | ||||
| using NetAdmin.Application.Services.Tpl.Dependency; | ||||
| using NetAdmin.Domain.DbMaps.Tpl; | ||||
| using NetAdmin.Domain.Dto.Dependency; | ||||
| using NetAdmin.Domain.Dto.Tpl.Example; | ||||
|  | ||||
| namespace NetAdmin.Application.Services.Tpl; | ||||
|  | ||||
| /// <inheritdoc cref="IExampleService" /> | ||||
| public sealed class ExampleService(BasicRepository<Tpl_Example, long> rpo) // | ||||
|     : RepositoryService<Tpl_Example, long, IExampleService>(rpo), IExampleService | ||||
| { | ||||
|     /// <inheritdoc /> | ||||
|     public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         var ret = 0; | ||||
|  | ||||
|         // ReSharper disable once LoopCanBeConvertedToQuery | ||||
|         foreach (var item in req.Items) { | ||||
|             ret += await DeleteAsync(item).ConfigureAwait(false); | ||||
|         } | ||||
|  | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<long> CountAsync(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         return QueryInternal(req) | ||||
|                #if DBTYPE_SQLSERVER | ||||
|                .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) | ||||
|                #endif | ||||
|                .CountAsync(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public async Task<QueryExampleRsp> CreateAsync(CreateExampleReq req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         var ret = await Rpo.InsertAsync(req).ConfigureAwait(false); | ||||
|         return ret.Adapt<QueryExampleRsp>(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<int> DeleteAsync(DelReq req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         return Rpo.DeleteAsync(a => a.Id == req.Id); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<bool> ExistAsync(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         return QueryInternal(req) | ||||
|                #if DBTYPE_SQLSERVER | ||||
|                .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) | ||||
|                #endif | ||||
|                .AnyAsync(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<IActionResult> ExportAsync(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         return ExportAsync<QueryExampleReq, QueryExampleRsp>(QueryInternal, req, Ln.示例导出); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public async Task<QueryExampleRsp> GetAsync(QueryExampleReq req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         var ret = await QueryInternal(new QueryReq<QueryExampleReq> { Filter = req, Order = Orders.None }).ToOneAsync().ConfigureAwait(false); | ||||
|         return ret.Adapt<QueryExampleRsp>(); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public async Task<PagedQueryRsp<QueryExampleRsp>> PagedQueryAsync(PagedQueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         var list = await QueryInternal(req) | ||||
|                          .Page(req.Page, req.PageSize) | ||||
|                          #if DBTYPE_SQLSERVER | ||||
|                          .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) | ||||
|                          #endif | ||||
|                          .Count(out var total) | ||||
|                          .ToListAsync() | ||||
|                          .ConfigureAwait(false); | ||||
|  | ||||
|         return new PagedQueryRsp<QueryExampleRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryExampleRsp>>()); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public async Task<IEnumerable<QueryExampleRsp>> QueryAsync(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         req.ThrowIfInvalid(); | ||||
|         var ret = await QueryInternal(req) | ||||
|                         #if DBTYPE_SQLSERVER | ||||
|                         .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait) | ||||
|                         #endif | ||||
|                         .Take(req.Count) | ||||
|                         .ToListAsync() | ||||
|                         .ConfigureAwait(false); | ||||
|         return ret.Adapt<IEnumerable<QueryExampleRsp>>(); | ||||
|     } | ||||
|  | ||||
|     private ISelect<Tpl_Example> QueryInternal(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter); | ||||
|  | ||||
|         // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault | ||||
|         switch (req.Order) { | ||||
|             case Orders.None: | ||||
|                 return ret; | ||||
|             case Orders.Random: | ||||
|                 return ret.OrderByRandom(); | ||||
|         } | ||||
|  | ||||
|         ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending); | ||||
|         if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) { | ||||
|             ret = ret.OrderByDescending(a => a.Id); | ||||
|         } | ||||
|  | ||||
|         return ret; | ||||
|     } | ||||
| } | ||||
| @@ -1,16 +0,0 @@ | ||||
| using NetAdmin.Application.Services; | ||||
|  | ||||
| namespace NetAdmin.Cache; | ||||
|  | ||||
| /// <summary> | ||||
| ///     缓存基类 | ||||
| /// </summary> | ||||
| public abstract class CacheBase<TCacheContainer, TService>(TCacheContainer cache, TService service) : ICache<TCacheContainer, TService> | ||||
|     where TService : IService | ||||
| { | ||||
|     /// <inheritdoc /> | ||||
|     public TCacheContainer Cache => cache; | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public TService Service => service; | ||||
| } | ||||
| @@ -1,93 +0,0 @@ | ||||
| using System.Runtime.CompilerServices; | ||||
| using NetAdmin.Application.Services; | ||||
|  | ||||
| namespace NetAdmin.Cache; | ||||
|  | ||||
| /// <summary> | ||||
| ///     分布式缓存 | ||||
| /// </summary> | ||||
| public abstract class DistributedCache<TService>(IDistributedCache cache, TService service) : CacheBase<IDistributedCache, TService>(cache, service) | ||||
|     where TService : IService | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建缓存 | ||||
|     /// </summary> | ||||
|     /// <param name="key">缓存键</param> | ||||
|     /// <param name="createObj">创建对象</param> | ||||
|     /// <param name="absLifeTime">绝对过期时间</param> | ||||
|     /// <param name="slideLifeTime">滑动过期时间</param> | ||||
|     /// <typeparam name="T">缓存对象类型</typeparam> | ||||
|     /// <returns>缓存对象</returns> | ||||
|     protected Task CreateAsync<T>(string key, T createObj, TimeSpan? absLifeTime = null, TimeSpan? slideLifeTime = null) | ||||
|     { | ||||
|         var cacheWrite = createObj.ToJson(); | ||||
|  | ||||
|         var options = new DistributedCacheEntryOptions(); | ||||
|         if (absLifeTime != null) { | ||||
|             _ = options.SetAbsoluteExpiration(absLifeTime.Value); | ||||
|         } | ||||
|  | ||||
|         if (slideLifeTime != null) { | ||||
|             _ = options.SetSlidingExpiration(slideLifeTime.Value); | ||||
|         } | ||||
|  | ||||
|         return Cache.SetAsync(key, cacheWrite.Hex(), options); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     获取缓存 | ||||
|     /// </summary> | ||||
|     protected async Task<T> GetAsync<T>(string key) | ||||
|     { | ||||
|         var cacheRead = await Cache.GetStringAsync(key).ConfigureAwait(false); | ||||
|         try { | ||||
|             return cacheRead != null ? cacheRead.ToObject<T>() : default; | ||||
|         } | ||||
|         catch (JsonException) { | ||||
|             return default; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     获取缓存键 | ||||
|     /// </summary> | ||||
|     protected string GetCacheKey(string id = "0", [CallerMemberName] string memberName = null) | ||||
|     { | ||||
|         return $"{GetType().FullName}.{memberName}.{id}"; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     获取或创建缓存 | ||||
|     /// </summary> | ||||
|     /// <param name="key">缓存键</param> | ||||
|     /// <param name="createProc">创建函数</param> | ||||
|     /// <param name="absLifeTime">绝对过期时间</param> | ||||
|     /// <param name="slideLifeTime">滑动过期时间</param> | ||||
|     /// <typeparam name="T">缓存对象类型</typeparam> | ||||
|     /// <returns>缓存对象</returns> | ||||
|     protected async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> createProc, TimeSpan? absLifeTime = null, TimeSpan? slideLifeTime = null) | ||||
|     { | ||||
|         var cacheRead = await GetAsync<T>(key).ConfigureAwait(false); | ||||
|         if (cacheRead is not null && App.HttpContext?.Request.Headers.CacheControl.FirstOrDefault() != Chars.FLG_HTTP_HEADER_VALUE_NO_CACHE) { | ||||
|             return cacheRead; | ||||
|         } | ||||
|  | ||||
|         var obj = await createProc.Invoke().ConfigureAwait(false); | ||||
|  | ||||
|         var cacheWrite = obj?.ToJson(); | ||||
|         if (cacheWrite == null) { | ||||
|             return obj; | ||||
|         } | ||||
|  | ||||
|         await CreateAsync(key, obj, absLifeTime, slideLifeTime).ConfigureAwait(false); | ||||
|         return obj; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     删除缓存 | ||||
|     /// </summary> | ||||
|     protected Task RemoveAsync(string key) | ||||
|     { | ||||
|         return Cache.RemoveAsync(key); | ||||
|     } | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| using NetAdmin.Application.Services; | ||||
|  | ||||
| namespace NetAdmin.Cache; | ||||
|  | ||||
| /// <summary> | ||||
| ///     缓存接口 | ||||
| /// </summary> | ||||
| public interface ICache<out TCacheLoad, out TService> | ||||
|     where TService : IService | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     缓存对象 | ||||
|     /// </summary> | ||||
|     TCacheLoad Cache { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     关联的服务 | ||||
|     /// </summary> | ||||
|     public TService Service { get; } | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| using NetAdmin.Application.Services; | ||||
|  | ||||
| namespace NetAdmin.Cache; | ||||
|  | ||||
| /// <summary> | ||||
| ///     内存缓存 | ||||
| /// </summary> | ||||
| public abstract class MemoryCache<TService>(IMemoryCache cache, TService service) : CacheBase<IMemoryCache, TService>(cache, service) | ||||
|     where TService : IService; | ||||
| @@ -1,6 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|     <Import Project="$(SolutionDir)/build/code.quality.props"/> | ||||
|     <ItemGroup> | ||||
|         <ProjectReference Include="../NetAdmin.Application/NetAdmin.Application.csproj"/> | ||||
|     </ItemGroup> | ||||
| </Project> | ||||
| @@ -1,9 +0,0 @@ | ||||
| using NetAdmin.Application.Modules.Tpl; | ||||
| using NetAdmin.Application.Services.Tpl.Dependency; | ||||
|  | ||||
| namespace NetAdmin.Cache.Tpl.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     示例缓存 | ||||
| /// </summary> | ||||
| public interface IExampleCache : ICache<IDistributedCache, IExampleService>, IExampleModule; | ||||
| @@ -1,65 +0,0 @@ | ||||
| using NetAdmin.Application.Services.Tpl.Dependency; | ||||
| using NetAdmin.Cache.Tpl.Dependency; | ||||
| using NetAdmin.Domain.Dto.Dependency; | ||||
| using NetAdmin.Domain.Dto.Tpl.Example; | ||||
|  | ||||
| namespace NetAdmin.Cache.Tpl; | ||||
|  | ||||
| /// <inheritdoc cref="IExampleCache" /> | ||||
| public sealed class ExampleCache(IDistributedCache cache, IExampleService service) | ||||
|     : DistributedCache<IExampleService>(cache, service), IScoped, IExampleCache | ||||
| { | ||||
|     /// <inheritdoc /> | ||||
|     public Task<int> BulkDeleteAsync(BulkReq<DelReq> req) | ||||
|     { | ||||
|         return Service.BulkDeleteAsync(req); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<long> CountAsync(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         return Service.CountAsync(req); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<QueryExampleRsp> CreateAsync(CreateExampleReq req) | ||||
|     { | ||||
|         return Service.CreateAsync(req); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<int> DeleteAsync(DelReq req) | ||||
|     { | ||||
|         return Service.DeleteAsync(req); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<bool> ExistAsync(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         return Service.ExistAsync(req); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<IActionResult> ExportAsync(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         return Service.ExportAsync(req); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<QueryExampleRsp> GetAsync(QueryExampleReq req) | ||||
|     { | ||||
|         return Service.GetAsync(req); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<PagedQueryRsp<QueryExampleRsp>> PagedQueryAsync(PagedQueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         return Service.PagedQueryAsync(req); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public Task<IEnumerable<QueryExampleRsp>> QueryAsync(QueryReq<QueryExampleReq> req) | ||||
|     { | ||||
|         return Service.QueryAsync(req); | ||||
|     } | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes; | ||||
|  | ||||
| /// <summary> | ||||
| ///     危险字段标记 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Property)] | ||||
| public sealed class DangerFieldAttribute : Attribute; | ||||
| @@ -1,23 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     支付宝验证器(手机或邮箱) | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class AlipayAttribute : ValidationAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="AlipayAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public AlipayAttribute() | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.支付宝账号); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override bool IsValid(object value) | ||||
|     { | ||||
|         return new MobileAttribute().IsValid(value) || new EmailAddressAttribute().IsValid(value); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     证件号码验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class CertificateAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="CertificateAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public CertificateAttribute() // | ||||
|         : base(Chars.RGX_CERTIFICATE) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.无效证件号码); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     中文姓名验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class ChineseNameAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="ChineseNameAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public ChineseNameAttribute() // | ||||
|         : base(Chars.RGXL_CHINESE_NAME) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.中文姓名); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     时间表达式验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class CronAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="CronAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public CronAttribute() // | ||||
|         : base(Chars.RGXL_CRON) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.时间表达式); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     邮箱验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class EmailAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="EmailAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public EmailAttribute() // | ||||
|         : base(Chars.RGXL_EMAIL) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.电子邮箱); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     邀请码验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class InviteCodeAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="InviteCodeAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public InviteCodeAttribute() // | ||||
|         : base(Chars.RGX_INVITE_CODE) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.邀请码不正确); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     JSON文本验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class JsonStringAttribute : ValidationAttribute | ||||
| { | ||||
|     /// <inheritdoc /> | ||||
|     protected override ValidationResult IsValid(object value, ValidationContext validationContext) | ||||
|     { | ||||
|         return (value as string).IsJsonString() ? ValidationResult.Success : new ValidationResult(Ln.非JSON字符串, [validationContext.MemberName]); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     手机号码验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class MobileAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="MobileAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public MobileAttribute() // | ||||
|         : base(Chars.RGX_MOBILE) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.手机号码不正确); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     密码验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class PasswordAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="PasswordAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public PasswordAttribute() // | ||||
|         : base(Chars.RGX_PASSWORD) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln._8位以上数字字母组合); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     交易密码验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class PayPasswordAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="PayPasswordAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public PayPasswordAttribute() // | ||||
|         : base(Chars.RGX_PAY_PASSWORD) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln._6位数字); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     端口号验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class PortAttribute : RangeAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="PortAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public PortAttribute() // | ||||
|         : base(1, ushort.MaxValue) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.无效端口号); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,16 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     正则表达式验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| #pragma warning disable DesignedForInheritance | ||||
| public class RegexAttribute : RegularExpressionAttribute | ||||
| #pragma warning restore DesignedForInheritance | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="RegexAttribute" /> class. | ||||
|     /// </summary> | ||||
|     protected RegexAttribute(string pattern) // | ||||
|         : base(pattern) { } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     固定电话验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class TelephoneAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="TelephoneAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public TelephoneAttribute() // | ||||
|         : base(Chars.RGX_TELEPHONE) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.区号电话号码分机号); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     用户名验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class UserNameAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="UserNameAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public UserNameAttribute() // | ||||
|         : base(Chars.RGX_USERNAME) | ||||
|     { | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override bool IsValid(object value) | ||||
|     { | ||||
|         if (!base.IsValid(value)) { | ||||
|             ErrorMessageResourceName = nameof(Ln.用户名长度4位以上); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (!new MobileAttribute().IsValid(value)) { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         // 不能是手机号码 | ||||
|         ErrorMessageResourceName = nameof(Ln.用户名不能是手机号码); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes.DataValidation; | ||||
|  | ||||
| /// <summary> | ||||
| ///     验证码验证器 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter)] | ||||
| public sealed class VerifyCodeAttribute : RegexAttribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="VerifyCodeAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public VerifyCodeAttribute() // | ||||
|         : base(Chars.RGX_VERIFY_CODE) | ||||
|     { | ||||
|         ErrorMessageResourceName = nameof(Ln.验证码不正确); | ||||
|         ErrorMessageResourceType = typeof(Ln); | ||||
|     } | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes; | ||||
|  | ||||
| /// <summary> | ||||
| ///     标记一个枚举的状态指示 | ||||
| /// </summary> | ||||
| /// <inheritdoc /> | ||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Enum)] | ||||
| public sealed class IndicatorAttribute(string indicate) : Attribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     状态指示 | ||||
|     /// </summary> | ||||
|     public string Indicate { get; } = indicate; | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Attributes; | ||||
|  | ||||
| /// <summary> | ||||
| ///     标记一个字段启用服务器时间 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Property)] | ||||
| public sealed class ServerTimeAttribute : Attribute; | ||||
| @@ -1,9 +0,0 @@ | ||||
| // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global | ||||
|  | ||||
| namespace NetAdmin.Domain.Attributes; | ||||
|  | ||||
| /// <summary> | ||||
| ///     标记一个字段启用雪花编号生成 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Property)] | ||||
| public sealed class SnowflakeAttribute : Attribute; | ||||
| @@ -1,58 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Contexts; | ||||
|  | ||||
| /// <summary> | ||||
| ///     上下文用户凭据 | ||||
| /// </summary> | ||||
| public sealed record ContextUserToken : DataAbstraction | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     部门编号 | ||||
|     /// </summary> | ||||
|     /// ReSharper disable once MemberCanBePrivate.Global | ||||
|     public long DeptId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     用户编号 | ||||
|     /// </summary> | ||||
|     /// ReSharper disable once MemberCanBePrivate.Global | ||||
|     public long Id { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     做授权验证的Token,全局唯一,可以随时重置(强制下线) | ||||
|     /// </summary> | ||||
|     /// ReSharper disable once MemberCanBePrivate.Global | ||||
|     public Guid Token { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     用户名 | ||||
|     /// </summary> | ||||
|     /// ReSharper disable once MemberCanBePrivate.Global | ||||
|     public string UserName { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     从HttpContext 创建上下文用户 | ||||
|     /// </summary> | ||||
|     public static ContextUserToken Create() | ||||
|     { | ||||
|         var claim = App.User?.FindFirst(nameof(ContextUserToken)); | ||||
|         return claim?.Value.ToObject<ContextUserToken>(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     从 QueryUserRsp 创建上下文用户 | ||||
|     /// </summary> | ||||
|     public static ContextUserToken Create(long id, Guid token, string userName, long deptId) | ||||
|     { | ||||
|         return new ContextUserToken { Id = id, Token = token, UserName = userName, DeptId = deptId }; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     从 Json Web Token 创建上下文用户 | ||||
|     /// </summary> | ||||
|     public static ContextUserToken Create(string jwt) | ||||
|     { | ||||
|         var claim = JWTEncryption.ReadJwtToken(jwt.TrimPrefix($"{Chars.FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA} ")) | ||||
|                                  ?.Claims.FirstOrDefault(x => x.Type == nameof(ContextUserToken)); | ||||
|         return claim?.Value.ToObject<ContextUserToken>(); | ||||
|     } | ||||
| } | ||||
| @@ -1,48 +0,0 @@ | ||||
| namespace NetAdmin.Domain; | ||||
|  | ||||
| /// <summary> | ||||
| ///     数据基类 | ||||
| /// </summary> | ||||
| public abstract record DataAbstraction | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     如果数据校验失败,抛出异常 | ||||
|     /// </summary> | ||||
|     /// <exception cref="NetAdminValidateException">NetAdminValidateException</exception> | ||||
|     public void ThrowIfInvalid() | ||||
|     { | ||||
|         var validationResult = this.TryValidate(); | ||||
|         if (!validationResult.IsValid) { | ||||
|             throw new NetAdminValidateException(validationResult.ValidationResults.ToDictionary( // | ||||
|                                                     x => x.MemberNames.First()                   // | ||||
|                                                   , x => new[] { x.ErrorMessage })); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         return this.ToJson(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     截断所有字符串属性 以符合[MaxLength(x)]特性 | ||||
|     /// </summary> | ||||
|     public void TruncateStrings() | ||||
|     { | ||||
|         foreach (var property in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.PropertyType == typeof(string))) { | ||||
|             var maxLen = property.GetCustomAttribute<MaxLengthAttribute>(true)?.Length; | ||||
|             if (maxLen is null or 0) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             var value = property.GetValue(this); | ||||
|             if (value is not string s || s.Length < maxLen) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             s = s.Sub(0, maxLen.Value); | ||||
|             property.SetValue(this, s); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     数据库实体基类 | ||||
| /// </summary> | ||||
| public abstract record EntityBase<T> : DataAbstraction | ||||
|     where T : IEquatable<T> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     public virtual T Id { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     创建者客户端IP字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldCreatedClientIp | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建者客户端IP | ||||
|     /// </summary> | ||||
|     int? CreatedClientIp { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     创建者客户端用户代理字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldCreatedClientUserAgent | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建者客户端用户代理 | ||||
|     /// </summary> | ||||
|     string CreatedUserAgent { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     创建时间字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldCreatedTime | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建时间 | ||||
|     /// </summary> | ||||
|     DateTime CreatedTime { get; init; } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     创建用户字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldCreatedUser | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建者编号 | ||||
|     /// </summary> | ||||
|     long? CreatedUserId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     创建者用户名 | ||||
|     /// </summary> | ||||
|     string CreatedUserName { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     启用字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldEnabled | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     是否启用 | ||||
|     /// </summary> | ||||
|     bool Enabled { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     修改客户端IP字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldModifiedClientIp | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     客户端IP | ||||
|     /// </summary> | ||||
|     int ModifiedClientIp { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     修改客户端用户代理字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldModifiedClientUserAgent | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     客户端用户代理 | ||||
|     /// </summary> | ||||
|     string ModifiedUserAgent { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     修改时间字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldModifiedTime | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     修改时间 | ||||
|     /// </summary> | ||||
|     DateTime? ModifiedTime { get; init; } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     修改用户字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldModifiedUser | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     修改者编号 | ||||
|     /// </summary> | ||||
|     long? ModifiedUserId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     修改者用户名 | ||||
|     /// </summary> | ||||
|     string ModifiedUserName { get; init; } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     拥有者字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldOwner | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     拥有者部门编号 | ||||
|     /// </summary> | ||||
|     long? OwnerDeptId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     拥有者用户编号 | ||||
|     /// </summary> | ||||
|     long? OwnerId { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     排序字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldSort | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     排序值,越大越前 | ||||
|     /// </summary> | ||||
|     long Sort { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     备注字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldSummary | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     备注 | ||||
|     /// </summary> | ||||
|     string Summary { get; init; } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
|  | ||||
| /// <summary> | ||||
| ///     版本字段接口 | ||||
| /// </summary> | ||||
| public interface IFieldVersion | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     数据版本 | ||||
|     /// </summary> | ||||
|     long Version { get; init; } | ||||
| } | ||||
| @@ -1,44 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public abstract record ImmutableEntity : ImmutableEntity<long> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [Snowflake] | ||||
|     public override long Id { get; init; } | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| ///     不可变实体 | ||||
| /// </summary> | ||||
| /// <typeparam name="T">主键类型</typeparam> | ||||
| public abstract record ImmutableEntity<T> : LiteImmutableEntity<T>, IFieldCreatedUser | ||||
|     where T : IEquatable<T> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建者编号 | ||||
|     /// </summary> | ||||
|     [Column(CanUpdate = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public long? CreatedUserId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     创建者用户名 | ||||
|     /// </summary> | ||||
|     [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanUpdate = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual string CreatedUserName { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     public override T Id { get; init; } | ||||
| } | ||||
| @@ -1,37 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public abstract record LiteImmutableEntity : LiteImmutableEntity<long> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [Snowflake] | ||||
|     public override long Id { get; init; } | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| ///     轻型不可变实体 | ||||
| /// </summary> | ||||
| /// <typeparam name="T">主键类型</typeparam> | ||||
| public abstract record LiteImmutableEntity<T> : EntityBase<T>, IFieldCreatedTime | ||||
|     where T : IEquatable<T> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建时间 | ||||
|     /// </summary> | ||||
|     [Column(ServerTime = DateTimeKind.Local, CanUpdate = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual DateTime CreatedTime { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public override T Id { get; init; } | ||||
| } | ||||
| @@ -1,35 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public abstract record LiteMutableEntity : LiteMutableEntity<long> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [Snowflake] | ||||
|     public override long Id { get; init; } | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| ///     轻型可变实体 | ||||
| /// </summary> | ||||
| public abstract record LiteMutableEntity<T> : LiteImmutableEntity<T>, IFieldModifiedTime | ||||
|     where T : IEquatable<T> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     public override T Id { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     修改时间 | ||||
|     /// </summary> | ||||
|     [Column(ServerTime = DateTimeKind.Local, CanInsert = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual DateTime? ModifiedTime { get; init; } | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public abstract record LiteVersionEntity : LiteVersionEntity<long> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [Snowflake] | ||||
|     public override long Id { get; init; } | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| ///     乐观锁轻型可变实体 | ||||
| /// </summary> | ||||
| public abstract record LiteVersionEntity<T> : LiteMutableEntity<T>, IFieldVersion | ||||
|     where T : IEquatable<T> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [Snowflake] | ||||
|     public override T Id { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     数据版本 | ||||
|     /// </summary> | ||||
|     [Column(IsVersion = true, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual long Version { get; init; } | ||||
| } | ||||
| @@ -1,59 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public abstract record MutableEntity : MutableEntity<long> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [Snowflake] | ||||
|     public override long Id { get; init; } | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| ///     可变实体 | ||||
| /// </summary> | ||||
| public abstract record MutableEntity<T> : LiteMutableEntity<T>, IFieldCreatedUser, IFieldModifiedUser | ||||
|     where T : IEquatable<T> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建者编号 | ||||
|     /// </summary> | ||||
|     [Column(CanUpdate = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual long? CreatedUserId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     创建者用户名 | ||||
|     /// </summary> | ||||
|     [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanUpdate = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual string CreatedUserName { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     public override T Id { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     修改者编号 | ||||
|     /// </summary> | ||||
|     [Column(CanInsert = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public long? ModifiedUserId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     修改者用户名 | ||||
|     /// </summary> | ||||
|     [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanInsert = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public string ModifiedUserName { get; init; } | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public abstract record SimpleEntity : SimpleEntity<long> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [Snowflake] | ||||
|     public override long Id { get; init; } | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| ///     简单实体 | ||||
| /// </summary> | ||||
| public abstract record SimpleEntity<T> : EntityBase<T> | ||||
|     where T : IEquatable<T>; | ||||
| @@ -1,59 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Dependency; | ||||
|  | ||||
| /// <inheritdoc /> | ||||
| public abstract record VersionEntity : VersionEntity<long> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     [Snowflake] | ||||
|     public override long Id { get; init; } | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| ///     乐观锁可变实体 | ||||
| /// </summary> | ||||
| public abstract record VersionEntity<T> : LiteVersionEntity<T>, IFieldModifiedUser, IFieldCreatedUser | ||||
|     where T : IEquatable<T> | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     创建者编号 | ||||
|     /// </summary> | ||||
|     [Column(CanUpdate = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual long? CreatedUserId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     创建者用户名 | ||||
|     /// </summary> | ||||
|     [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanUpdate = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual string CreatedUserName { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     唯一编码 | ||||
|     /// </summary> | ||||
|     [Column(IsIdentity = false, IsPrimary = true, Position = 1)] | ||||
|     [CsvIgnore] | ||||
|     public override T Id { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     修改者编号 | ||||
|     /// </summary> | ||||
|     [Column(CanInsert = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual long? ModifiedUserId { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     修改者用户名 | ||||
|     /// </summary> | ||||
|     [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31, CanInsert = false, Position = -1)] | ||||
|     [CsvIgnore] | ||||
|     [JsonIgnore] | ||||
|     public virtual string ModifiedUserName { get; init; } | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| namespace NetAdmin.Domain.DbMaps.Tpl; | ||||
|  | ||||
| /// <summary> | ||||
| ///     示例表 | ||||
| /// </summary> | ||||
| [Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Tpl_Example))] | ||||
| public record Tpl_Example : VersionEntity; | ||||
| @@ -1,16 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     批量请求 | ||||
| /// </summary> | ||||
| public sealed record BulkReq<T> : DataAbstraction | ||||
|     where T : DataAbstraction, new() | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     请求对象 | ||||
|     /// </summary> | ||||
|     [MaxLength(Numbers.MAX_LIMIT_BULK_REQ)] | ||||
|     [MinLength(1)] | ||||
|     [Required(ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.请求对象不能为空))] | ||||
|     public IEnumerable<T> Items { get; init; } | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| /// <inheritdoc cref="DelReq{T}" /> | ||||
| public sealed record DelReq : DelReq<long>; | ||||
|  | ||||
| /// <summary> | ||||
| ///     请求:通过编号删除 | ||||
| /// </summary> | ||||
| public record DelReq<T> : EntityBase<T> | ||||
|     where T : IEquatable<T> | ||||
| { | ||||
|     /// <inheritdoc cref="EntityBase{T}.Id" /> | ||||
|     public override T Id { get; init; } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     信息:分页 | ||||
| /// </summary> | ||||
| public interface IPagedInfo | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     当前页码 | ||||
|     /// </summary> | ||||
|     int Page { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     页容量 | ||||
|     /// </summary> | ||||
|     int PageSize { get; init; } | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     空请求 | ||||
| /// </summary> | ||||
| public sealed record NopReq : DataAbstraction; | ||||
| @@ -1,16 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     请求:分页查询 | ||||
| /// </summary> | ||||
| public sealed record PagedQueryReq<T> : QueryReq<T>, IPagedInfo | ||||
|     where T : DataAbstraction, new() | ||||
| { | ||||
|     /// <inheritdoc cref="IPagedInfo.Page" /> | ||||
|     [Range(1, Numbers.MAX_LIMIT_QUERY_PAGE_NO)] | ||||
|     public int Page { get; init; } = 1; | ||||
|  | ||||
|     /// <inheritdoc cref="IPagedInfo.PageSize" /> | ||||
|     [Range(1, Numbers.MAX_LIMIT_QUERY_PAGE_SIZE)] | ||||
|     public int PageSize { get; init; } = Numbers.DEF_PAGE_SIZE_QUERY; | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     响应:分页查询 | ||||
| /// </summary> | ||||
| public sealed record PagedQueryRsp<T>(int Page, int PageSize, long Total, IEnumerable<T> Rows) : IPagedInfo | ||||
|     where T : DataAbstraction | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     数据行 | ||||
|     /// </summary> | ||||
|     public IEnumerable<T> Rows { get; } = Rows; | ||||
|  | ||||
|     /// <inheritdoc cref="IPagedInfo.Page" /> | ||||
|     public int Page { get; init; } = Page; | ||||
|  | ||||
|     /// <inheritdoc cref="IPagedInfo.PageSize" /> | ||||
|     public int PageSize { get; init; } = PageSize; | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     数据总条 | ||||
|     /// </summary> | ||||
|     public long Total { get; init; } = Total; | ||||
| } | ||||
| @@ -1,72 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Dto.Dependency; | ||||
|  | ||||
| /// <summary> | ||||
| ///     请求:查询 | ||||
| /// </summary> | ||||
| public record QueryReq<T> : DataAbstraction | ||||
|     where T : DataAbstraction, new() | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     取前n条 | ||||
|     /// </summary> | ||||
|     [Range(1, Numbers.MAX_LIMIT_QUERY)] | ||||
|     public int Count { get; init; } = Numbers.MAX_LIMIT_QUERY; | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     动态查询条件 | ||||
|     /// </summary> | ||||
|     public DynamicFilterInfo DynamicFilter { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     查询条件 | ||||
|     /// </summary> | ||||
|     public T Filter { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     查询关键字 | ||||
|     /// </summary> | ||||
|     public string Keywords { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     排序方式 | ||||
|     /// </summary> | ||||
|     public Orders? Order { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     排序字段 | ||||
|     /// </summary> | ||||
|     public string Prop { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     所需字段 | ||||
|     /// </summary> | ||||
|     public string[] RequiredFields { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     列表表达式 | ||||
|     /// </summary> | ||||
|     public Expression<Func<TEntity, TEntity>> GetToListExp<TEntity>() | ||||
|     { | ||||
|         if (RequiredFields.NullOrEmpty()) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         var expParameter = Expression.Parameter(typeof(TEntity), "a"); | ||||
|         var bindings     = new List<MemberBinding>(); | ||||
|  | ||||
|         // ReSharper disable once LoopCanBeConvertedToQuery | ||||
|         foreach (var field in RequiredFields) { | ||||
|             var prop = typeof(TEntity).GetProperty(field); | ||||
|             if (prop == null || prop.GetCustomAttribute<DangerFieldAttribute>() != null) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             var propExp = Expression.Property(expParameter, prop); | ||||
|             var binding = Expression.Bind(prop, propExp); | ||||
|             bindings.Add(binding); | ||||
|         } | ||||
|  | ||||
|         var expBody = Expression.MemberInit(Expression.New(typeof(TEntity)), bindings); | ||||
|         return Expression.Lambda<Func<TEntity, TEntity>>(expBody, expParameter); | ||||
|     } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| using NetAdmin.Domain.Enums; | ||||
|  | ||||
| namespace NetAdmin.Domain.Dto; | ||||
|  | ||||
| /// <summary> | ||||
| ///     动态过滤条件生成器 | ||||
| /// </summary> | ||||
| public sealed record DfBuilder | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     构建生成器 | ||||
|     /// </summary> | ||||
|     public static DynamicFilterInfo New(DynamicFilterLogics logic) | ||||
|     { | ||||
|         return new DynamicFilterInfo { Logic = logic, Filters = [] }; | ||||
|     } | ||||
| } | ||||
| @@ -1,125 +0,0 @@ | ||||
| using NetAdmin.Domain.Enums; | ||||
|  | ||||
| namespace NetAdmin.Domain.Dto; | ||||
|  | ||||
| /// <summary> | ||||
| ///     动态过滤条件 | ||||
| /// </summary> | ||||
| public sealed record DynamicFilterInfo : DataAbstraction | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     字段名 | ||||
|     /// </summary> | ||||
|     public string Field { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     子过滤条件 | ||||
|     /// </summary> | ||||
|     public List<DynamicFilterInfo> Filters { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     子过滤条件逻辑关系 | ||||
|     /// </summary> | ||||
|     public DynamicFilterLogics Logic { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     操作符 | ||||
|     /// </summary> | ||||
|     public DynamicFilterOperators Operator { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     值 | ||||
|     /// </summary> | ||||
|     public object Value { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     隐式转换为 FreeSql 的 DynamicFilterInfo 对象 | ||||
|     /// </summary> | ||||
|     public static implicit operator FreeSql.Internal.Model.DynamicFilterInfo(DynamicFilterInfo d) | ||||
|     { | ||||
|         var ret = d.Adapt<FreeSql.Internal.Model.DynamicFilterInfo>(); | ||||
|         ProcessDynamicFilter(ret); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     添加子过滤条件 | ||||
|     /// </summary> | ||||
|     public DynamicFilterInfo Add(DynamicFilterInfo df) | ||||
|     { | ||||
|         if (Filters == null) { | ||||
|             return this with { Filters = [df] }; | ||||
|         } | ||||
|  | ||||
|         Filters.Add(df); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     添加过滤条件 | ||||
|     /// </summary> | ||||
|     public DynamicFilterInfo Add(string field, DynamicFilterOperators opt, object val) | ||||
|     { | ||||
|         return Add(new DynamicFilterInfo { Field = field, Operator = opt, Value = val }); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     添加过滤条件 | ||||
|     /// </summary> | ||||
|     public DynamicFilterInfo AddIf(bool condition, string field, DynamicFilterOperators opt, object val) | ||||
|     { | ||||
|         return !condition ? this : Add(field, opt, val); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     添加过滤条件 | ||||
|     /// </summary> | ||||
|     public DynamicFilterInfo AddIf(bool condition, DynamicFilterInfo df) | ||||
|     { | ||||
|         return !condition ? this : Add(df); | ||||
|     } | ||||
|  | ||||
|     private static void ParseDateExp(FreeSql.Internal.Model.DynamicFilterInfo d) | ||||
|     { | ||||
|         var values = ((JsonElement)d.Value).Deserialize<string[]>(); | ||||
|         if (!DateTime.TryParse(values[0], CultureInfo.InvariantCulture, out _)) { | ||||
|             var result = values[0] | ||||
|                          .ExecuteCSharpCodeAsync<DateTime>([typeof(DateTime).Assembly], nameof(System)) | ||||
|                          .ConfigureAwait(false) | ||||
|                          .GetAwaiter() | ||||
|                          .GetResult(); | ||||
|             values[0] = $"{result:yyyy-MM-dd HH:mm:ss}"; | ||||
|         } | ||||
|  | ||||
|         if (!DateTime.TryParse(values[1], CultureInfo.InvariantCulture, out _)) { | ||||
|             var result = values[1] | ||||
|                          .ExecuteCSharpCodeAsync<DateTime>([typeof(DateTime).Assembly], nameof(System)) | ||||
|                          .ConfigureAwait(false) | ||||
|                          .GetAwaiter() | ||||
|                          .GetResult(); | ||||
|             values[1] = $"{result:yyyy-MM-dd HH:mm:ss}"; | ||||
|         } | ||||
|  | ||||
|         d.Value = values; | ||||
|     } | ||||
|  | ||||
|     private static void ProcessDynamicFilter(FreeSql.Internal.Model.DynamicFilterInfo d) | ||||
|     { | ||||
|         if (d?.Filters != null) { | ||||
|             foreach (var filterInfo in d.Filters) { | ||||
|                 ProcessDynamicFilter(filterInfo); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (new[] { nameof(IFieldCreatedClientIp.CreatedClientIp), nameof(IFieldModifiedClientIp.ModifiedClientIp) }.Contains( | ||||
|                 d?.Field, StringComparer.OrdinalIgnoreCase)) { | ||||
|             var val = d!.Value?.ToString(); | ||||
|             if (val?.IsIpV4() == true) { | ||||
|                 d.Value = val.IpV4ToInt32(); | ||||
|             } | ||||
|         } | ||||
|         else if (d?.Operator == DynamicFilterOperator.DateRange) { | ||||
|             ParseDateExp(d); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Dto; | ||||
|  | ||||
| /// <summary> | ||||
| ///     信息:RESTful 风格结果集 | ||||
| /// </summary> | ||||
| public record RestfulInfo<T> : DataAbstraction | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     代码 | ||||
|     /// </summary> | ||||
|     /// <example>succeed</example> | ||||
|     [JsonIgnore(Condition = JsonIgnoreCondition.Never)] | ||||
|     public ErrorCodes Code { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     数据 | ||||
|     /// </summary> | ||||
|     public T Data { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     字符串:"消息内容",或数组:[{"参数名1":"消息内容1"},{"参数名2":"消息内容2"}] | ||||
|     /// </summary> | ||||
|     /// <example>请求成功</example> | ||||
|     public object Msg { get; init; } | ||||
| } | ||||
| @@ -1,8 +0,0 @@ | ||||
| using NetAdmin.Domain.DbMaps.Tpl; | ||||
|  | ||||
| namespace NetAdmin.Domain.Dto.Tpl.Example; | ||||
|  | ||||
| /// <summary> | ||||
| ///     请求:创建示例 | ||||
| /// </summary> | ||||
| public record CreateExampleReq : Tpl_Example; | ||||
| @@ -1,13 +0,0 @@ | ||||
| using NetAdmin.Domain.DbMaps.Tpl; | ||||
|  | ||||
| namespace NetAdmin.Domain.Dto.Tpl.Example; | ||||
|  | ||||
| /// <summary> | ||||
| ///     请求:查询示例 | ||||
| /// </summary> | ||||
| public sealed record QueryExampleReq : Tpl_Example | ||||
| { | ||||
|     /// <inheritdoc cref="EntityBase{T}.Id" /> | ||||
|     [JsonIgnore(Condition = JsonIgnoreCondition.Never)] | ||||
|     public override long Id { get; init; } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| using NetAdmin.Domain.DbMaps.Tpl; | ||||
|  | ||||
| namespace NetAdmin.Domain.Dto.Tpl.Example; | ||||
|  | ||||
| /// <summary> | ||||
| ///     响应:查询示例 | ||||
| /// </summary> | ||||
| public sealed record QueryExampleRsp : Tpl_Example | ||||
| { | ||||
|     /// <inheritdoc cref="EntityBase{T}.Id" /> | ||||
|     [JsonIgnore(Condition = JsonIgnoreCondition.Never)] | ||||
|     public override long Id { get; init; } | ||||
|  | ||||
|     /// <inheritdoc cref="IFieldVersion.Version" /> | ||||
|     [JsonIgnore(Condition = JsonIgnoreCondition.Never)] | ||||
|     public override long Version { get; init; } | ||||
| } | ||||
| @@ -1,22 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Enums; | ||||
|  | ||||
| /// <summary> | ||||
| ///     动态查询条件逻辑运算符 | ||||
| /// </summary> | ||||
| [Export] | ||||
| public enum DynamicFilterLogics | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     并且 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.并且))] | ||||
|     And = 0 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     或者 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.或者))] | ||||
|     Or = 1 | ||||
| } | ||||
| @@ -1,158 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Enums; | ||||
|  | ||||
| /// <summary> | ||||
| ///     动态查询条件操作符 | ||||
| /// </summary> | ||||
| [Export] | ||||
| public enum DynamicFilterOperators | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     包含 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.包含))] | ||||
|     Contains = 0 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     以什么开始 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.以什么开始))] | ||||
|     StartsWith = 1 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     以什么结束 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.以什么结束))] | ||||
|     EndsWith = 2 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     不包含 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.不包含))] | ||||
|     NotContains = 3 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     不以什么开始 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.不以什么开始))] | ||||
|     NotStartsWith = 4 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     不以什么结束 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.不以什么结束))] | ||||
|     NotEndsWith = 5 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     等于 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.等于))] | ||||
|     Equal = 6 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     等于 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.等于))] | ||||
|     Equals = 7 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     等于 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.等于))] | ||||
|     Eq = 8 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     不等于 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.不等于))] | ||||
|     NotEqual = 9 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     大于 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.大于))] | ||||
|     GreaterThan = 10 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     大于等于 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.大于等于))] | ||||
|     GreaterThanOrEqual = 11 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     小于 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.小于))] | ||||
|     LessThan = 12 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     小于等于 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.小于等于))] | ||||
|     LessThanOrEqual = 13 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     范围 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.范围))] | ||||
|     Range = 14 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     日期范围 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.日期范围))] | ||||
|     DateRange = 15 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     为其中之一 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.为其中之一))] | ||||
|     Any = 16 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     不为其中之一 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.不为其中之一))] | ||||
|     NotAny = 17 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     自定义 | ||||
|     /// </summary> | ||||
|     [ResourceDescription<Ln>(nameof(Ln.自定义))] | ||||
|     Custom = 18 | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Enums; | ||||
|  | ||||
| /// <summary> | ||||
| ///     HTTP 请求方法 | ||||
| /// </summary> | ||||
| [Export] | ||||
| public enum HttpMethods | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Connect | ||||
|     /// </summary> | ||||
|     Connect = 1 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Delete | ||||
|     /// </summary> | ||||
|     Delete = 2 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Get | ||||
|     /// </summary> | ||||
|     Get = 3 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Head | ||||
|     /// </summary> | ||||
|     Head = 4 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Options | ||||
|     /// </summary> | ||||
|     Options = 5 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Patch | ||||
|     /// </summary> | ||||
|     Patch = 6 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Post | ||||
|     /// </summary> | ||||
|     Post = 7 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Put | ||||
|     /// </summary> | ||||
|     Put = 8 | ||||
|  | ||||
|    , | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Trace | ||||
|     /// </summary> | ||||
|     Trace = 9 | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Events; | ||||
|  | ||||
| /// <summary> | ||||
| ///     泛型事件源接口 | ||||
| /// </summary> | ||||
| public interface IEventSourceGeneric<out T> : IEventSource | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     事件承载(携带)数据 | ||||
|     /// </summary> | ||||
|     T Data { get; } | ||||
| } | ||||
| @@ -1,38 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Events; | ||||
|  | ||||
| /// <summary> | ||||
| ///     种子数据插入完毕事件 | ||||
| /// </summary> | ||||
| public sealed record SeedDataInsertedEvent : DataAbstraction, IEventSource | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="SeedDataInsertedEvent" /> class. | ||||
|     /// </summary> | ||||
|     public SeedDataInsertedEvent(int insertedCount, bool isConsumOnce = false) | ||||
|     { | ||||
|         IsConsumOnce  = isConsumOnce; | ||||
|         InsertedCount = insertedCount; | ||||
|         CreatedTime   = DateTime.Now; | ||||
|         EventId       = nameof(SeedDataInsertedEvent); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public DateTime CreatedTime { get; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public string EventId { get; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public bool IsConsumOnce { get; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public CancellationToken CancellationToken { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     插入数量 | ||||
|     /// </summary> | ||||
|     public int InsertedCount { get; set; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public object Payload { get; init; } | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Events; | ||||
|  | ||||
| /// <summary> | ||||
| ///     Sql命令执行后事件 | ||||
| /// </summary> | ||||
| public sealed record SqlCommandAfterEvent : SqlCommandBeforeEvent | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="SqlCommandAfterEvent" /> class. | ||||
|     /// </summary> | ||||
|     public SqlCommandAfterEvent(CommandAfterEventArgs e) // | ||||
|         : base(e) | ||||
|     { | ||||
|         ElapsedMilliseconds = (long)((double)e.ElapsedTicks / Stopwatch.Frequency * 1_000); | ||||
|         EventId             = nameof(SqlCommandAfterEvent); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     耗时(单位:毫秒) | ||||
|     /// </summary> | ||||
|     /// de | ||||
|     private long ElapsedMilliseconds { get; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: {2} ms {1}", Id, Sql, ElapsedMilliseconds); | ||||
|     } | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Events; | ||||
|  | ||||
| /// <summary> | ||||
| ///     Sql命令执行前事件 | ||||
| /// </summary> | ||||
| public record SqlCommandBeforeEvent : SqlCommandEvent | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="SqlCommandBeforeEvent" /> class. | ||||
|     /// </summary> | ||||
|     public SqlCommandBeforeEvent(CommandBeforeEventArgs e) | ||||
|     { | ||||
|         Identifier  = e.Identifier; | ||||
|         Sql         = e.Command.ParameterFormat().RemoveWrapped(); | ||||
|         EventId     = nameof(SqlCommandBeforeEvent); | ||||
|         CreatedTime = DateTime.Now; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: Executing...", Id); | ||||
|     } | ||||
| } | ||||
| @@ -1,45 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Events; | ||||
|  | ||||
| /// <summary> | ||||
| ///     Sql命令事件 | ||||
| /// </summary> | ||||
| public abstract record SqlCommandEvent : DataAbstraction, IEventSource | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="SqlCommandEvent" /> class. | ||||
|     /// </summary> | ||||
|     protected SqlCommandEvent(bool isConsumOnce = false) | ||||
|     { | ||||
|         IsConsumOnce = isConsumOnce; | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public bool IsConsumOnce { get; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public CancellationToken CancellationToken { get; init; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public DateTime CreatedTime { get; protected init; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public string EventId { get; protected init; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public object Payload { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     标识符缩写 | ||||
|     /// </summary> | ||||
|     protected string Id => Identifier.ToString()[..8].ToUpperInvariant(); | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     标识符,可将 CommandBefore 与 CommandAfter 进行匹配 | ||||
|     /// </summary> | ||||
|     protected Guid Identifier { get; init; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     关联的Sql语句 | ||||
|     /// </summary> | ||||
|     protected string Sql { get; init; } | ||||
| } | ||||
| @@ -1,22 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Events; | ||||
|  | ||||
| /// <summary> | ||||
| ///     同步数据库结构之后事件 | ||||
| /// </summary> | ||||
| public sealed record SyncStructureAfterEvent : SyncStructureBeforeEvent | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="SyncStructureAfterEvent" /> class. | ||||
|     /// </summary> | ||||
|     public SyncStructureAfterEvent(SyncStructureBeforeEventArgs e) // | ||||
|         : base(e) | ||||
|     { | ||||
|         EventId = nameof(SyncStructureAfterEvent); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         return string.Format(CultureInfo.InvariantCulture, "{0}: {1}: {2}", Id, Ln.数据库结构同步完成, string.Join(',', EntityTypes.Select(x => x.Name))); | ||||
|     } | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| namespace NetAdmin.Domain.Events; | ||||
|  | ||||
| /// <summary> | ||||
| ///     同步数据库结构之前事件 | ||||
| /// </summary> | ||||
| public record SyncStructureBeforeEvent : SqlCommandEvent | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="SyncStructureBeforeEvent" /> class. | ||||
|     /// </summary> | ||||
|     public SyncStructureBeforeEvent(SyncStructureBeforeEventArgs e) | ||||
|     { | ||||
|         Identifier  = e.Identifier; | ||||
|         EventId     = nameof(SyncStructureBeforeEvent); | ||||
|         CreatedTime = DateTime.Now; | ||||
|         EntityTypes = e.EntityTypes; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     实体类型 | ||||
|     /// </summary> | ||||
|     protected Type[] EntityTypes { get; } | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         return string.Format(CultureInfo.InvariantCulture, "{0}: {1}", Id, Ln.数据库同步开始); | ||||
|     } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|     <Import Project="$(SolutionDir)/build/code.quality.props"/> | ||||
|     <ItemGroup> | ||||
|         <ProjectReference Include="../NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj"/> | ||||
|     </ItemGroup> | ||||
|     <ItemGroup> | ||||
|         <PackageReference Include="CronExpressionDescriptor" Version="2.36.0"/> | ||||
|         <PackageReference Include="Cronos" Version="0.8.4"/> | ||||
|         <PackageReference Include="CsvHelper.NS" Version="33.0.2-ns2"/> | ||||
|         <PackageReference Include="Yitter.IdGenerator" Version="1.0.14"/> | ||||
|     </ItemGroup> | ||||
| </Project> | ||||
| @@ -1,5 +0,0 @@ | ||||
| global using NetAdmin.Domain.Attributes; | ||||
| global using NetAdmin.Domain.DbMaps.Dependency; | ||||
| global using NetAdmin.Domain.DbMaps.Dependency.Fields; | ||||
| global using CsvIgnore = CsvHelper.Configuration.Attributes.IgnoreAttribute; | ||||
| global using DynamicFilterOperators = NetAdmin.Domain.Enums.DynamicFilterOperators; | ||||
| @@ -1,7 +0,0 @@ | ||||
| namespace NetAdmin.Host.Attributes; | ||||
|  | ||||
| /// <summary> | ||||
| ///     标记一个Action,其响应的json结果会被删除值为null的节点 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Method)] | ||||
| public sealed class RemoveNullNodeAttribute : Attribute; | ||||
| @@ -1,41 +0,0 @@ | ||||
| namespace NetAdmin.Host.Attributes; | ||||
|  | ||||
| /// <summary> | ||||
| ///     标记一个Action启用事务 | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Method)] | ||||
| public sealed class TransactionAttribute : Attribute | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="TransactionAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public TransactionAttribute() { } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="TransactionAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public TransactionAttribute(Propagation propagation) // | ||||
|         : this(null, propagation) { } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     Initializes a new instance of the <see cref="TransactionAttribute" /> class. | ||||
|     /// </summary> | ||||
|     public TransactionAttribute(IsolationLevel isolationLevel, Propagation propagation) // | ||||
|         : this(new IsolationLevel?(isolationLevel), propagation) { } | ||||
|  | ||||
|     private TransactionAttribute(IsolationLevel? isolationLevel, Propagation propagation) | ||||
|     { | ||||
|         IsolationLevel = isolationLevel; | ||||
|         Propagation    = propagation; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     事务隔离级别 | ||||
|     /// </summary> | ||||
|     public IsolationLevel? IsolationLevel { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     ///     事务传播方式 | ||||
|     /// </summary> | ||||
|     public Propagation Propagation { get; } = Propagation.Required; | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| namespace NetAdmin.Host.BackgroundRunning; | ||||
|  | ||||
| /// <summary> | ||||
| ///     轮询工作接口 | ||||
| /// </summary> | ||||
| public interface IPollingWork | ||||
| { | ||||
|     /// <summary> | ||||
|     ///     启动工作 | ||||
|     /// </summary> | ||||
|     ValueTask StartAsync(CancellationToken cancelToken); | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 GitHub
						GitHub