RuoVea.ExDto 10.0.0.4

dotnet add package RuoVea.ExDto --version 10.0.0.4
                    
NuGet\Install-Package RuoVea.ExDto -Version 10.0.0.4
                    
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="RuoVea.ExDto" Version="10.0.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RuoVea.ExDto" Version="10.0.0.4" />
                    
Directory.Packages.props
<PackageReference Include="RuoVea.ExDto" />
                    
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 RuoVea.ExDto --version 10.0.0.4
                    
#r "nuget: RuoVea.ExDto, 10.0.0.4"
                    
#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 RuoVea.ExDto@10.0.0.4
                    
#: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=RuoVea.ExDto&version=10.0.0.4
                    
Install as a Cake Addin
#tool nuget:?package=RuoVea.ExDto&version=10.0.0.4
                    
Install as a Cake Tool

📦 RuoVea.ExDto

纯 BCL 共享契约库 — 提供 RESTful 响应模型、分页参数与结果、17 种业务枚举、实体基类接口、用户上下文抽象、Claim 常量及反射工具,内置 8 种语言的本地化资源,零 NuGet 依赖


📖 目录


📋 概览

RuoVea.ExDto 为 .NET 企业级应用提供统一的 DTO 契约层,避免各层之间重复定义数据结构。纯 BCL 实现,零第三方依赖,可直接放入任何 .NET 8.0+ 项目中。

 ┌──────────────────────────────────────────────────────────┐
 │                    RuoVea.ExDto                           │
 ├──────────────────────────────────────────────────────────┤
 │  RESTful 响应          分页模型           实体接口        │
 │  ├─ RestfulResult      ├─ PageParam       ├─ IPrimaryKey  │
 │  ├─ RestfulResult<T>   ├─ PageParam<T>    ├─ IAuditable   │
 │  ├─ Restful (工厂)     ├─ PageResult<T>   ├─ IDeleted     │
 │  └─ Restful<T> (工厂)  ├─ PageData        ├─ IDataEntity  │
 │                        └─ Pagination      └─ ITenantEntity│
 │                                                           │
 │  枚举系统 (17种)       Claim 常量         用户上下文      │
 │  ├─ CodeStatus         ├─ CLAINM_USERID   ├─ ICurrentUser │
 │  ├─ ErrorEnum (81项)   ├─ CLAINM_ACCOUNT  └─ ICurrentUser<TT>
 │  ├─ DataOpType         ├─ CLAINM_NAME
 │  ├─ BusinessType       ├─ TENANT_ID
 │  ├─ QueryTypeEnum      └─ ... (共14项)
 │  └─ ... (共17种)
 │                                                           │
 │  反射工具              国际化 (8语言)                     │
 │  ├─ EnumManager        ├─ zh-CN / zh-TW / zh-HK          │
 │  └─ DisplayInfo        ├─ en-US / fr-FR / ja-JP / vi-VN │
 │                        └─ I18nConverter (NET5.0+)        │
 ├──────────────────────────────────────────────────────────┤
 │  命名空间: RuoVea.ExDto | RuoVea.ExEnum                    │
 │  零依赖   纯 BCL 共享契约库                                │
 └──────────────────────────────────────────────────────────┘

设计原则

原则 说明
零依赖 仅依赖 .NET BCL(System.Collections.ConcurrentSystem.ComponentModel.DataAnnotations 等),无任何第三方 NuGet 引用
纯数据契约 不包含业务逻辑,不注册 DI,所有类型可直接 new 使用
静态工厂 Restful/Restful<T> 提供静态方法创建标准化响应,避免分散的 new RestfulResult { ... }
高性能缓存 EnumManager 使用 ConcurrentDictionary 作为缓存层,反射结果只计算一次
多语言支持 8 种 resx 资源文件覆盖中、英、法、日、越南语及粤语地区

📦 安装

.NET CLI

# .NET 8.0
dotnet add package RuoVea.ExDto --version 8.0.1.5

# .NET 10.0
dotnet add package RuoVea.ExDto --version 10.0.0.3

Package Manager

Install-Package RuoVea.ExDto -Version 8.0.1.5

PackageReference

<PackageReference Include="RuoVea.ExDto" Version="8.0.1.5" />

支持的 Target Framework

