Skip to content

tinylit/inkslab

Repository files navigation

Inkslab

GitHub language codeSize AppVeyor AppVeyor tests GitHub issues

Inkslab 是什么?

Inkslab 是一套简单、高效、模块化的 .NET 轻量基础设施框架。它由若干独立 NuGet 包组成,围绕 SingletonPools 单例池与 XStartup 启动机制协同工作:面向接口、约定优先、按需引用、零侵入替换

核心特性

  • 统一 API 设计:所有模块遵循 接口契约 + 默认实现 + 单例池注册 的一致模式。
  • 自动启动XStartup 扫描并按 Code/Weight 顺序执行所有 IStartup
  • 语法糖扩展:字符串、集合、日期、枚举、类型、反射、加密等扩展方法位于 src/Inkslab/Extentions
  • 多框架支持net461 / netstandard2.1 / net6.0
  • 零侵入替换:任何默认实现都可以通过 SingletonPools.TryAdd<TService, TImplementation>() 在启动前替换。

仓库结构

以下 6 个 src/ 子目录各自对应一个独立的 NuGet 包,是唯一可被引用的交付物:

inkslab/
└─ src/
   ├─ Inkslab/          # 核心基础包(所有场景均需引用)
   ├─ Inkslab.Config/   # 配置读取           → 文档: Inkslab.Config.md
   ├─ Inkslab.Json/     # JSON 序列化         → 文档: Inkslab.Json.md
   ├─ Inkslab.Map/      # 对象映射            → 文档: Inkslab.Map.md
   ├─ Inkslab.DI/       # 依赖注入自动装配    → 文档: Inkslab.DI.md
   └─ Inkslab.Net/      # HTTP 请求客户端     → 文档: Inkslab.Net.md

模块选择指南

AI 使用提示:根据下表"适用场景"一列匹配需求,点击"详细文档"链接获取完整 API 参考。Inkslab(核心包)是所有模块的共同依赖,始终需要引用。下表仅列出可通过 NuGet 引用的 6 个包,源码仓库中的 tests/ 不在其中。

