Confio 0.1.0-preview.1
Confio
独立的 .NET 配置文件读写组件,通过同一个 NuGet 包提供运行库与源生成器。源码和验证入口维护在项目仓库。
以 .NET 10 LTS 为主要目标,同时面向 .NET 8 / 9 和 Windows .NET Framework 4.6.2 至 4.8.1;现代 .NET 支持 JIT 与 Native AOT。当前处于预发布开发阶段,已实现 JSON、YAML/YML、TOML、INI、模型默认值与业务校验、同步与异步读写、不可变模型更新、直接变更订阅、字段保护、普通 DI 和原生 Configuration / Options / Host 接入,尚未正式发布。保护内置 Windows DPAPI、指定密钥的 AES-GCM、macOS Keychain 和 Linux Secret Service 接入。完整范围与实测边界见设计方案。
当前维护四种格式共用的配置读写、数据语义、保护和文件可靠性,示例服务于这些核心行为的验证;通用集成深化、额外格式及更多平台适配按明确需求推进,具体顺序见实施安排。
安装
预览包 Confio 0.1.0-preview.1 通过 BaGet 分发,NuGet 源地址为 https://baget.pluscode.cn/v3/index.json。安装不需要发布 API key。
在应用仓库的 NuGet.Config 中配置包源;已有配置时合并对应节点。以下映射让 Confio 从 BaGet 获取,其余依赖从 nuget.org 获取:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="BaGet" value="https://baget.pluscode.cn/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="BaGet">
<package pattern="Confio" />
</packageSource>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
</configuration>
在应用项目目录安装:
dotnet add package Confio --version 0.1.0-preview.1
也可以在项目文件中直接声明包引用。以下是可使用后文模型与读写代码的最小控制台项目:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Confio" Version="0.1.0-preview.1" />
</ItemGroup>
</Project>
Framework 应用将 TargetFramework 改为 net462 或下表中的其他 Framework 目标,同样保留 C# 12 设置。生成器和编译期辅助类型随包提供。现代 .NET 应用可直接发布 Native AOT,例如 Windows x64:
dotnet publish -c Release -r win-x64 -p:PublishAot=true
使用
应用声明模型和一个原生 JSON 上下文,Confio 自动生成配置节、默认构造、保护和类型服务声明。需要业务约束的模型实现 IValidatableSettings,规则只写一次,直接使用和 DI 共用。使用 SDK 风格项目、PackageReference 与 C# 12;当前验收工具链为 .NET 10 SDK,编译器版本不要求应用运行在 .NET 10。Confio 的生成器随 NuGet 包交付,应用无需额外安装生成器包。
| 应用目标 | NuGet 自动选择 | 发布方式 |
|---|---|---|
| .NET Framework 4.6.2 / 4.7 / 4.7.1 / 4.7.2 / 4.8 / 4.8.1 | net462 |
Windows 托管应用 |
| .NET 8 / 9 | net8.0 |
JIT、Native AOT |
| .NET 10 | net10.0 |
JIT、Native AOT |
低版本通过包依赖自动取得所需 JSON 静态元数据 API;Framework 的 AES-GCM 由微软官方兼容库提供,PolySharp 提供编译期语言辅助,使用 record/init 不必手写辅助类型。各目标共用以下模型和 API,不需要额外选择“兼容模式”或“AOT 包”。Framework 消费项目需显式设置 <LangVersion>12.0</LangVersion>;DateOnly 等仅在现代 .NET 存在的 BCL 类型不由 Confio 补造。
using Confio;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
[SettingsSection("Mail")]
public sealed class MailSettings : IValidatableSettings
{
public string Host { get; set; } = "localhost";
public int Port { get; set; } = 587;
[Protected]
public string Password { get; set; } = "";
public void Validate()
{
if (string.IsNullOrWhiteSpace(Host))
throw new ValidationException("The mail host is required.");
if (Port is < 1 or > 65535)
throw new ValidationException("The mail port must be between 1 and 65535.");
}
}
[SettingsSection("Retry")]
public sealed record RetrySettings : IValidatableSettings
{
public int MaxAttempts { get; init; } = 3;
public void Validate()
{
if (MaxAttempts < 1)
throw new ValidationException("At least one retry attempt is required.");
}
}
[JsonSerializable(typeof(MailSettings))]
[JsonSerializable(typeof(RetrySettings))]
public partial class AppSettingsContext : JsonSerializerContext
{
}
直接使用,以下代码放在方法体中:
using var config = new ConfigurationFile(
AppSettingsContext.Default, applicationId: "Contoso.Mail");
var mail = config.Read<MailSettings>();
mail.Host = "smtp.example.com";
mail.Port = 465;
config.Save(mail);
同一实例提供 ReadAsync、SaveAsync、UpdateAsync、ResetAsync、ReloadAsync,均返回 Task 并接受取消令牌。同步与异步消费都使用普通 using,首次读写自动加载,不需要先初始化。读取返回独立副本;修改副本后显式保存,或用 Update / UpdateAsync 基于最新文件修改。
| 要做的事 | 使用入口 | 实际效果 |
|---|---|---|
| 读取当前生效配置 | Read<T>() |
首次加载并自动保护文件中的明文,之后从最近成功的内存配置返回副本;不会每次读取磁盘 |
| 保存一份完整编辑结果 | Save(model) |
完整替换目标模型节;旧草稿也会覆盖该节的新值 |
| 在最新配置上修改 | Update<T>(edit) |
在文件锁内读取磁盘最新值,执行一次修改并保存;应用不管理文件锁或重试 |
| 恢复某个模型的默认值 | Reset<T>() |
删除该节的持久化覆盖,采用模型默认值;例如默认端口是 587,恢复后就是 587 |
| 采用外部文件修改 | Reload() |
重新读取并自动保护声明位置的明文,成功后更新生效配置;失败保留之前成功的内存配置 |
保存、更新或重置保留其他配置节的数据与已有密文,并将其他所选声明位置的待保护明文合并到同一次提交;完整替换目标节时,该节内未被模型承载的未知属性不保证保留。JSON 输出保留中文等常用 Unicode 文本的可读性,引号、控制字符和换行仍按 JSON 规则转义;不承诺原注释、排版或 YAML 锚点写法保持不变。
Update 同时接受修改副本的 Action<T> 和返回新模型的 Func<T,T>。record/init 模型使用 with,文件协调和保存由组件完成:
await config.UpdateAsync<RetrySettings>(retry =>
retry with { MaxAttempts = checked(retry.MaxAttempts + 1) });
业务校验在首次加载、重载和提交前执行,失败抛出 ValidationException,保留文件与最近的有效快照,不发出变化通知。已加载的普通读取不重复校验;Reset 也要求模型默认值有效。校验只读取模型,不做 I/O;消息描述规则,避免包含敏感值。它与原生 Options 的创建后校验有不同的执行时点,详见业务校验契约。
直接使用 config.OnChange<T>(listener),或在容器中调用 ISettings<T>.OnChange(listener),即可订阅共享文件的变化:
using var subscription = config.OnChange<MailSettings>(mail =>
System.Console.WriteLine($"当前端口:{mail.Port}"));
订阅不加载文件、不立即回调。成功保存、重置和重载后,每个订阅者获得当前模型的独立副本;同文件其他节的提交也会通知。回调在锁外执行,不保证 UI 线程;释放返回值可退订,回调异常通过诊断报告,不回滚保存。Avalonia 示例已演示 UI 调度和退订。
OnChange 不会自动监听外部文件,外部编辑后仍需调用 Reload。格式损坏、业务校验失败、解密失败都会报告,不能统一重置为默认值;修正配置或密钥后可重新加载。备份、恢复与历史管理不属于当前产品范围。Sample 的恢复按钮只还原它自己制造损坏前保留的演示原文,具体见错误处理与功能边界。
通过 path 的扩展名选择格式;默认是 JSON,.yaml 与 .yml 等价。JSON、YAML、TOML、INI 使用相同的模型、上下文和读写 API;应用不增加逐格式的序列化声明:
using var config = new ConfigurationFile(
AppSettingsContext.Default, applicationId: "Contoso.Mail", path: "appsettings.toml");
var mail = await config.ReadAsync<MailSettings>();
mail.Port = 465;
await config.SaveAsync(mail);
| 扩展名 | 可用范围与主要限制 |
|---|---|
.json |
对象、数组、标量、null,允许注释与尾逗号输入 |
.yaml / .yml |
YAML 1.2 Core 的字符串键映射、数组、标量、null 与已完成锚点的别名;字符串 00123 需要加引号 |
.toml |
表、数组、标量和原生日期;支持空容器、多行字符串,没有原生 null;原生整数为有符号 64 位,浮点为有限 binary64,保存不能往返的高精度数值会报错 |
.ini |
原生 INI 行与节规则,用 : 表示层级,数组用从 0 开始的连续索引;本项目的固定方言不支持 null、空容器和多行值 |
INI 根据静态模型判断类型:Port=465 进入整数属性,Code=00123 进入字符串属性并保留前导零。常见数值、布尔、枚举和日期类型由组件处理;不能确定明文形态的自定义转换器在创建文件实例时拒绝,整体保护后的载荷不受这一限制。
格式限制针对实际写入数据检查,不会悄悄省略属性或改为空字符串。例如整体保护的非空子对象先变成一条密文,其内部可以含 null 或空集合;属性本身是 null 时,TOML / INI 仍无法保存。保存保留其他配置节的数据语义与密文,包括 TOML 原生日期与普通字符串的区别;注释与原排版不承诺保留。完整边界见格式约定。
模型可以声明可空属性,由实际保存的值决定是否超出格式范围。格式适配发现无法表达的值时抛出 ConfigurationValueException,提供 Format、Path 和 Reason;文件、旧快照与通知保持不变,应用不需要先做一轮格式检查。开发者可以直接看到具体位置与原因,例如:
TOML cannot persist null at '/Mail/Password'.
INI cannot persist an empty collection at '/Mail/Recipients'.
Path 使用 JSON Pointer,例如 /Mail/Recipients/0 指向第一个元素,路径段中的 ~、/ 分别写为 ~0、~1。界面可根据结构化属性生成自己的提示,无需解析异常正文或显示配置值。
容器入口也通过同一个 path 参数选择格式。四种格式共用静态 JSON 模型元数据,TOML 的固定文档上下文由 Confio 内部生成;JIT 与 Native AOT 使用同一路径,应用无需额外声明 TOML 上下文。
普通容器只注册一次,应用服务直接注入 ISettings<MailSettings>,使用同样的类型读写方法:
services.AddConfigurationFile(
AppSettingsContext.Default, applicationId: "Contoso.Mail");
文件和类型服务默认是单例,文件由根容器释放;需要复用外部实例时使用 services.AddConfigurationFile(config),仍由调用方释放。注册和解析服务不加载文件。完整示例见容器接入示例,详细语义见读写与容器契约。
需要原生 IConfiguration、IOptions<T>、IOptionsSnapshot<T> 或 IOptionsMonitor<T> 时,直接用构建入口完成预加载和注册,不再调用前面的普通注册。以下代码位于异步方法中:
using var provider = await services.BuildServiceProviderWithConfigurationFileAsync(
AppSettingsContext.Default, applicationId: "Contoso.Mail");
var mail = provider.GetRequiredService<IOptionsMonitor<MailSettings>>().CurrentValue;
Host 使用原生构建器;需要只加载选定文件时,从空构建器开始。日志输出和业务服务按应用需要选择:
var builder = Host.CreateEmptyApplicationBuilder(null);
using var host = await builder.BuildWithConfigurationFileAsync(
AppSettingsContext.Default, applicationId: "Contoso.Mail",
configure: app =>
{
app.Logging.AddConfiguration(app.Configuration.GetSection("Logging")).AddConsole();
app.Services.AddHostedService<MailWorker>();
});
await host.RunAsync(cancellationToken);
上述原生类型分别来自 Microsoft.Extensions.DependencyInjection、Microsoft.Extensions.Configuration、Microsoft.Extensions.Options、Microsoft.Extensions.Hosting 和 Microsoft.Extensions.Logging;MailWorker 是应用自己的业务服务,可执行示例见容器接入示例。两个构建入口均有同步版本、上下文集合和已有文件重载;configure 在文件可读后执行。应用无需逐模型绑定或编写 Options 工厂,构建失败清理和自建文件释放由组件完成。
IConfiguration 保留原生配置源优先级。Confio 的默认命名 Options 从文件快照创建,再执行原生 Configure/PostConfigure/Validate;其他 Provider 的值不会自动进入该文件或这些 Options。保存、更新、重置和显式重载会刷新 IOptionsMonitor<T>,IOptions<T> 和已有作用域的快照保留原生缓存。编辑使用文件或 ISettings<T> 的副本;Provider 只读,外部文件修改通过 ConfigurationFile.Reload/ReloadAsync 获取。完整启动与所有权规则见原生读取接入。
省略 path 时,Windows 使用 %LocalAppData%/Confio/<applicationId>/appsettings.json。不存在的文件读取默认值,不落盘。标记 [Protected] 的字符串和子对象在保存时自动加密,首次加载或显式重载发现普通明文时自动加密写回;空字符串和 null 不调用密钥设施。
文件密文统一使用 enc:v1:<Base64> 字符串。文件输入中受保护位置的 enc: 是保留前缀,带该前缀的手写明文会按密文解析;版本、编码或认证失败会报错。通过模型 API 保存时,值始终按明文处理,即使密码本身以 enc:v1: 开头也能完整往返。读取已有密文不会重复加密写盘,未声明保护的普通字段不按前缀解密。
例如,手写一份普通明文配置:
{"Mail":{"Password":"smtp-password"}}
首次 Read 或显式 Reload 校验通过后,组件将 Password 自动替换为 enc:v1:<Base64> 密文,应用仍读到 smtp-password,无需额外调用保存。缺失的默认属性不会补写;需要保护而无法写回时加载失败,已有有效密文的文件可只读加载。四种格式使用相同规则。
默认使用系统用户保护:Windows 直接使用 DPAPI,现代 .NET 在 macOS 通过 Keychain 托管 AES 密钥,在 Linux 通过 Secret Service 托管 AES 密钥。Linux 默认保护需要 libsecret 0.19 或以上、用户 D-Bus 会话和可访问的 Secret Service;系统可能请求授权或解锁。已有用户反馈 macOS Sample 正常运行,专项平台验收范围见设计第 8.1 节。
服务器、Docker 或跨机器共享配置时,在同一个入口传入部署环境提供的稳定 32 字节随机密钥,即使用内置 AES-256-GCM;Windows、Linux、macOS 使用同一实现。应用无需创建保护器或管理算法参数:
using var config = new ConfigurationFile(
AppSettingsContext.Default, "Contoso.Mail", encryptionKey: key);
// 普通 DI、原生 Configuration / Options 和 Host 构建入口同样支持 encryptionKey。
services.AddConfigurationFile(
AppSettingsContext.Default, "Contoso.Mail", encryptionKey: key);
key 由应用的部署或凭据设施提供,不能每次启动重新生成,也不能与密文一起写入配置文件。构造或注册固定一份输入副本,文件实例管理内置保护器及其运行时密钥;高级设施通过 protector 参数传入 IConfigurationProtector,与 encryptionKey 互斥,外部实例始终由调用方管理。密钥服务不可用、密钥丢失及密文认证失败会报错并保留数据。跨机器解密需要相同密钥、应用标识和逻辑字段用途,默认系统保护不承诺文件可直接搬迁。
运行示例
ConfioSample 是 Avalonia 配置读写示例。首页提供四步引导,解释预期变化和对应 API;保存、恢复默认、读取和重新加载等常用按钮始终可见,无需先完成或收起引导。下方并排展示“你正在编辑、程序实际读到、磁盘实际保存”:程序值先用服务器、端口和密码状态展示,完整模型 JSON 按需展开。
从仓库根目录运行:
dotnet run --project samples/ConfioSample/ConfioSample.csproj -c Release
先依次点击引导中的四个按钮,无需准备配置文件:
- 填入示例值:左边端口变为
465,中间仍为默认值587,右边说明文件尚未创建。 - 保存邮件配置:中间采用
465,右边出现真实文件,非空密码和整个凭据对象自动加密。保存失败会停在这一步,并保留输入和上次成功结果。 - 模拟外部修改:另一个配置实例将文件端口改为
2525,当前程序仍读到465。 - 重新加载文件:程序和表单采用
2525。点击“继续自由探索”可收起引导。
每一步均可通过“查看模型与用法源码”查看实际模型声明。保存或“读取到表单”后,勾选密码旁的“显示”可核对解密后的原值;完整模型与操作记录默认隐藏敏感内容。可以随时收起引导,切到“重试”或“加密与失败演示”也会收起引导。“异步 API”默认勾选,取消勾选后操作和引导代码一起切换到同步入口。
完成引导后可按以下场景继续体验;容器功能放在独立的“进阶:容器接入”页。
| 界面操作 | 可观察的行为 |
|---|---|
| 顶部:打开目录 | 用系统文件管理器打开当前配置文件所在目录;尚未保存时只创建空目录,不生成配置文件,也不改变表单草稿 |
| 邮件:填入示例、保存 | 编辑不会改变程序已读取的值或文件;展开“集合与多行文本”可编辑收件人和多行备注 |
| Save / Update 对照:新建文件并运行对照 | 两份草稿都只改端口,另一个实例修改文件中的主机;重新打开文件后,Save 读到草稿中的旧主机,Update 读到外部修改后的主机。使用两个独立文件,保留当前文件与草稿,可打开对照目录查看原文;同步和异步均可运行 |
| 密码与 API 凭据 | Password 单字段保护,Credentials 子对象整体保护;快照保留模型结构并隐藏敏感内容,文件展示真实密文 |
| 重试:保存重试配置、次数 +1、恢复重试默认值 | Retry 使用 record/init;通过 with 基于最新文件值更新,保存或重置一个配置节保留另一个节及其表单草稿 |
| 加密与失败演示:正常保存空字符串、enc:v1:plain | 四种格式均可保存空字符串,它与 null 不同;前缀密码通过模型 API 保存后加密并完整还原 |
| 加密与失败演示:null | JSON / YAML 标为“正常保存”;TOML / INI 单列为“预期失败”,点击“验证 null 保存失败”后显示 /Mail/Password 与不支持 null 的原因,保留原文件、旧配置、草稿和通知状态 |
| 格式边界:空收件人、多行备注 | 当前 INI 方言拒绝空集合与多行值,错误分别定位到 /Mail/Recipients、/Mail/Notes,保留文件和编辑草稿;JSON / YAML / TOML 支持这两种值。顶部始终显示当前格式的限制 |
| 加密与失败演示:新建手写明文文件 → 加载文件,观察自动加密 | 两个相邻按钮先展示虚构明文,再用 Reload 自动加密写回,无需 Save;再次重载不重写有效密文,之前的演示文件保留 |
| 加密与失败演示:验证空白主机保存失败 | 标为“预期失败”,调用真实保存并由模型拒绝;文件、快照与通知次数保留,日志记录失败 |
| 刷新观察、读取到表单、重新加载文件 | 刷新观察保留草稿且不重载;读取到表单用已有快照替换草稿;重新加载从文件更新快照 |
| 加密与失败演示:写入损坏内容、还原演示文件 | 重载损坏文件失败后仍可读旧快照;仅撤销这次演示制造的损坏,不代表运行库提供备份恢复 |
| 普通 DI:读取当前配置、保存邮件表单 | 业务服务注入 ISettings<T>,与窗口共享文件实例。读取已有快照,保留文件及未保存草稿;保存使用“读写与加密”页的邮件表单,执行校验、保护并展示变更通知。外部文件修改仍需显式重新加载 |
| Options 对照与原生读取视图 | 用实际取值表格比较 Configuration、IOptions、原作用域与新作用域的 Snapshot、Monitor 及通知次数;下方展示已解密并脱敏的扁平读取投影 |
| Host 启停 | 使用空 Host 构建器,加载时执行模型校验,按原生启动时序创建 Options,显示托管服务的启动、读取与停止结果 |
| 用法源码、操作记录 | 查看实际参与编译的模型、读写事件与容器代码;查看最近 100 条操作和直接通知,包含顺序、时间与安全的失败提示 |
两个配置节模型使用同一个 AppSettingsContext,ApiCredentials 作为 Mail 的受保护子对象。窗口事件直接调用正式 API,入门引导复用相同动作,容器场景按方法组织。窗口拥有文件实例,容器场景借用它并在操作结束后释放各自的根;关闭窗口会先取消并等待正在执行的操作。源码页随构建嵌入实际模型与消费代码,不维护另一份展示代码。示例不发送邮件或自动监听配置文件。UI 采用 Avalonia 12.1.2(MIT,提供 net10.0 资产),相关依赖仅由示例工程引用。
默认使用每次独立的临时 JSON 路径,首次读取默认值不创建文件,窗口顶部显示完整路径。展开“新建演示与设置”,选择 JSON / YAML / TOML / INI 后点击“新建演示”可重新开始,之前的文件会保留。基础示例使用四种格式均可表达的数据;默认凭据为含空字符串成员的对象,主动取消凭据勾选才表示 null。选择只影响下次新建,左上“当前”标签始终显示当前文件使用的格式和保护方式。也可传入一个尚不存在的文件路径,已有文件会被拒绝,以免重置演示覆盖用户数据:
dotnet run --project samples/ConfioSample/ConfioSample.csproj -c Release -- artifacts/sample-run/appsettings.yaml
示例启用 AOT 分析,关闭默认 JSON 与 TOML 反射;Windows x64 可通过下列命令发布和运行 Native AOT,需要下文所述 C++ 工具链:
dotnet publish samples/ConfioSample/ConfioSample.csproj -c Release -r win-x64 -o artifacts/sample-aot
./artifacts/sample-aot/ConfioSample.exe
示例的新建演示入口可选择系统用户保护或 AES-GCM。AES-GCM 使用公开测试密钥,只处理示例创建的虚构数据;真实应用应从部署环境取得密钥。启动时传入 --aes 可直接选择该演示方式。
同一桌面程序提供 --verify 验收入口,依次触发可用按钮,断言同步/异步四步引导、失败不推进、可读摘要、JSON 展开与密码显示,以及集合、格式限制、字段及子对象保护、手写明文自动保护、前缀密码通过模型 API 往返、空值区别、校验失败、草稿隔离、不可变更新、通知、损坏文件恢复、独立文件中的 Save / Update 对照、DI / Options 作用域 / Host、源码资源、取消及新会话隔离。INI 会验证多行值与空集合失败,TOML / INI 会验证 null 失败;其他格式验证对应值往返。Save / Update 对照核实实际文件结果、当前文件与草稿保留,以及当前格式和保护选择不受下次新建设置影响。保护结果通过重新创建文件实例读取核对;除明确展示虚构手写文件的步骤外,观察区与日志检查敏感值没有泄漏。完成后自动退出;需要桌面会话及所选保护设施。省略路径时使用新的临时目录,也可在 --verify 后传入一个尚不存在的 .json、.yaml、.toml 或 .ini 路径:
dotnet run --project samples/ConfioSample/ConfioSample.csproj -c Release -- --verify
./artifacts/sample-aot/ConfioSample.exe --verify --aes
成功返回 0,在初始配置路径旁生成 .verification.txt 和默认值、引导关键步骤、完整模型、读写、集合、子对象、边界失败、明文自动保护前后、Save / Update 对照、容器、源码、日志及较小窗口的 PNG 截图;失败返回非零退出码。最小窗口检查引导展开与收起时编辑区及观察区的可用高度,内容较多时可独立滚动。UI 入口用于理解和验证消费体验,运行库的并发、保护认证失败及其他复杂边界仍由行为测试、格式与操作顺序测试、保护测试、明文保护测试、原生接入测试和真实消费者验收。桌面运行当前仅在 Windows x64 验证,运行库平台证据单独维护。
构建与验证
本仓库使用 .NET 10 SDK 构建。运行库与模型类库面向 net462;net8.0;net10.0,真实消费者逐一以表中六个 Framework 目标及 .NET 8 / 9 / 10 验证资产选择与行为,Avalonia Sample 保持 .NET 10。生成器的 netstandard2.0 只服务编译器加载,不交付 Standard 运行库。完整矩阵需安装相应运行时和 Framework targeting pack;本机 Framework 完整矩阵在 Windows x64、Framework 4.8.1 宿主通过。用户回传日志确认 Windows 7 SP1 x64 下原始 Framework 4.6.2、4.7、4.7.1、4.7.2 和 4.8 的完整消费者通过,各版本回传密文均通过现代 .NET / AOT 反向读取验证,实际 Release 及密文互读证据见设计第 8.1 节。
Framework 使用 SDK 风格项目、PackageReference 和 C# 12。SDK 自动处理 .NET Standard 依赖所需的兼容程序集与绑定重定向,包传递 record/init 所需的编译期辅助类型,应用无需手写兼容源码。.NET Framework 4.6 / 4.6.1 及 .NET 5 / 6 / 7 不在当前范围:现有依赖的支持下限为 Framework 4.6.2 和现代 .NET 8,不通过压制目标框架警告扩大承诺。
完整行为测试包含 Windows DPAPI 场景,在 Windows x64 运行;独立保护测试可跨平台运行。现代 .NET 完整消费者使用当前系统的默认保护,Linux 上需准备可访问的 Secret Service;指定密钥的消费者不依赖桌面密钥设施:
dotnet run --project tests/ConfioConsumer/ConfioConsumer.csproj -c Release -f net10.0 -- encryption
dotnet test tests/ConfioTests/ConfioTests.csproj -c Release --filter FullyQualifiedName~ProtectionTests
dotnet build Confio.sln -c Release
dotnet test tests/ConfioTests/ConfioTests.csproj -c Release --no-build
dotnet run --project tests/ConfioConsumer/ConfioConsumer.csproj -c Release -f net462 --no-build
dotnet run --project tests/ConfioConsumer/ConfioConsumer.csproj -c Release -f net8.0 --no-build
dotnet run --project tests/ConfioConsumer/ConfioConsumer.csproj -c Release -f net9.0 --no-build
dotnet run --project tests/ConfioConsumer/ConfioConsumer.csproj -c Release -f net10.0 --no-build
候选包验收脚本建立独立 feed、缓存和仅消费候选包的工程,检查三个运行库资产与依赖组、九种应用目标的资产选择、跨项目模型及生成器交付。消费路径覆盖四种格式、同步异步读写、校验、record/init 默认值与更新、通知、DI / Configuration / Options / Host、保护与多进程协调;还验证 Framework 与现代 .NET 双向读取同密钥 AES 密文。加上 -NativeAot 后发布并运行 .NET 8 / 9 / 10 的 Windows x64 Native AOT,需要安装 Visual Studio C++ 桌面工具和 Windows SDK:
./eng/Verify-Package.ps1 -NativeAot
指定 -Source 时验证该源中与 Directory.Build.props 版本一致的现有包,不重新打包。脚本仍使用独立缓存和包源映射,并检查实际下载来源;源可以是本地目录或 NuGet 服务地址:
./eng/Verify-Package.ps1 -Source https://baget.pluscode.cn/v3/index.json -NativeAot
源码消费者也可以单独发布;该验证项目在现代目标指定 RID 时启用 Native AOT:
dotnet publish tests/ConfioConsumer/ConfioConsumer.csproj -c Release -f net10.0 -r win-x64 -o artifacts/aot/net10.0
./artifacts/aot/net10.0/ConfioConsumer.exe
消费者和测试默认使用隔离临时目录,失败返回非零退出码。候选包验收在本次产物目录下执行文件读写,以覆盖工作区所在文件系统;候选包与发布结果位于 artifacts/,不提交 Git。Framework 的禁止反射开关由测试程序的 App.config 设置,现代 .NET 使用运行时配置;应用无需设置这些验收开关。矩阵之外的运行时按明确需求再扩展,平台证据见验收状态。
真实消费者可以在指定文件系统上验收,始终在给定根目录下新建独立子目录,结束时只清理本次子目录。该入口同时验证四种格式的同步异步保存和多进程更新,并在 JSON / YAML 路径验证连续替换、中文与保护值、已有读取句柄:
dotnet run --project tests/ConfioConsumer/ConfioConsumer.csproj -c Release -f net10.0 -- --directory ./artifacts/file-verification
Native AOT 消费者支持同样的 --directory 参数。文件提交对 Windows 短暂占用做有上限的等待,持续失败仍报告错误;重试与取消边界见文件提交契约。
发布预览包
版本由 Directory.Build.props 维护。上传已经验收的同一份 .nupkg,已发布版本不覆盖;下次修改使用新版本。发布密钥从 BAGET_API_KEY 环境变量读取,不写入仓库或 NuGet.Config。
dotnet pack src/Confio/Confio.csproj -c Release -o ./artifacts/packages
./eng/Verify-Package.ps1 -Source ./artifacts/packages -NativeAot
dotnet nuget push ./artifacts/packages/Confio.0.1.0-preview.1.nupkg --source https://baget.pluscode.cn/v3/index.json --api-key $env:BAGET_API_KEY --no-symbols
发布后使用上面的远端包验证命令确认实际安装与消费结果。当前仅通过 BaGet 分发预览版;nuget.org 的包名归属和公开许可证在对外发布前确定。
文档入口
| 文档 | 内容 |
|---|---|
| 设计方案 | 产品契约、技术取舍、目标矩阵、消费方式与验收状态 |
| 开发规范 | 工程、命名与 API、数据安全、生成器、AOT 和交付规则 |
| AGENTS.md | 项目边界、工作入口与协作约束 |
.NET 10.0
- Microsoft.Extensions.Configuration.Ini (>= 10.0.12)
- YamlDotNet (>= 18.1.0)
- Tomlyn (>= 2.10.1)
- System.Security.Cryptography.ProtectedData (>= 10.0.12)
- Microsoft.Extensions.Hosting (>= 10.0.12)
.NET 8.0
- YamlDotNet (>= 18.1.0)
- Tomlyn (>= 2.10.1)
- System.Threading.AccessControl (>= 10.0.12)
- System.Text.Json (>= 10.0.12)
- System.Security.Cryptography.ProtectedData (>= 10.0.12)
- Microsoft.Extensions.Hosting (>= 10.0.12)
- Microsoft.Extensions.Configuration.Ini (>= 10.0.12)
.NET Framework 4.6.2
- YamlDotNet (>= 18.1.0)
- System.Text.Json (>= 10.0.12)
- Tomlyn (>= 2.10.1)
- PolySharp (>= 1.16.0)
- Microsoft.Extensions.Hosting (>= 10.0.12)
- Microsoft.Extensions.Configuration.Ini (>= 10.0.12)
- Microsoft.Bcl.Cryptography (>= 10.0.12)
- System.Security.Cryptography.ProtectedData (>= 10.0.12)
| Version | Downloads | Last updated |
|---|---|---|
| 2.0.0 | 4 | 09/24/2026 |
| 1.1.0 | 2 | 09/18/2026 |
| 1.0.0 | 2 | 09/18/2026 |
| 0.1.0-preview.3 | 3 | 09/17/2026 |
| 0.1.0-preview.2 | 2 | 09/17/2026 |
| 0.1.0-preview.1 | 4 | 09/17/2026 |