TFM 最低版本
net8.0 8.0.1.5
net10.0 10.0.0.3

⚡ 30 秒快速开始

1. 导入命名空间

using RuoVea.ExDto;      // 模型、接口、工具类
using RuoVea.ExEnum;      // 所有枚举类型

2. 第一行代码

// <inheritdoc cref="Restful{T}.Success"/>
// 创建成功响应
var successResult = Restful<string>.Success("Hello, ExDto!");

// <inheritdoc cref="Restful.Bad(string)"/>
// 创建错误响应
var errorResult = Restful.Bad("参数校验失败");

// <inheritdoc cref="PageParam"/>
// 分页查询参数
var pageParam = new PageParam(pageNo: 1, pageSize: 20)
{
    Sidx = "CreateTime",
    Sord = "desc"
};

// <inheritdoc cref="PageResult{T}"/>
// 分页结果
var pageResult = new PageResult<string>(
    rows: new[] { "A", "B", "C" },
    pageNo: 1,
    pageSize: 20,
    totalRows: 100
);
Console.WriteLine($"共 {pageResult.TotalPage} 页,{pageResult.TotalRows} 条记录");

3. 使用枚举和反射工具

// <inheritdoc cref="EnumManager.GetEnumItems{T}"/>
var adminTypes = EnumManager.GetEnumItems<AdminType>();
// → [{ Key: "None", Value: "0" }, { Key: "Admin", Value: "1" }, { Key: "SuperAdmin", Value: "2" }]

// <inheritdoc cref="EnumManager.GetAllEnumTypesInfo"/>
var allEnums = EnumManager.GetAllEnumTypesInfo();
// → 返回当前程序集中所有 17 种枚举的结构化信息

// <inheritdoc cref="ClaimConst.GetAllConstantInfos"/>
var claimInfo = ClaimConst.GetAllConstantInfos();
// → 14 个 Claim 常量的结构化元数据

30 秒内你完成了: RESTful 成功/失败响应 → 分页参数构建 → 枚举反射查询 → Claim 常量读取。无需任何 DI 注册或配置。


🧩 核心场景

场景一:RESTful 响应模型

┌────────────┐   Restful<T>.Success(data)   ┌──────────────────────┐
│  业务数据   │ ──────────────────────────▶ │  RestfulResult<T>     │
│  (T data)   │                              │  ├─ Code: OK (200)    │
└────────────┘                              │  ├─ Data: <T>         │
                                            │  ├─ Message: string   │
┌────────────┐   Restful.Bad(message)       │  ├─ Extras: object    │
│  错误信息   │ ──────────────────────────▶ │  └─ Timestamp: long   │
└────────────┘                              └──────────────────────┘
泛型响应
// <inheritdoc cref="Restful{T}.Success(T)"/>
var result = Restful<UserDto>.Success(new UserDto { Id = 1, Name = "张三" });
// result.Code == CodeStatus.OK
// result.Data is UserDto

// <inheritdoc cref="Restful{T}.Bad(string)"/>
var error = Restful<UserDto>.Bad("用户名已存在");
// error.Code == CodeStatus.BadRequest (400)
// error.Message == "用户名已存在"
// error.Data == null

// <inheritdoc cref="Restful{T}.Bad(CodeStatus, string)"/>
// 自定义状态码
var forbidden = Restful<UserDto>.Bad(CodeStatus.Forbidden, "无权访问该资源");
非泛型响应
// <inheritdoc cref="Restful.Success(object)"/>
var result = Restful.Success(new { Total = 100, Items = new[] { 1, 2, 3 } });

// <inheritdoc cref="Restful.Bad(string)"/>
var error = Restful.Bad("操作失败");
附加数据 (Extras)
// <inheritdoc cref="RestfulResult.Extras"/>
var result = Restful<UserDto>.Success(user);
result.Extras = new { Token = "jwt-token-string", ExpiresIn = 7200 };
// 前端可一并获取 token 和业务数据

已修复: RestfulResult.Timestamp 已改为 DateTimeOffset.UtcNow.ToUnixTimeSeconds(),输出真正的 Unix 时间戳(UTC 秒),跨时区一致。


场景二:分页参数与结果