包名 适用场景 核心 API 详细文档
Inkslab 单例池注册/获取、框架启动协调、雪花算法主键生成、LRU/LFU 有界缓存、异步锁、字符串/集合/日期/加密扩展方法、模板格式化(StringSugar)、XML 序列化、正则常量 SingletonPoolsXStartupKeyGenLru<K,V>Lfu<K,V>AsynchronousLock 本文
Inkslab.Config 读取配置文件(appsettings.json / app.config);强类型对象绑定;热更新监听 "key".Config<T>()IConfigHelperConfigHelper Inkslab.Config.md
Inkslab.Json JSON 序列化与反序列化;命名风格转换(camelCase / snake_case);匿名类型反序列化;属性忽略([Ignore]);键名覆盖([JsonProperty] JsonHelper.ToJson()JsonHelper.Json<T>() Inkslab.Json.md
Inkslab.Map 不同类型对象互转(Entity ↔ DTO);集合/字典映射;深拷贝;构造函数映射;自定义字段改名/忽略/常量 Mapper.Map<T>()MapperInstanceProfile Inkslab.Map.md
Inkslab.DI IServiceCollection 自动注册服务(按 [Singleton]/[Scoped]/[Transient] 特性或 IConfigureServices 约定),取代手动 AddSingleton/AddScoped 等调用 .DependencyInjection(options).SeekAssemblies().ConfigureByDefined().ConfigureByAuto() Inkslab.DI.md
Inkslab.Net 发送 HTTP/REST 请求;链式设置请求头、Query 参数、请求体(JSON/XML/Form/multipart);响应反序列化;条件重试;数据验证;流下载 IRequestFactory.CreateRequestable(url).JsonCast<T>().When().ThenAsync() Inkslab.Net.md

NuGet 包一览

版本 下载 文档 用途
Inkslab Nuget Nuget 本文 核心基础设施
Inkslab.Config Nuget Nuget Inkslab.Config.md 配置文件读取
Inkslab.Json Nuget Nuget Inkslab.Json.md JSON 序列化
Inkslab.Map Nuget Nuget Inkslab.Map.md 对象映射
Inkslab.DI Nuget Nuget Inkslab.DI.md 依赖注入扩展
Inkslab.Net Nuget Nuget Inkslab.Net.md HTTP 请求

快速入门

1. 安装核心包

dotnet add package Inkslab

2. 启动框架

框架使用 XStartup 发现并执行所有 IStartup(含其它 Inkslab.* 包的默认注册)。

using Inkslab;

using (var startup = new XStartup())
{
    startup.DoStartup();
}

XStartup 构造函数支持按程序集模式、程序集实例、类型集合进行范围限定:

new XStartup();                          // 扫描基目录所有程序集
new XStartup("MyApp.*.dll");             // 按通配符
new XStartup(new[] { typeof(Program).Assembly });

3. 按需引入实现包

仅添加 Inkslab 不会带入 JSON/Map/Net/Config 实现。按需引用即可;引用后无需任何代码,XStartup 会自动注册默认实现到单例池。

dotnet add package Inkslab.Json      # 注册 IJsonHelper
dotnet add package Inkslab.Config    # 注册 IConfigHelper
dotnet add package Inkslab.Map       # 注册 IMapper
dotnet add package Inkslab.Net       # 通过 DI 注入 IRequestFactory
dotnet add package Inkslab.DI        # 为 IServiceCollection 提供自动装配扩展

核心 API 速览

单例池 SingletonPools

所有服务契约的统一注册与获取入口。

// 注册(返回 false 代表已注册)
SingletonPools.TryAdd<IJsonHelper, CustomJsonHelper>();
SingletonPools.TryAdd<IMyService>(new MyServiceImpl());
SingletonPools.TryAdd<IMyService>(() => new MyServiceImpl());

// 获取
var json = SingletonPools.Singleton<IJsonHelper>();
方法 说明
TryAdd<TService>() 注册无参默认实现
TryAdd<TService>(TService instance) 注册已有实例
TryAdd<TService>(Func<TService> factory) 注册工厂
TryAdd<TService, TImplementation>() 注册契约-实现映射
Singleton<TService>() 获取单例,未注册时按约定创建

启动项契约 IStartup

public interface IStartup
{
    int Code { get; }      // 启动阶段编号(排序依据)
    int Weight { get; }    // 同阶段内权重
    void Startup();        // 注册逻辑(通常向 SingletonPools 注册默认实现)
}

实现此接口 + 放入被扫描的程序集即可自动被 XStartup 执行。

主键生成 KeyGen

默认基于雪花算法。

long id  = KeyGen.Id();    // long 主键
Key key  = KeyGen.New();   // 值对象封装
Key key2 = KeyGen.New(id); // 从已有 long 还原

// 自定义机房/机器号(启动前注册)
SingletonPools.TryAdd(new KeyOptions(workerId: 1, datacenterId: 1));

分页与懒加载

var page = new PagedList<User>(users, pageIndex: 1, pageSize: 20, total: 135);

命名风格 NamingType

public enum NamingType
{
    Normal = 0,       // 原样
    CamelCase = 1,    // userName
    SnakeCase = 2,    // user_name
    PascalCase = 3,   // UserName
    KebabCase = 4     // user-name
}

"UserName".ToNamingCase(NamingType.SnakeCase);  // => "user_name"
  • Lru<T> / Lru<TKey, TValue>:线程安全 LRU 淘汰。
  • Lfu<T> / Lfu<TKey, TValue>:线程安全 LFU 淘汰。
  • 共用 IEliminationAlgorithm<T> 契约,便于替换。
  • 分片并发:内部按哈希分片以降低锁竞争,每个分片各自持锁。
  • 整体容量淘汰:淘汰以整个缓存的容量为界(借助跨分片共享的原子计数器判断),仅当缓存整体写满才触发淘汰,避免单个分片因本地计数提前淘汰、导致整体远未达容量即开始丢数据。当整体已满但命中的分片为空时,本次写入直接放弃缓存以保持整体不超容。

悲观异步锁(基于 SemaphoreSlim):

using (await _lock.AcquireAsync())
{
    // 临界区
}
异常 用途
CodeException 基础异常(带错误码)
BusiException 业务异常
ServException 服务层异常
SyntaxException 语法/配置错误

程序集发现 AssemblyFinder

var asms = AssemblyFinder.Find("MyApp.*.dll");

Singleton<T> 泛型访问器

SingletonPools.Singleton<T>() 的类型安全封装,适合在静态字段或字段初始化器中使用,内部采用嵌套类延迟初始化,性能与直接调用等价:

private static readonly IJsonHelper _json = Singleton<IJsonHelper>.Instance;
private static readonly DefaultSettings _settings = Singleton<DefaultSettings>.Instance;

Regexs 预编译正则

位于 Inkslab.Regexs,提供预编译的常用正则(字段以 Is 开头表示完整匹配,否则表示"包含"):

成员 类型 说明
IsMail Regex 邮箱地址完整匹配
IsNumber Regex 数字(含正负号与小数点)
Whitespaces Regex 含空白符(包括 \t\r\n
ChineseCharacters Regex 含中文字符
DoubleByteCharacters Regex 含双字节字符(含汉字)
Regexs.IsMail.IsMatch("user@example.com");     // true
Regexs.IsNumber.IsMatch("-3.14");               // true
Regexs.ChineseCharacters.IsMatch("Hello你好");  // true

XmlHelper XML 序列化

位于 Inkslab.Serialize.Xml,提供静态 XML 序列化/反序列化,与 Inkslab.Net.XmlCast<T>() 内部保持一致:

using Inkslab.Serialize.Xml;

// 序列化(失败时 obj 为 null 返回 null)
string xml = XmlHelper.XmlSerialize(dto);
string xml = XmlHelper.XmlSerialize(dto, Encoding.UTF8, indented: true);

// 反序列化(失败静默返回 null / default,不抛出异常)
var dto = XmlHelper.XmlDeserialize<MyDto>(xml);
var obj = XmlHelper.XmlDeserialize(xml, typeof(MyDto));

CData 的相等比较统一采用 StringComparison.Ordinal(区分大小写、文化无关,且对 null 安全),保证序列化往返及用作字典键时行为稳定一致。


注解(Inkslab.Annotations

跨模块共享的元数据注解,无额外包依赖(位于核心 Inkslab 包):

注解 作用目标 用途
[Export] DI 标记基类;[Singleton] / [Scoped] / [Transient] 均继承自此
[Import] 构造器 / 属性 / 字段 标记 DI 注入点
[Ignore] 属性 / 字段 Map 映射与 JSON 序列化时跳过该成员
[JsonProperty("name")] 属性 / 字段 / 参数 覆盖 JSON 序列化 / 反序列化时使用的键名
[Match("groupName")] 方法参数 AdapterSugar 中将参数绑定到指定命名正则组
[Mismatch("groupName")] 方法(可多次叠加) AdapterSugar 中:当指定命名正则组匹配成功时排除此方法
public class User
{
    public int    Id   { get; set; }

    [JsonProperty("user_name")]     // JSON 输出 key 为 user_name
    public string Name { get; set; }

    [Ignore]                        // Map 映射与 JSON 均跳过
    public string Password { get; set; }
}

扩展方法索引

全部位于 Inkslab 命名空间(部分定义在 System 以实现全局可见)。

分类 文件 主要方法
字符串 StringExtensions ToNamingCase · ToPascalCase · ToSnakeCase · ToCamelCase · ToKebabCase · IsNull · IsEmpty · IsMail · Format · Config<T> · StringSugar
集合 IEnumerableExtentions Join · ForEach · Distinct · AlignOverall · Align · ZipEach · AlignEach · JoinEach
日期时间 DateTimeExtensions StartOfDay/Week/Month/Quarter/Year · EndOfDay/... · IsToday/Yesterday/Tomorrow · IsWeekday/Weekend · IsSameDay/Week/Month/Year · WeekOfYear · IsLeapYear · NextWeekday · PreviousWeekday · WorkingDays · AddWorkingDays · ToUnixTimestamp[Milliseconds] · FromUnixTimestamp[Milliseconds] · GetAge · RoundTo/FloorTo/CeilingTo
枚举 EnumExtensions GetText · ToInt32 · ToInt64 · ToValueString · ToValues
类型 TypeExtensions IsMini · IsSimple · IsNullable · IsKeyValuePair · IsAmongOf · IsLike
反射 ReflectionExtensions IsIgnore · GetDescription
加密 CryptoExtensions Md5 · Encrypt · DecryptCryptoKind.DES / AES / ...)

日期周边界约定UTC 以周日为一周起始,Local 以周一为起始。

StringSugar 属性模板格式化

通过扩展方法 string.StringSugar(source) 将模板字符串中的 ${PropertyName} 占位符替换为对象属性值,底层正则规则由 IStringSugar 决定(可通过 SingletonPools.TryAdd<IStringSugar, MyStringSugar>() 替换)。

默认实现(DefaultStringSugar)支持以下语法:

语法 说明 示例
${Name} 属性值 ${UserName}
${Name:format} 带格式化,调用 .ToString(format) ${CreateAt:yyyy-MM}${Status:D}
${Name:#} 字符串属性的字符数(Length) ${Title:#}
${Name:0..5} 字符串属性的子串(Substring) ${Title:0..5}
${A?B} / ${A??B} 空值合并:A 为 null 则返回 B,否则返回 A ${Nickname?UserName}
${A+B} 值合并(数值相加 / 字符串拼接) ${First+Last}
${A?+B} 空试探合并:A 为 null 则返回 null,否则返回 A+B ${Prefix?+Name}
var user = new { Name = "张三", Age = 30, Birthday = new DateTime(1994, 6, 1) };
"姓名:${Name},年龄:${Age}".StringSugar(user);
// => "姓名:张三,年龄:30"

"生日:${Birthday:yyyy-MM-dd}".StringSugar(user);
// => "生日:1994-06-01"

var order = new { Code = (string)null, BackupCode = "B001" };
"编号:${Code?BackupCode}".StringSugar(order);
// => "编号:B001"

通过 DefaultSettings 控制格式化行为:

// DefaultSettings(默认):字符串直接输出,null 输出 ""
"姓名=${Name}".StringSugar(user, new DefaultSettings());

// JsonSettings:字符串类型加双引号,null 输出 "null"
"姓名=${Name}".StringSugar(user, new JsonSettings());
// => 姓名="张三"

扩展 AdapterSugar<T>:继承此抽象类可自定义模板解析规则。在子类方法参数上使用 [Match("groupName")] 将参数绑定到指定命名正则组,在方法上使用 [Mismatch("groupName")] 声明"该命名组匹配时不触发此方法"。


使用示例

字符串命名与配置

"UserName".ToSnakeCase();                // "user_name"
"user_name".ToPascalCase();              // "UserName"

var conn = "ConnectionStrings:Default".Config<string>();
var cfg  = "AppSettings".Config<AppConfig>();

集合对齐与遍历

var ordered = array2.AlignOverall(array1).ToList();  // array2 按 array1 重排
array1.JoinEach(array2, x => x, y => y.Id, (x, y) => { /* 内连接回调 */ });

加密

"password".Md5();
var cipher = "data".Encrypt("Test@*$!", CryptoKind.DES);
var plain  = cipher.Decrypt("Test@*$!", CryptoKind.DES);

JSON / 配置 / 映射(配合实现包)

string json = JsonHelper.ToJson(obj, NamingType.CamelCase, indented: true);
var    obj2 = JsonHelper.Json<MyDto>(json, NamingType.CamelCase);

var    dbConn = "ConnectionStrings:Default".Config<string>();
var    dto    = Mapper.Map<UserDto>(user);

替换默认实现

任何 IXxxHelper 都可在启动前通过 SingletonPools.TryAdd 替换:

public class MyJsonHelper : IJsonHelper { /* ... */ }

// 必须在 XStartup.DoStartup() 之前调用
SingletonPools.TryAdd<IJsonHelper, MyJsonHelper>();

using var startup = new XStartup();
startup.DoStartup();

构建与发布

  • 版本管理Directory.Build.props 统一 Version=1.2.25LangVersion=9.0TreatWarningsAsErrors=trueGenerateDocumentationFile=true
  • 打包build.ps1 对 6 个包逐个 dotnet pack --configuration Release.nupkgs/
  • CIappveyor.ymlmain 分支自动发布到 NuGet。

贡献

  1. Fork 并创建特性分支:git checkout -b feature/xxx
  2. 补充或维护对应模块的单元测试。
  3. 确保 dotnet test 全部通过。
  4. 提交 PR。

许可证

MIT


Stargazers over time

About

【架构体系】笔墨纸砚,笔是灵魂、墨是自研、纸是平台、砚是辅助和支持。

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors