C# SDK 概述
开发 AI 推理应用的 .NET 类库。P/Invoke 薄封装,零密码学;唯一契约为 Core/include/darra_ai.h。
本文档对应 C# SDK v1.0.0(与 darra_ai.h 的 DARRA_VERSION_* 对齐)。运行时版本通过 AiRuntime.VersionString 查询,形如 "1.0.0+runtime" / "1.0.0+authoring"。加载后静态构造核对 darra_version major == 1,不等立即失败。
安装
- NuGet 包管理器
- 直接引用 DLL
Install-Package Darra.AI.Runtime
或使用 .NET CLI:
dotnet add package Darra.AI.Runtime
程序集 / PackageId = Darra.AI.Runtime(工程名 Darra.AI.Studio.Runtime,过仓根前缀门槛)。Studio 是本包的消费方,不是宿主目录。
客户交付包必须带 runtimes/win-x64/native/darraai_core.dll。缺 native 的纯托管包只能编译引用,不能推理;运行时报 AiLoadException,不影响编译 / pack。本包不内嵌、不伪造 native dll。
如果不使用 NuGet,可以直接引用编译好的 DLL:
- 从 下载页面 或官方输出
bin/AI SDK/{Debug|Release}/获取Darra.AI.Runtime.dll和Darra.AI.Runtime.xml - 在项目中添加引用:
<Reference Include="Darra.AI.Runtime">
<HintPath>lib\Darra.AI.Runtime.dll</HintPath>
</Reference>
- 将 native 库放到进程搜索路径,或设置环境变量
DARRA_AI_CORE_PATH指向库文件或其所在目录。native 库名darraai_core(Windows 亦可加载DarraAI.Core.dll;Linux 为darraai_core.so/libdarraai_core.so)
将 Darra.AI.Runtime.xml 与 DLL 放在同一目录,即可获得完整的 IntelliSense 方法提示和注释。
环境要求
- 操作系统: Windows x64;Linux x86_64 / ARM64。macOS 不在 v1;只交付 x64 / ARM64
- 运行时: .NET 8.0
- native:
darraai_core(缺库时报AiLoadException) - 驱动 / OS 级依赖: SDK 不代装(NVIDIA 驱动过旧、RK3588 板镜像缺 NPU 驱动只诊断不代劳)。Windows 上指名
edge-rknn由 Core 返回UNSUPPORTED_PLATFORM
快速开始
- 用 AI Studio 导出加密容器
.darmodel与授权.darmkey - 客户机安装
Darra.AI.Runtime(须带 native) - 代码中
AiSession.Open→InferImage
using Darra.AI.Runtime;
// 静态构造已核 ABI。基础检测:推荐哪套包、装了没有(不联网)。
AiEnvCheck env = AiEnvironment.Check();
Console.Error.WriteLine(env.Message);
if (!env.Ready)
{
AiEnvironment.EnsureReady((percent, stage) =>
Console.Write($"\r环境准备 [{stage,-8}] {percent,5:0.0}% "));
Console.WriteLine();
}
using var session = AiSession.Open("model.darmodel", keyPath: "model.darmkey");
Console.WriteLine("[meta] " + session.MetaJson());
byte[] photo = File.ReadAllBytes("photo.jpg");
string results = session.InferImage(photo, ImageDesc.Auto());
Console.WriteLine("[results] " + results);
失败时捕获对应子类,Hint 即 error-catalog 给最终用户的修复建议:
try { /* Open / InferImage */ }
catch (AiException ex)
{
Console.Error.WriteLine(ex.Message); // 含 [码] 描述 | 建议: hint
}
备选方式: 明文 ONNX 试跑
Studio 试跑 / 客户自有无需加密模型,走同一推理路径,只跳过容器解码与验票:
using Darra.AI.Runtime;
AiRuntime.Ensure("cpu-only");
using var session = AiSession.OpenPlain("model.onnx");
byte[] jpg = File.ReadAllBytes("photo.jpg");
string json = session.InferImage(jpg, ImageDesc.Encoded());
Console.WriteLine(json);
训练格式(.pt / .pth / Paddle)不是运行时载荷,会抛 AiUnsupportedPayloadException。
- 加密容器 — 生产环境,
.darmodel+.darmkey(或密码),推荐。 - 明文 ONNX — Studio 试跑 / 客户自有未加密模型。
工业相机裸缓冲 BGR888 + 取消安装
using Darra.AI.Runtime;
// UI「取消」从 UI 线程调;不要在 progress 回调里调 Cancel。
CancellationToken token = /* UI token */;
token.Register(AiRuntime.Cancel);
try
{
AiRuntime.Ensure("nvidia-gpu", progress: (p, s) => Console.WriteLine($"{s} {p:0}%"));
}
catch (AiCancelledException)
{
// 半成品已清理,需要时重新 Ensure 即可
return;
}
using var session = AiSession.Open("model.darmodel", password: Environment.GetEnvironmentVariable("DARRA_MODEL_PASSWORD"));
// frame = 相机一帧,1920x1080 BGR 紧凑
byte[] frame = GrabBgrFrame(); // 调用方自己的采集
var desc = ImageDesc.Bgr888(width: 1920, height: 1080, stride: 0);
string results = session.InferImage(frame, desc);
Console.WriteLine(results);
裸缓冲禁止 ImageDesc.Auto()(嗅探不出通道序)。stride = 0 表示紧凑排列(= width × 3)。
keyPath 与 password 至少给一个;都给则 key 文件优先验票。preferProvider 指名但不可用 = fail-closed,绝不静默降级。
高级 API
| 功能 | 说明 |
|---|---|
环境检测 (AiEnvironment.Check) | 不联网:推荐哪套 Provider、装了没有 |
自动安装 (AiRuntime.Ensure / AiEnvironment.EnsureReady) | 没装就探测→选包→下载→校验→解压登记;幂等 |
取消安装 (AiRuntime.Cancel) | 任意线程可调;进度回调内禁止 |
诊断 (AiDiagnostics.Collect) | 本机环境 JSON(去敏);耗时可到数百毫秒,禁止放进 PLC 扫描周期 |
会话选项 (OpenEx / OpenPlainEx) | 线程数 / CPU 亲和;禁止改 Windows ReservedCpuSets、禁止动 PLC 隔离核 |
| authoring | 仅 authoring 构建导出;runtime 缺符号时抛 AiAuthoringUnavailableException |
AiRuntime.Ensure("cpu-only");
string diag = AiDiagnostics.Collect();
using var session = AiSession.OpenEx(
"model.darmodel",
keyPath: "model.darmkey",
options: new SessionOptions { IntraOpThreads = 2, InterOpThreads = 1 });
进度回调(AiRuntime.Ensure)在 SDK 工作线程触发,回调内禁止调用任何 Darra AI API(含 Cancel)。回调抛出的异常会被吞掉,避免穿过 native 边界。
API 总览
| 类别 | 属性 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| AiSession 打开 | Open | AiSession | 静态 | 打开加密容器(.darmodel,DARM1)。keyPath 与 password 至少给一个;都给则 key 文件优先验票。preferProvider 指名但不可用 = fail-closed |
OpenPlain | AiSession | 静态 | 打开明文 .onnx 建会话。与 Open 同一推理路径,只跳过容器解码与验票 | |
OpenEx | AiSession | 静态 | 打开加密容器并传入 SessionOptions(线程数 / CPU 亲和)。options 为 null = 等同 Open。native 缺符号时抛 AiLoadException | |
OpenPlainEx | AiSession | 静态 | 打开明文 .onnx 并传入 SessionOptions。options 为 null = 等同 OpenPlain | |
| AiSession 元信息 | MetaJson | string | 方法 | 会话元信息 JSON。首次向 native 取一次并缓存;无需调用方释放 |
Task | string | 只读 | 任务短名(detect / classify / segment / pose / ocr / anomaly)。缺席为空串 | |
Labels | IReadOnlyList<string> | 只读 | 类别标签。缺席为空列表,永不 null | |
InputWidth | uint | 只读 | 模型输入宽。0 = 容器头未写 / 未知 | |
InputHeight | uint | 只读 | 模型输入高。0 = 容器头未写 / 未知 | |
InputChannels | uint | 只读 | 模型输入通道。0 = 容器头未写 / 未知 | |
Layout | string | 只读 | 张量布局(NCHW / NHWC)。缺席为空串 | |
PayloadKind | string | 只读 | 载荷类型(onnx / trt-engine / openvino / rknn)。缺席为空串 | |
ProviderId | string | 只读 | 实际选中的 Provider(不是 prefer 入参)。缺席为空串 | |
Encrypted | bool | 只读 | 是否加密容器会话。明文 ONNX 为 false | |
| AiSession 推理 | InferImage | string | 方法 | 对一张图片跑推理,结果 JSON。重载:byte[] / ReadOnlySpan<byte>。阻塞调用,不承诺硬实时。同一会话可并发;Dispose 禁止与在飞调用并发 |
Dispose | void | 方法 | 关闭会话并释放全部资源(含解密明文窗口清零)。重复 Dispose 安全。实现 IDisposable | |
| AiRuntime | ExpectedMajor | int | 常量 | 头文件 DARRA_VERSION_MAJOR。静态构造已核对此值(1) |
VersionPacked | uint | 只读 | 打包版本 (major<<16)|(minor<<8)|patch | |
VersionString | string | 只读 | 形如 "1.0.0+runtime" / "1.0.0+authoring" 的静态字符串。禁止释放 | |
Ensure | void | 静态 | 确保 Provider / profile 已装好。细包:onnx-cpu / onnx-cuda / onnx-openvino / onnx-trt-ep / trt-native / edge-rknn;场景包:cpu-only / nvidia-gpu / intel-iap / amd-dml / board-rk3588;null = 按硬件探测自动选。offlineZip 非空 = 离线安装。幂等 | |
Cancel | void | 静态 | 请求取消当前在飞的 Ensure。可从任意线程调(含 UI 线程);进度回调内部禁止。没有在飞的 Ensure 时为 no-op | |
| ImageDesc | Format | ImageFormat | 只读 | 图像输入格式。Auto/Encoded 时 Width/Height/Stride 忽略(填 0) |
Width | uint | 只读 | 裸缓冲宽。Rgb888/Bgr888 时必填(>0) | |
Height | uint | 只读 | 裸缓冲高。Rgb888/Bgr888 时必填(>0) | |
Stride | uint | 只读 | 每行字节数。0 = 紧凑排列(= Width×3) | |
Auto | ImageDesc | 静态 | 编码字节流,按魔数自嗅探(JPG/PNG/BMP)。裸缓冲禁止用 Auto | |
Encoded | ImageDesc | 静态 | 显式编码字节流(JPG/PNG/BMP);v1 行为同 Auto | |
Rgb888 | ImageDesc | 静态 | 裸 RGB888。stride=0 表示紧凑 | |
Bgr888 | ImageDesc | 静态 | 裸 BGR888(工业相机常见)。stride=0 表示紧凑 | |
| 异常 | AiException.Code | int? | 只读 | darra_error_code 整数值;绑定侧加载/ABI/authoring 缺符号为 null |
AiException.Hint | string | 只读 | 修复建议(error-catalog 标准文案,可为空串),可原样展示给最终用户 | |
AiLoadException | AiException | 抛出 | native 内核加载失败或 ABI 不匹配。Code 恒为 null | |
AiAuthoringUnavailableException | AiException | 抛出 | runtime 构建没有 authoring 符号。文案固定:「当前 SDK 为 runtime 构建,不含加密/签发能力」 | |
AiIoNotFoundException | AiException | 抛出 | DARRA_IO_NOT_FOUND (1):文件不存在(容器/授权/图片/离线包路径错) | |
AiIoDeniedException | AiException | 抛出 | DARRA_IO_DENIED (2):文件存在但读/写被拒 | |
AiBadContainerException | AiException | 抛出 | DARRA_BAD_CONTAINER (3):.darmodel 损坏 / 非 DARM1 / 被截断篡改 | |
AiBadLicenseException | AiException | 抛出 | DARRA_BAD_LICENSE (4):.darmkey 损坏或与容器不配对 | |
AiPasswordRequiredException | AiException | 抛出 | DARRA_PASSWORD_REQUIRED (5):该容器需要密码但调用方没给 | |
AiPasswordWrongException | AiException | 抛出 | DARRA_PASSWORD_WRONG (6):密码错误 | |
AiMachineMismatchException | AiException | 抛出 | DARRA_MACHINE_MISMATCH (7):绑机授权在非目标机器上使用 | |
AiTrialExhaustedException | AiException | 抛出 | DARRA_TRIAL_EXHAUSTED (8):试用计次已用完 | |
AiUnsupportedPayloadException | AiException | 抛出 | DARRA_UNSUPPORTED_PAYLOAD (9):载荷类型在当前平台/Provider 下不支持 | |
AiUnsupportedPlatformException | AiException | 抛出 | DARRA_UNSUPPORTED_PLATFORM (10):整个 OS/架构不在支持矩阵 | |
AiProviderMissingException | AiException | 抛出 | DARRA_PROVIDER_MISSING (11):需要的运行时 Provider 包未安装 | |
AiProviderAbiMismatchException | AiException | 抛出 | DARRA_PROVIDER_ABI_MISMATCH (12):Provider 包与内核 ABI 不匹配 | |
AiHardwareMissingException | AiException | 抛出 | DARRA_HARDWARE_MISSING (13):未探测到所需硬件 | |
AiDriverTooOldException | AiException | 抛出 | DARRA_DRIVER_TOO_OLD (14):驱动版本低于 Provider 包要求(SDK 不代装) | |
AiNetworkFailedException | AiException | 抛出 | DARRA_NETWORK_FAILED (15):清单 / 运行时包下载失败 | |
AiChecksumMismatchException | AiException | 抛出 | DARRA_CHECKSUM_MISMATCH (16):下载包或离线包 sha256 校验不过 | |
AiCancelledException | AiException | 抛出 | DARRA_CANCELLED (17):操作被取消(AiRuntime.Cancel) | |
AiInternalException | AiException | 抛出 | DARRA_INTERNAL (18):SDK 内部错误;也用于调用方参数契约违反。未知新码兜底为 AiException 基类,Code 原样保留 |
ImageFormat 枚举值
public enum ImageFormat
{
Auto = 0, // 按字节魔数自嗅探编码格式(JPG/PNG/BMP)。裸缓冲禁止用 Auto
Encoded = 1, // 显式声明为已编码字节流(JPG/PNG/BMP);v1 行为同 Auto
Rgb888 = 2, // 裸缓冲,RGB 三通道 8bit,须给宽高
Bgr888 = 3, // 裸缓冲,BGR 三通道 8bit,须给宽高
}
AiErrorCode 枚举值
public enum AiErrorCode
{
Ok = 0,
IoNotFound = 1,
IoDenied = 2,
BadContainer = 3,
BadLicense = 4,
PasswordRequired = 5,
PasswordWrong = 6,
MachineMismatch = 7,
TrialExhausted = 8,
UnsupportedPayload = 9,
UnsupportedPlatform = 10,
ProviderMissing = 11,
ProviderAbiMismatch = 12,
HardwareMissing = 13,
DriverTooOld = 14,
NetworkFailed = 15,
ChecksumMismatch = 16,
Cancelled = 17,
Internal = 18,
}
ABI 核对
加载 native 时静态构造核对 darra_version major 必须等于 AiRuntime.ExpectedMajor(1)。库找不到或位数不匹配抛 AiLoadException;major 不等亦抛 AiLoadException,禁止继续调用。
AiRuntime.Ensure 启动时:已装且匹配 → 直接成功(回调收到一次 "done", 100)。进程内串行;取消或失败不留半成品。
错误处理
失败时 ThrowIfError 取本线程 darra_last_error,再抛对应子类。Message 格式为 [码] 描述 | 建议: hint。Hint 原文透传,不改写。
string ver = AiRuntime.VersionString; // "1.0.0+runtime" / "1.0.0+authoring"
uint packed = AiRuntime.VersionPacked; // (major<<16)|(minor<<8)|patch
try
{
using var session = AiSession.Open("model.darmodel", keyPath: "model.darmkey");
}
catch (AiException ex)
{
Console.Error.WriteLine(ex.Message);
Console.Error.WriteLine(ex.Hint);
}
版本兼容
当前 C# SDK v1.0.0。绑定与 DarraAI.Core 必须同一发布批次;major 变 = ABI 破坏,须成套升级。OpenEx / OpenPlainEx 在旧 native 上缺符号时抛 AiLoadException(提示升到同一批次)。
authoring(Authoring.EncryptOnnx / IssueKey / FingerprintPerturb)仅 authoring 构建导出;本 NuGet 面向客户机 runtime,缺符号时抛 AiAuthoringUnavailableException:「当前 SDK 为 runtime 构建,不含加密/签发能力」。调用顺序:扰动 → 加密 → 签发。