┌─────────────────┐                    ┌──────────────────────┐
│  PageParam       │  传入 Service 层   │  PageResult<T>        │
│  ├─ PageNo: 1    │ ────────────────▶ │  ├─ PageNo: 1         │
│  ├─ PageSize: 20 │                    │  ├─ PageSize: 20      │
│  ├─ Sidx: "Id"   │                    │  ├─ TotalRows: 100    │
│  ├─ Sord: "desc" │                    │  ├─ TotalPage: 5      │
│  └─ BeginTime    │                    │  └─ Rows: IEnumerable │
└─────────────────┘                    └──────────────────────┘
// <inheritdoc cref="PageParam"/>
// 基础分页参数
var param = new PageParam
{
    PageNo = 2,
    PageSize = 50,
    Sidx = "CreateTime",
    Sord = "desc",
    BeginTime = DateTime.Now.AddDays(-30),
    EndTime = DateTime.Now
};

// <inheritdoc cref="PageParam{T}"/>
// 带查询条件的分页参数
var paramWithFilter = new PageParam<OrderFilter>
{
    PageNo = 1,
    Filter = new OrderFilter { Status = "pending", MinAmount = 100 }
};
// <inheritdoc cref="PageResult{T}"/>
// 构建分页结果
var rows = await db.Orders
    .Where(o => o.Status == "pending")
    .OrderByDescending(o => o.CreateTime)
    .Skip((param.PageNo - 1) * param.PageSize)
    .Take(param.PageSize)
    .ToListAsync();

var total = await db.Orders.CountAsync(o => o.Status == "pending");

var pageResult = new PageResult<OrderDto>(rows, param.PageNo, param.PageSize, total);
// pageResult.TotalPage 自动计算 (向上取整)
分页模型对比
类型 泛型 用途 典型场景
PageParam 基础分页查询参数 简单列表查询
PageParam<T> 带查询条件的分页参数 带 Filter 的高级搜索
PageResult<T> 泛型分页结果 返回强类型列表
PageData object 类型分页结果 兼容旧代码或动态数据
Pagination 精简分页模型 内部计算或轻量传输
// <inheritdoc cref="PageData"/>
// 非泛型分页(用于兼容旧接口)
var pageData = new PageData(new { Items = dataList }, 1, 20, 100);

// <inheritdoc cref="Pagination"/>
// 精简分页(TotalPage 基于 Total 自动计算)
var pagination = new Pagination(page: 2, pageSize: 30) { Total = 100 };
Console.WriteLine(pagination.TotalPage); // 4 (100/30 = 3.33 → 向上取整)

TotalPage 计算规则: PageResult<T>PageDataPaginationTotalPage 均采用 TotalRows % PageSize == 0 ? TotalRows / PageSize : TotalRows / PageSize + 1 的向上取整逻辑。当 TotalRows <= 0 时返回 0


场景三:实体基类接口

┌──────────────────────────────────────────────────────┐
│                    IDataEntity                         │
│  ├─ IPrimaryKeyEntity: long Id                       │
│  ├─ IAuditableEntity: CreateTime, Creator,            │
│  │                    ModifyTime, Modifier             │
│  └─ IDeletedEntity: IsDelete? (逻辑删除)              │
├──────────────────────────────────────────────────────┤
│  ITenantEntity: long? TenantId (多租户)               │
└──────────────────────────────────────────────────────┘
using RuoVea.ExDto;
using RuoVea.ExEnum;

// <inheritdoc cref="IDataEntity"/>
// 完整的审计实体(主键 + 审计 + 逻辑删除)
public class UserEntity : IDataEntity, ITenantEntity
{
    public long Id { get; set; }
    public DateTime? CreateTime { get; set; }
    public long? Creator { get; set; }
    public DateTime? ModifyTime { get; set; }
    public long? Modifier { get; set; }
    public IsDelete? IsDelete { get; set; }
    public long? TenantId { get; set; }

    // 业务字段
    public string Name { get; set; }
    public string Email { get; set; }
}

// <inheritdoc cref="IAuditableEntity"/>
// 仅审计字段(无主键、无逻辑删除),适用于关联表
public class UserRoleEntity : IAuditableEntity
{
    public long UserId { get; set; }
    public long RoleId { get; set; }
    public DateTime? CreateTime { get; set; }
    public long? Creator { get; set; }
    public DateTime? ModifyTime { get; set; }
    public long? Modifier { get; set; }
}
// 通用仓储约束
public interface IRepository<T> where T : IDataEntity
{
    Task<T> GetByIdAsync(long id);
    Task<PageResult<T>> GetPagedAsync(PageParam param);
    Task SoftDeleteAsync(long id);  // 设置 IsDelete = IsDelete.Y
}
实体接口详解
接口 成员 说明
IPrimaryKeyEntity long Id 统一长整型主键约定
IAuditableEntity DateTime? CreateTime, long? Creator, DateTime? ModifyTime, long? Modifier 创建/修改审计四个字段
IDeletedEntity IsDelete? IsDelete 逻辑删除标记(IsDelete.N=未删除, IsDelete.Y=已删除)
IDataEntity 继承以上三者 完整的数据实体契约
ITenantEntity long? TenantId 多租户隔离标识

场景四:用户上下文抽象

using RuoVea.ExDto;

// <inheritdoc cref="ICurrentUser"/>
// 标准 long 型用户上下文
public class AppUser : ICurrentUser
{
    public long UserId { get; set; }
    public long TenantId { get; set; }
    public string Account { get; set; }
    public string Name { get; set; }
    public bool IsSuperAdmin { get; set; }
    public bool IsTenantAdmin { get; set; }

    public T User<T>() where T : class
    {
        // 返回完整用户实体(可配合 EF Core 查询)
        return this as T;
    }
}

// <inheritdoc cref="ICurrentUser{TT}"/>
// 泛型用户上下文(支持 string / Guid 主键)
public class AppUser<TT> : ICurrentUser<TT>
{
    public TT UserId { get; set; }
    public TT TenantId { get; set; }
    public string Account { get; set; }
    public string Name { get; set; }
    public bool IsSuperAdmin { get; set; }
    public bool IsTenantAdmin { get; set; }

    public T User<T>() where T : class => null;
}
// Controller 中使用
[ApiController]
public class OrderController : ControllerBase
{
    private readonly ICurrentUser _currentUser;

    public OrderController(ICurrentUser currentUser)
    {
        _currentUser = currentUser;
    }

    [HttpGet]
    public IActionResult GetOrders()
    {
        // 利用用户上下文进行数据隔离
        if (!_currentUser.IsSuperAdmin)
        {
            // 非超级管理员仅查询本租户数据
            return Ok(await _orderService.GetByTenantAsync(_currentUser.TenantId));
        }
        return Ok(await _orderService.GetAllAsync());
    }
}

场景五:枚举与常量管理

┌──────────────┐    EnumManager.GetEnumItems<T>()    ┌─────────────────┐
│  枚举类型 T   │ ─────────────────────────────────▶ │  List<DisplayInfo>│
│  (17种枚举)   │     EnumManager.GetEnumDictionary<T>()│  (带缓存)        │
└──────────────┘                                    └─────────────────┘
获取单个枚举项
// <inheritdoc cref="EnumManager.GetEnumItems{T}"/>
var items = EnumManager.GetEnumItems<StatusEnum>();
// → [
//     { Key: "ENABLE", Value: "0", Name: "0", Description: "启用" },
//     { Key: "DISABLE", Value: "1", Name: "1", Description: "停用" }
//   ]

// <inheritdoc cref="EnumManager.GetEnumDictionary{T}"/>
var dict = EnumManager.GetEnumDictionary<Gender>();
// → { 1: "男", 2: "女", 3: "未知" }
批量获取与全局查询
// <inheritdoc cref="EnumManager.GetMultipleEnums"/>
var enums = EnumManager.GetMultipleEnums(typeof(StatusEnum), typeof(YesOrNot), typeof(Gender));

// <inheritdoc cref="EnumManager.GetAllEnumTypesInfo"/>
// 获取程序集中所有 17 种枚举的完整层级信息(含子项)
var allEnumInfo = EnumManager.GetAllEnumTypesInfo();
foreach (var enumInfo in allEnumInfo)
{
    Console.WriteLine($"{enumInfo.Name}: {enumInfo.Children.Count} 个值");
}

// <inheritdoc cref="EnumManager.GetSpecifiedEnumInfo"/>
var codeStatusInfo = EnumManager.GetSpecifiedEnumInfo("CodeStatus");
// → 包含 40 个 HTTP 状态码枚举值

// <inheritdoc cref="EnumManager.ClearEnumTypesCache"/>
// 若运行时动态加载了新枚举,可清除缓存强制重新反射
EnumManager.ClearEnumTypesCache();

性能提示: EnumManager 使用 ConcurrentDictionary 进行三层缓存。首次调用触发反射,后续直接返回缓存。新增 ClearAllCaches() 可一次性清除全部三层缓存;ClearEnumTypesCache() 仅清除类型信息缓存。


场景六:Claim 常量

// <inheritdoc cref="ClaimConst"/>
// 14 个标准 Claim Key 常量,避免硬编码字符串
var userIdClaim = ClaimConst.CLAINM_USERID;     // "UserId"
var accountClaim = ClaimConst.CLAINM_ACCOUNT;    // "Account"
var tenantIdClaim = ClaimConst.TENANT_ID;        // "TenantId"
var openIdClaim = ClaimConst.OpenId;             // "OpenId"

// JWT Token 生成时使用
var claims = new[]
{
    new Claim(ClaimConst.CLAINM_USERID, user.Id.ToString()),
    new Claim(ClaimConst.CLAINM_ACCOUNT, user.Account),
    new Claim(ClaimConst.CLAINM_NAME, user.Name),
    new Claim(ClaimConst.TENANT_ID, user.TenantId?.ToString() ?? ""),
    new Claim(ClaimConst.CLAINM_SUPERADMIN, user.IsSuperAdmin.ToString()),
    new Claim(ClaimConst.LoginMode, "PC")
};

// <inheritdoc cref="ClaimConst.GetAllConstantInfos"/>
var allClaimInfo = ClaimConst.GetAllConstantInfos();
// → 返回 DisplayInfo 树形结构,包含 14 个子项,每项含 Name/ShortName/Description/GroupName/Order
foreach (var child in allClaimInfo.Children)
{
    Console.WriteLine($"{child.Name} = \"{child.Value}\" ({child.Description})");
}
Claim 常量分组
分组 Claim Key 常量值 说明
UserInfo CLAIINM_USERID "UserId" 用户ID
CLAIINM_ACCOUNT "Account" 账号
CLAIINM_NAME "Name" 名称
RealName "RealName" 真实姓名
NickName "NickName" 昵称
AccountType "AccountType" 账号类型
RolePermission CLAIINM_ROLEIDS "RoleIds" 角色Id
CLAIINM_ISADMIN "IsAdmin" 是否管理
CLAIINM_SUPERADMIN "SuperAdmin" 是否超级管理
Organization TENANT_ID "TenantId" 租户Id
OrgId "OrgId" 组织机构Id
OrgName "OrgName" 组织机构名称
Authentication OpenId "OpenId" 微信OpenId
LoginMode "LoginMode" 登录模式(PC/APP)

⚙️ 配置选项详解

本包是纯数据契约库,无 DI 扩展方法,所有类型均可直接实例化,无需任何配置。

RestfulResult / RestfulResult<T>

属性 类型 默认值 说明
Code CodeStatus OK (200) HTTP 状态码枚举
Message object / string null 错误/提示信息
Data object / T null 响应数据
Extras object null 附加数据(如 Token、分页信息)
Timestamp long Unix 秒(UTC) DateTimeOffset.UtcNow.ToUnixTimeSeconds()

Restful / Restful<T> 工厂方法

方法 返回 说明
Success() RestfulResult / RestfulResult<T> Code = OK, Message/Data = null
Success(T data) / Success(object data) 同上 Code = OK, Data = data
Bad() 同上 Code = BadRequest
Bad(string message) 同上 Code = BadRequest, Message = message
Bad(CodeStatus code, string message) 同上 自定义 Code 和 Message

PageParam / PageParam<T>

参数 类型 默认值 说明
PageNo int 1 当前页码(从1开始)
PageSize int 20 每页行数
Sidx string null 排序列名称
Sord string "asc" 排序方向 ("asc" / "desc")
BeginTime DateTime? null 搜索开始时间
EndTime DateTime? null 搜索结束时间
Filter (PageParam<T> only) T default 查询条件对象

IRESTfulResult 接口

