Ruth.Net8.Core.Services 2026.11.10

dotnet add package Ruth.Net8.Core.Services --version 2026.11.10
                    
NuGet\Install-Package Ruth.Net8.Core.Services -Version 2026.11.10
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ruth.Net8.Core.Services" Version="2026.11.10" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ruth.Net8.Core.Services" Version="2026.11.10" />
                    
Directory.Packages.props
<PackageReference Include="Ruth.Net8.Core.Services" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ruth.Net8.Core.Services --version 2026.11.10
                    
#r "nuget: Ruth.Net8.Core.Services, 2026.11.10"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ruth.Net8.Core.Services@2026.11.10
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ruth.Net8.Core.Services&version=2026.11.10
                    
Install as a Cake Addin
#tool nuget:?package=Ruth.Net8.Core.Services&version=2026.11.10
                    
Install as a Cake Tool

Ruth.Net8.Core.Services 说明

核心业务服务层(用户模块),提供用户/角色/菜单/系统/组织机构/租户等业务服务的实现, 以及数据库自动迁移。Controller(Ruth.Net8.Core.Controllers)调用本层接口,本层依赖 Ruth.Net8.Core.Data(实体/EF 上下文)与 Ruth.Net8.Core.Models(DTO)。

目录结构

Ruth.Net8.Core.Services/
├── ServiceCollectionExtensions.cs     // 服务注册入口(AddServices),反射扫描 Service 目录
├── ModuleInitializer.cs               // 模块初始化器约定(反射自动注册)
├── RunMigrations.cs                   // 启动任务:自动执行 EF 迁移(MigrateAsync)
└── Service/
    ├── 用户Service.cs                 // 用户 CRUD / 登录 / 角色授权 / 密码等
    ├── 租户Service.cs                 // 多租户:租户 CRUD / 用户-租户授权 / 切租户校验
    ├── 角色Service.cs                 // 角色 CRUD / 角色菜单授权
    ├── 菜单Service.cs                 // 菜单 CRUD / 树
    ├── 系统Service.cs                 // 系统 CRUD / 用户-系统菜单
    ├── 组织机构Service.cs             // 部门树
    ├── 日志Service.cs                 // 操作日志
    ├── CustomTreeService.cs           // 通用自定义树
    ├── WeChatWorkService.cs           // 企业微信
    ├── OpcServerConfigService.cs      // OPC 服务器配置
    ├── OpcGroupConfigService.cs       // OPC 分组配置
    ├── OpcDeviceConfigService.cs      // OPC 设备配置
    ├── OpcTagConfigService.cs         // OPC 标签配置
    ├── OpcTagGroupTemplateService.cs  // OPC 标签组模板
    └── ...

服务注册机制

  • ServiceCollectionExtensions.AddServices(services, configuration):反射扫描本程序集 命名空间 Ruth.Net8.Core.Services.Service 下、实现 *Service 结尾接口的类, AddScoped 注册(接口 → 实现)。
  • ModuleInitializer:模块初始化器约定(moduleinitializer 约定注入)。
  • 新增 Service 的写法:新建 类名Service.cs + I类名Service.cs(Ruth.Net8.Core.Interfaces), 无需手工改注册代码,重启即注册。

Service 通用模式

public class XxxService : JYC.Net6.CustomCLS.EFCORE.BaseDbService<XxxEntity, XxxDto, RuthCoreContext>, IXxxService
{
    public XxxService(IDbContextFactory<RuthCoreContext> dbContextFactory, IMapper mapper) : base(dbContextFactory, mapper) { }
}
  • 通用 CRUD(增删改查/分页)由 BaseDbService 提供;
  • 业务方法内部 using var db = _dbContextFactory.CreateDbContext() 创建短生命周期上下文;
  • DTO 映射:实体标注 [CustomEFCoreAutoMapper] 反射自动映射。

多租户改造(用户可访问多个租户)

改造日期:2026-11-02 | 编译:0 错误(64 个 Lib 存量 nullable 警告)

一、需求与方案

需求:user 模块支持多租户,实现一个用户可以访问多个租户。

已确认方案: | 决策点 | 结论 | | --- | --- | | 租户粒度 | 项目/矿点(同一系统下按项目/矿点分租户) | | 数据隔离 | 共享表 + TenantId 行过滤(EF 全局查询过滤器,一个库一张表) | | 租户切换 | 登录返回租户列表 + JWT 携带/切换租户 |

二、本层改动(Ruth.Net8.Core.Services)

文件 说明
新增 Service\租户Service.cs 租户 CRUD + 用户-租户授权 + 切租户校验
修改 Service\用户Service.cs LoginAsync 成功时填充 data.Tenants(可访问租户列表)

三、配套改动(跨项目)

项目 文件 说明
Ruth.Net8.Core.Data Entity\租户Entity.cs(新) 租户实体:TenantCode / TenantName / Description / Status
Ruth.Net8.Core.Data Config\租户Config.cs(新) 表名 租户,schema RuthCore
Ruth.Net8.Core.Data TenantContext.cs(新) AsyncLocal 当前租户上下文(随异步流传播)
Ruth.Net8.Core.Data RuthCoreContext.cs(改) CurrentTenantId 属性 + ApplyTenantQueryFilters 全局查询过滤器
Ruth.Net8.Core.Models 租户Dto.cs / UserTenantDto.cs / SwitchTenantDto.cs / SwitchTenantResultDto.cs(新) 租户相关 DTO
Ruth.Net8.Core.Models 用户Dto.cs(改) 加 List<租户Dto>? Tenants
Ruth.Net8.Core.Models Define.cs(改) 加 USERTENANT = "用户租户"
Ruth.Net8.Core.Interfaces I租户Service.cs(新) 租户服务接口
Ruth.Net8.Core.Controllers 租户sController.cs(新) 租户管理接口
Ruth.Net8.Core.WebAPIService Classes\租户s.cs(新) 管理端 HTTP 调用封装
Ruth.Net8.Core.WebAPI Controllers\TenantController.cs(新) SwitchTenantAsync 切租户签发 JWT
Ruth.Net8.Core.WebAPI Program.cs(改) AddJwtBearer.OnTokenValidated 写入 TenantContext
SqlServerMigrations / SqliteMigrations 20261102083228_coresql20261102_tenant / 20261102083250_sqlite20261102_tenant(新) 建 租户 表

四、核心设计

4.1 "用户-租户"关系:复用泛化关系表

与现有 用户角色(USERROLE)/ 角色菜单(ROLEMENU)/ 部门用户(DepartMentUSER)同机制:

关系表一条记录:FirstId = 用户ID,SecondId = 租户ID,Key = "用户租户"(Define.USERTENANT)
一个用户授权 N 条 → 可访问 N 个租户

4.2 数据隔离链路

登录 LoginAsync ──► 返回用户 + Tenants(可访问租户列表)
前端选租户 ──► SwitchTenantAsync ──► 校验授权 ──► 签发 JWT(TenantId Claim,30分钟)
后续请求 Authorization: Bearer <token>
  └─► JWT OnTokenValidated ──► TenantContext.CurrentTenantId = TenantId
       └─► 工厂创建 DbContext ──► RuthCoreContext.CurrentTenantId
            └─► EF 全局查询过滤器 ──► 只查当前租户数据

4.3 全局查询过滤器(RuthCoreContext.ApplyTenantQueryFilters)

  • 凡带 TenantId 属性的业务实体自动应用: CurrentTenantId == null || e.TenantId == CurrentTenantId
  • 当前租户为空 → 不过滤(返回全部,兼容现有场景);
  • 有当前租户 → 只返回该租户数据;
  • 用户 / 角色 / 菜单 / 关系 / 租户等共享基础表不带 TenantId,不受过滤。

4.4 租户Service 接口方法

方法 说明
SetUserTenantsAsync(List<UserTenantDto>) 保存用户-租户授权(先删后插,同 SetUserRolesAsync)
GetTenantsByUserIdAsync(用户Dto) 用户可访问租户(超管返回全部启用租户)
GetUsersByTenantIdAsync(租户Dto) 租户下用户列表(授权界面反查)
CheckUserTenantAsync(SwitchTenantDto) 切换前校验(用户存在 + 租户启用 + 已授权;超管免授权校验)

4.5 超管规则

IsSuperMan == true:可访问全部启用租户,切租户免授权校验。

五、接口一览

接口 方法 说明
/api/租户s/... 通用 CRUD 租户增删改查(BaseController)
/api/租户s/SetUserTenantsAsync POST 保存用户-租户授权
/api/租户s/GetTenantsByUserId POST 用户可访问租户列表
/api/租户s/GetUsersByTenantId POST 租户下用户列表
/api/租户s/CheckUserTenant POST 切换前校验
/api/TenantController/SwitchTenantAsync POST 切租户并签发 JWT(Body: {"UserId":"...","TenantId":"..."})

六、业务表启用租户隔离(后续步骤,本轮未执行)

本轮只搭好多租户基础设施,未给任何现有业务表加 TenantId(现有表保持全局,不受影响)。 需要隔离某张业务表时:

  1. 业务实体加属性:public string? TenantId { get; set; };
  2. 生成迁移(dotnet ef migrations add 或手写),迁移里 UPDATE 业务表 SET TenantId = '<默认租户ID>' 回填存量数据;
  3. 重启 WebAPI → 自动迁移 → 过滤器自动生效,业务 Service 查询代码一行不用改。

七、数据库迁移说明

  • 迁移项目:Ruth.Net8.Core.SqlServerMigrations(SqlServer)与 Ruth.Net8.Core.SqliteMigrations(Sqlite)两套同步;
  • 应用方式:WebAPI 启动时 RunMigrations.ExecuteAsync → db.Database.MigrateAsync() 自动应用,无需手工执行;
  • 新增迁移命令(示例,dotnet-ef 9.0.5 全局工具,需先把 C:\Program Files\dotnet 加入 PATH):
dotnet ef migrations add <迁移名> --project Ruth.Net8.Core.SqlServerMigrations --startup-project Ruth.Net8.Core.SqlServerMigrations --context RuthCoreContext
dotnet ef migrations add <迁移名> --project Ruth.Net8.Core.SqliteMigrations --startup-project Ruth.Net8.Core.SqliteMigrations --context RuthCoreContext

八、前端对接要点

  1. 登录:LoginAsync 返回值新增 data.Tenants(数组,空则未授权任何租户);
  2. 切换:调 /api/TenantController/SwitchTenantAsync,Body {"UserId": 用户Id, "TenantId": 目标租户Id},返回 data.Token(携带租户信息的 JWT);
  3. 访问:之后的请求带 Authorization: Bearer <Token>,服务端自动按该租户过滤数据;
  4. 授权管理界面:租户管理页维护租户;用户管理页或租户页调 SetUserTenantsAsync 分配可访问租户。
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2026.11.10 73 11/10/2026
2026.11.2 100 11/3/2026
2026.8.10 149 8/10/2026
2026.6.6 144 6/5/2026
2026.4.26 135 4/26/2026
2026.1.29 162 1/29/2026
2026.1.8 147 1/8/2026
2025.10.4 194 10/4/2025
2025.5.18 212 5/18/2025
2025.2.21 218 2/21/2025
2024.12.9 223 12/9/2024
2024.11.25 215 11/26/2024
2024.11.21 210 11/21/2024
2024.10.14 229 10/14/2024
2024.8.21 265 8/21/2024
8.0.4 238 5/7/2024
8.0.1 260 1/26/2024