OpenRobot.Edge.AppSdk 0.1.0

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

OpenRobot.Edge.AppSdk

边缘应用接入 SDK:连接 EdgeWebApi、自动注册、配置声明与热更新、状态上报、业务数据写入。

应用只写业务逻辑,配置界面、数据存储、状态展示、控制面板交给平台。

快速开始

var builder = ModuleHostBuilder.Create(args);
builder.Services.AddLogging();
builder.Services.AddEdgeApp(o =>
{
    o.AppId = "EdgeCDS";                    // = IPC ClientId = 平台侧身份,只配这一处
    o.DisplayName = "边缘数据服务";
    o.Version = "26.10.09.1";
    o.Ipc.Transport = IpcTransportKind.NamedPipe;

    o.Variables.Add(new AppVariableDeclarationEntry
    {
        Key = "apps.EdgeCDS.collect.interval",
        Title = "采集周期",
        Type = AppVariableTypes.Int,
        Default = 1000,
        Min = 100,
        Max = 60000,
        Editable = true,
    });

    o.Collections.Add(new AppCollectionDeclaration
    {
        Name = "alarms",
        Mode = AppCollectionModes.Log,
        TtlSeconds = 30 * 24 * 3600,
        Indexed = ["$.level"],
    });
});

// 让宿主替我们管连接生命周期:PostInitialize 连、Shutdown 断
builder.AddModule<EdgeAppModule>();
await using var host = builder.Build();
await host.RunAsync();

AddEdgeApp 只注册、不连接,与 Communication 库同一约定。连接由宿主发起,两种接法去下面挑一种。

选择宿主接法

一、Modularity(推荐)

[DependsOn(typeof(EdgeAppModule))]     // 声明依赖,保证拓扑排序里排在 SDK 之后
public sealed class EdgeCdsModule : StartupModule
{
    private readonly EdgeAppClient _edge;

    public EdgeCdsModule(EdgeAppClient edge) => _edge = edge;

    public override void PostInitialize()
    {
        // 注册回调要在连接之前 —— 重连后平台可能立刻补发,晚注册就漏了第一条
        _edge.ConfigChanged = OnConfigChanged;
    }

    private Task OnConfigChanged(AppConfigChangedPayload payload)
    {
        // SDK 已经在回调之前把新值刷进缓存了,这里直接读就是新值。
        // payload.ChangedKeys 告诉你是哪些键变了(null = 整份重载),可用来做增量应用。
        var interval = _edge.Config.Get<int>("apps.EdgeCDS.collect.interval");
        RestartCollector(interval);
        return Task.CompletedTask;
    }
}

EdgeAppModule 在 PostInitialize 发起连接、在 WaitReadyAsync 最多等 5 秒。 连不上不算启动失败:超时只记一条 Warning,应用按离线模式继续跑,后台会持续重连。

二、Generic Host

services.AddEdgeApp(...);

public sealed class EdgeAppHostedService : IHostedService
{
    private readonly EdgeAppRunner _runner;
    public EdgeAppHostedService(EdgeAppRunner runner) => _runner = runner;

    public Task StartAsync(CancellationToken ct) => _runner.StartAsync(ct);
    public Task StopAsync(CancellationToken ct) => _runner.StopAsync();
}

需要知道「到底连上没有」时用 _runner.WaitForConnectedAsync(TimeSpan);它超时返回 false 而不是抛异常。

业务代码

注入 EdgeAppClient:

await edge.ReportStateAsync(new { running = true, throughput = 128 });
await edge.UpsertAsync("devices", "dev-01", device);
await edge.AppendAsync("alarms", new { level = "error", code = "E1024" });

// 注册控制点(在 PostInitialize 里做,别等指令到了再注册)
edge.OnControl("restartCollector", async (cmd, ct) =>
{
    if (_collector.IsBusy) return new AppControlResultPayload { Ok = false, Message = "正在采集中,稍后再试" };

    await _collector.RestartAsync(ct);
    return new AppControlResultPayload { Ok = true, Message = "已重启" };
});

控制点要先在 EdgeAppOptions.Controls 里声明(界面才有按钮), 再在运行时用 OnControl 挂执行器 —— 声明说「有什么按钮」,执行器说「按下去做什么」。 执行器自己判断能不能做:声明不是许可。

方法 用途 失败行为
ReportStateAsync(state, controls) 状态上报,建议 2–5 秒一次 只记日志
UpsertAsync(collection, key, payload) 按唯一键写入 只记日志
AppendAsync(collection, payload) 追加一条(键由平台生成) 只记日志
WriteAsync(collection, records) 批量写入 只记日志
GetConfigAsync() 拉一次生效配置并刷新 Config 返回 null,保留旧缓存
RegisterAsync() / DeclareVariablesAsync() 手动重发声明 抛给调用方

读配置是同步的,走本地缓存:

int interval = edge.Config.Get<int>("apps.EdgeCDS.collect.interval");
if (edge.Config.TryGet<string>("apps.EdgeCDS.mode", out var mode)) { ... }

缓存由 SDK 自动维护:连上时拉一次,收到 app.config.changed 时先刷新再回调。 读不到(键不存在 / 类型对不上)返回 default 而不是抛 —— 配置读取散落在业务各处, 为一个漏写的键打断采集循环不值得。

失败不阻断业务:这条链路是管理面旁路,发送失败只记日志。唯一的硬失败是构造期 AppId 为空、以及往未声明的集合里写数据 —— 这两件事写下去只会变成孤儿数据,早抛比晚查好。

协议

topic 常量见 EdgeAppProtocol。前缀固定 app.,点分、无版本前缀、不带应用名 —— IPC 信封的 target 负责寻址,路由器按 topic 精确匹配且没有通配符。

方向 topic 载荷类型
应用 → 平台 app.register AppRegisterPayload
应用 → 平台 app.vars.declare AppVariableDeclarationPayload
应用 → 平台 app.state AppStatePayload
应用 → 平台 app.data AppDataPayload
应用 → 平台(请求-响应) app.config.get AppConfigRequestPayload → AppConfigSnapshotPayload
平台 → 应用 app.config.changed AppConfigChangedPayload
平台 → 应用(请求-响应) app.control.invoke AppControlInvokePayload → AppControlResultPayload

注册与声明在每次连上时自动重发(AutoRegisterOnConnect,默认开),应用不必自己订阅连接事件。 声明内容会算 SHA-256 摘要,平台据此判断「没变就不重复落盘」,所以重复发送是安全的。

当前范围

已实现:注册、变量声明、状态上报、业务数据写入(IPC)、配置变更订阅、 配置读取(app.config.get + 本地缓存)、控制点声明与执行(app.control.invoke)。

后续:配置写入(SetAsync / ApplyAsync,需平台侧校验与审计)、树形 schema(object / array)、 HTTP 数据通道、本地开发模式。

平台侧已接入 app.register(应用台账:注册信息落库 + 在线 / pm2 进程状态) 与 app.config.get;控制点的平台侧(下发入口、界面按钮)尚未接入 —— 协议与应用侧都就绪,RequestToAsync 一接就能用。

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 was computed.  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
0.1.0 37 10/29/2026