方法 参数 返回 说明
RESTfulResult CodeStatus statusCode, object data, object message, object extras dynamic 统一 RESTful 响应方法签名

命名警告: IRESTfulResult 接口定义在文件 IRestfulFilterLog.cs 中,接口名与文件名不匹配。查找该接口时请搜索 IRESTfulResult 而非 IRestfulFilterLog

DisplayInfo 模型

属性 类型 说明
Value string 常量/枚举的数值(字符串形式)
Name string 显示名称
ShortName string 短名称/简称
Description string 描述文本
GroupName string 分组名称
Order int 排序顺序
Key string 常量/枚举键名
Children List<DisplayInfo> 子项列表(用于树形结构)

I18nConverter(条件编译)

// 仅在 NET5.0_OR_GREATER 下可用
#if NET5_0_OR_GREATER
// <inheritdoc cref="I18nConverter.ConvertResxToJson"/>
// 将 resx 资源转换为 JSON 字符串
string json = I18nConverter.ConvertResxToJson();
// → { "continue": "Continue", "badrequest": "Bad Request", ... }
#endif

🧵 线程安全

组件 线程安全 说明
EnumManager ✅ 是 所有缓存使用 ConcurrentDictionary.GetOrAdd,确保只反射一次
ClaimConst.GetAllConstantInfos() ✅ 是 使用 ConcurrentDictionary.GetOrAdd
Restful / Restful<T> ✅ 是 纯静态工厂,每次返回新实例
RestfulResult / RestfulResult<T> ✅ 是 普通 POCO 类,无共享状态
PageParam / PageResult<T> / PageData / Pagination ✅ 是 普通 POCO 类,无共享状态
DisplayInfo ✅ 是 普通 POCO 类,无共享状态
i18n / I18nConverter ✅ 是 ResourceManager 天然线程安全
实体接口 (IDataEntity 等) ✅ 是 无状态的接口定义
枚举类型 ✅ 是 不可变值类型

全部线程安全。本包是纯数据契约库,所有类型均无共享可变状态。


📊 类型速查表

17 种枚举速查

枚举 值数量 典型值
AdminType 3 None=0, Admin=1, SuperAdmin=2
BusinessType 10 OTHER, INSERT, UPDATE, DELETE, GRANT, EXPORT, IMPORT, FORCE, GENCODE, CLEAN
CategoryEnum 11 NORMAL, GITEE, GITHUB, WECHART, AILIPAY, QQ, BAIDU, TRILl, DingTalkQrcodeOAuth, Microsoft, Coding
CodeStatus 40 HTTP 100–505,含 OK=200, BadRequest=400, Unauthorized=401, Forbidden=403, NotFound=404, InternalServerError=500
DataOpType 14 OTHER, ADD, DELETE, EDIT, UPDATE, QUERY, DETAIL, TREE, IMPORT, EXPORT, GRANT, FORCE, CLEAN, CHANGE_STATUS
DataScopeType 5 ALL=1, DEPT_WITH_CHILD=2, DEPT=3, SELF=4, DEFINE=5
ErrorEnum 81 D1000D1600, xg1000xg1002, B1000B1006 系统错误码
Gender 3 MALE=1, FEMALE=2, UNKNOWN=3
IsDelete 2 N=0, Y=1
LoginType 5 LOGIN, LOGOUT, REGISTER, CHANGEPASSWORD, AUTHORIZEDLOGIN
MenuType 3 DIR=0, MENU=1, BTN=2
QueryTypeEnum 8 eq=0, like=1, gt=2, lt=3, ne=4, ge=5, le=6, isNotNull=7
RequestTypeEnum 5 Run=0, Get=1, Post=2, Put=3, Delete=4
SordEnum 2 Asc=1, Desc=2
StatusEnum 2 ENABLE=0, DISABLE=1
TenantTypeEnum 2 COMMON=0, SYSTEM=1
YesOrNot 2 N=0, Y=1

模型类型速查

类型 用途 关键成员
RestfulResult 非泛型 RESTful 响应 Code, Message, Data, Extras, Timestamp
RestfulResult<T> 泛型 RESTful 响应 同上 + 泛型 Data: T
Restful 非泛型静态工厂 Success(), Success(object), Bad(), Bad(string), Bad(CodeStatus, string)
Restful<T> 泛型静态工厂 同上,返回 RestfulResult<T>
PageParam 基础分页查询参数 PageNo=1, PageSize=20, Sidx, Sord="asc", BeginTime, EndTime
PageParam<T> 带条件的分页参数 继承 PageParam + Filter: T
PageResult<T> 泛型分页结果 PageNo, PageSize, TotalPage(计算), TotalRows, Rows
PageData 非泛型分页结果 同上,Rows: object
Pagination 精简分页模型 PageSize, PageNo, Sidx, Sord, Total, TotalPage(计算)

接口类型速查

接口 用途 关键成员
IPrimaryKeyEntity 主键约定 long Id
IAuditableEntity 审计字段约定 CreateTime, Creator, ModifyTime, Modifier
IDeletedEntity 逻辑删除约定 IsDelete?
IDataEntity 完整数据实体契约 继承 IPrimaryKeyEntity + IAuditableEntity + IDeletedEntity
ITenantEntity 多租户隔离 long? TenantId
ICurrentUser<TT> 泛型用户上下文 TT UserId, TT TenantId, Account, Name, IsSuperAdmin, IsTenantAdmin, User<T>()
ICurrentUser 标准用户上下文 继承 ICurrentUser<long>
IRESTfulResult RESTful 响应约定 dynamic RESTfulResult(CodeStatus, object data, object message, object extras)

🌍 国际化

i18n 资源类(RuoVea.ExDto.Language 命名空间)提供 8 种语言的本地化字符串,根据 CultureInfo.CurrentUICulture 自动切换:

语言 区域代码 资源文件
简体中文 (默认) zh-CN i18n.resx
繁体中文(台湾) zh-TW i18n.zh-TW.resx
粤语(香港) zh-HK i18n.zh-HK.resx
英语 en-US i18n.en-US.resx
法语 fr-FR i18n.fr-FR.resx
日语 ja-JP i18n.ja-JP.resx
越南语 vi-VN i18n.vi-VN.resx

注:i18n.resx 为默认回退资源(简体中文),其余按 CultureInfo 自动匹配。

using RuoVea.ExDto.Language;

// 当前线程 UI 文化为 en-US 时:
// i18n.@continue → "Continue"
// i18n.badrequest → "Bad Request"
// i18n.notfound → "Not Found"

// 当前线程 UI 文化为 ja-JP 时对应的日语本地化字符串

I18nConverter(NET5.0+ 专属)

#if NET5_0_OR_GREATER
// <inheritdoc cref="I18nConverter.ConvertResxToJson"/>
// 将当前语言的 resx 资源导出为 JSON 字符串
// 可用于前端 i18n 初始化或 API 输出
string json = I18nConverter.ConvertResxToJson();
#endif

⚠️ 关键警告

1. RestfulResult.Timestamp 时区硬编码

// RestfulResult.cs 原始实现:
public long Timestamp { get; set; } = 
    (DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000 - 8 * 60 * 60;

已修复: Timestamp 现使用 DateTimeOffset.UtcNow.ToUnixTimeSeconds() 生成标准 Unix 时间戳,跨时区一致。

2. 无 DI 注册扩展

本包是纯数据库,不包含 IServiceCollection 扩展方法。DI 注册需由调用方自行处理:

// 需自行注册 ICurrentUser 的实现
services.AddScoped<ICurrentUser, AppUser>();

3. IRESTfulResult 接口文件名不匹配

接口 IRESTfulResult 定义在 IRestfulFilterLog.cs 文件中,两者名称不一致。通过 IDE 搜索时应使用接口名 IRESTfulResult 而非文件名。

4. PageData 非泛型限制

PageData.Rows 类型为 object,使用时需要手动类型转换。新项目建议优先使用 PageResult<T>

5. EnumManager 程序集扫描范围

GetAllEnumTypesInfo() 仅扫描命名空间为 RuoVea.ExEnum 的枚举类型。若在外部程序集定义了同命名空间的枚举,不会被自动扫描到——需使用 GetAllEnums(assemblies) 重载。


🗺️ 版本迁移指南

从手工定义 DTO 迁移

旧代码模式 迁移到 RuoVea.ExDto
自定义 ApiResult<T> RestfulResult<T> + Restful<T>.Success() / Restful<T>.Bad()
自定义 PagedList<T> PageResult<T>
手动定义 long Id 接口 IPrimaryKeyEntity
手动定义 CreateTime/Creator 审计字段 IAuditableEntity
const string UserId = "UserId" 硬编码 ClaimConst.CLAINM_USERID
手动 Enum.GetValues() + GetName() EnumManager.GetEnumItems<T>()

v8.0.x → v10.0.x

  • API 无变化。v10.0.x 仅在 net10.0 TFM 上编译,所有公开 API 签名与 v8.0.x 保持一致。
  • 无依赖包变更。

📄 License

MIT License © RuoVea


🔗 相关资源: NuGet Gallery · 问题反馈

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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.
  • net10.0

    • No dependencies.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on RuoVea.ExDto:

Package Downloads
RuoVea.ExSugar

Sqlsugar扩展 快速注入,支持简体中文、繁体中文、粤语、日语、法语、英语.使用方式:service.AddSqlsugar();继承RestFulLog 重写异常日志,操作日志,差异日志

RuoVea.ExFilter

注入 进行全局的异常日志收集、执行操作日志、参数验证,支持简体中文、繁体中文、粤语、日语、法语、英语.services.ExceptionSetup();// 注入 全局错误日志处 services.ExceptionSetup(ExceptionLog actionOptions);// 注入 全局错误日志处 services.ExceptionSetup(builder.Configuration.GetSection("AopOption:ExceptionLog"));// 注入 全局错误日志处 services.RequestActionSetup();// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.RequestActionSetup(RequestLog actionOptions);// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.RequestActionSetup(builder.Configuration.GetSection("AopOption:RequestLog"));// 注入 请求日志拦截 [执行操作日志、参数验证 ] services.ResourceSetup();//对资源型信息进行过滤 services.ResultSetup();//对结果进行统一 services.ApISafeSetup(AppSign actionOptions);//接口安全校验 services.ApISafeSetup(builder.Configuration.GetSection("AopOption:AppSign"));//接口安全校验 services.ApISignSetup(AppSign actionOptions);//签名验证 ( appKey + signKey + timeStamp + data ); services.ApISignSetup(builder.Configuration.GetSection("AopOption:AppSign"));//签名验证 ( appKey + signKey + timeStamp + data ); services.AddValidateSetup();//模型校验 services.AddUiFilesZipSetup();//将前端UI压缩文件进行解压 不进行接口安全校验 -> NonAplSafeAttribute 不签名验证 -> NonAplSignAttribute 不进行全局的异常日志收集 -> NonExceptionAttribute 不对资源型信息进行过滤 -> NonResourceAttribute 不对结果进行统一 -> NonRestfulResultAttribute

RuoVea.ExJwtBearer

Jwt 授权验证拓展插件。声名:IJwtHelper _jwtHelper,支持简体中文、繁体中文、粤语、日语、法语、英语.添加验权:services.AddAuthenticationSetup(enableGlobalAuthorize: true);添加鉴权:services.AddAuthorizationSetup.MyPermission.(enableGlobalAuthorize: true);添加Jwt加密:services.AddJwtSetup();

RuoVea.ExWeb

CorsUrls、IPLimit、SafeIps、Jwt 配置

RuoVea.ExGlobal

web 注入 全局错误日志、操作日志记录

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.0.0.4 2,534 6/24/2026
10.0.0.3 1,132 1/26/2026
10.0.0.2 200 1/12/2026
9.0.0.4 1,374 1/26/2026
9.0.0.3 440 10/23/2025
9.0.0.2 283 10/23/2025
8.0.1.6 4,511 6/24/2026
8.0.1.5 2,689 1/26/2026
8.0.1.4 3,558 10/23/2025
8.0.1.3 285 10/23/2025
7.0.1.5 2,491 1/26/2026
7.0.1.4 4,140 10/23/2025
6.0.12.5 3,010 1/26/2026
6.0.12.4 5,247 10/23/2025
5.0.16.5 511 1/26/2026
5.0.16.4 500 10/23/2025
2.1.1.5 155 1/26/2026
2.1.1.4 274 10/23/2025
2.0.0.5 144 1/26/2026
2.0.0.4 286 10/23/2025
Loading failed