WSL C# API 深度解析:用 PullImageOptions 从容器镜像仓库拉取镜像
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
本文围绕 WSL(Windows Subsystem for Linux)WSLC(Windows Subsystem for Linux Containers)SDK 的 C# 配置类PullImageOptions展开,说明其两个核心属性Uri与RegistryAuth的用法、底层 C 结构体映射关系,以及Session.PullImage/PullImageAsync的调用链与错误语义。读完后可掌握如何用 C# 从公共或私有镜像仓库拉取容器镜像、处理拉取进度事件,并理解该选项类在 WinRT 层与 C API 之间的转换机制。
类定义与基本用法
PullImageOptions是 C# API 设置类之一,用于描述"从镜像仓库拉取镜像"操作的参数。其完整定义为:
public sealed class PullImageOptions { public PullImageOptions(string uri); public string Uri { get; set; } public string RegistryAuth { get; set; } }最小使用示例(来自 官方文档):
var pullOptions = new PullImageOptions("docker.io/library/alpine:latest") { RegistryAuth = string.Empty // optional for public registries };要点:
- 构造函数的
uri参数是唯一的必选项,指定要拉取的镜像地址,通常包含registry/namespace/image:tag形式(如docker.io/library/alpine:latest,以及本地 registry 的localhost:5000/hello-world:latest); RegistryAuth对公共仓库可省略(置为空字符串即可匿名拉取),拉取私有仓库镜像时必须提供认证凭据。
属性语义:从源码确认的约束
WinRT 实现位于 PullImageOptions.cpp 与 PullImageOptions.h,可从中确认以下行为约束:
Uri不可为空。构造函数和 setter 都会检查:if (uri.empty()) { throw hresult_invalid_argument(L"URI cannot be empty"); }即传入空字符串会抛出
hresult_invalid_argument(C# 中表现为ArgumentException)。选项类是"一次应用后冻结"的。两个属性的 setter 在选项已被 SDK 消费后(内部
m_pullImageOptions已分配)都会拒绝修改:if (m_pullImageOptions) { throw hresult_illegal_state_change(L"Cannot change value after options have been applied"); }这意味着一个
PullImageOptions实例参与拉取操作后不应再被修改复用,如需不同参数应新建实例。RegistryAuth为空串等价于匿名拉取。在转换为 C 结构体时:m_pullImageOptions->registryAuth = m_registryAuth.empty() ? nullptr : m_registryAuth.c_str();空串会被转换为
nullptr,与 C 结构体中registryAuth字段标注的_In_opt_(可选)一致。
底层映射:WinRT 选项类到 WslcPullImageOptions 结构体
C# 层的PullImageOptions最终通过ToStruct()转换为 C API 的结构体 WslcPullImageOptions,定义于 wslcsdk.h:
typedef struct WslcPullImageOptions { _In_z_ PCSTR uri; WslcContainerImageProgressCallback progressCallback; PVOID progressCallbackContext; _In_opt_z_ PCSTR registryAuth; } WslcPullImageOptions; STDAPI WslcPullSessionImage(_In_ WslcSession session, _In_ const WslcPullImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);| C 字段 | 说明 | C# 对应 |
|---|---|---|
uri(_In_z_,必填) | 镜像地址 | Uri属性 |
registryAuth(_In_opt_,可选) | 仓库认证凭据 | RegistryAuth属性 |
progressCallback/progressCallbackContext | 进度回调 | C# 层不直接暴露,见下文PullImageAsync |
注意 WinRT 转换实现中有两处细节(PullImageOptions.cpp):
ToStruct()是惰性且幂等的:首次调用时分配结构体并写入字段,之后重复调用返回同一缓存结构体的引用;- 结构体中的
progressCallback被置为nullptr——C# 用户不通过函数指针接收进度,而是走PullImageAsync的IAsyncActionWithProgress事件通道。
对应的拉取接口在 IDL 中声明(wslcsdk.idl):
void PullImage(PullImageOptions options); Windows.Foundation.IAsyncActionWithProgress<ImageProgress> PullImageAsync(PullImageOptions options);即同步与异步两个入口,PullImageOptions运行时类定义于 wslcsdk.idl:
runtimeclass PullImageOptions { PullImageOptions(String uri); String Uri; String RegistryAuth; };拉取进度:ImageProgress 与 ImageProgressStatus
异步拉取会回调进度事件,进度类型为 ImageProgress,字段为Id(层 ID 或 digest)、Status、CurrentBytes、TotalBytes。Status对应 C 层枚举(wslcsdk.h),与docker pull的常见输出阶段一一对应:
typedef enum WslcImageProgressStatus { WSLC_IMAGE_PROGRESS_STATUS_UNKNOWN = 0, WSLC_IMAGE_PROGRESS_STATUS_PULLING = 1, // "Pulling fs layer" WSLC_IMAGE_PROGRESS_STATUS_WAITING = 2, // "Waiting" WSLC_IMAGE_PROGRESS_STATUS_DOWNLOADING = 3, // "Downloading" WSLC_IMAGE_PROGRESS_STATUS_VERIFYING = 4, // "Verifying Checksum" WSLC_IMAGE_PROGRESS_STATUS_EXTRACTING = 5, // "Extracting" WSLC_IMAGE_PROGRESS_STATUS_COMPLETE = 6 // "Pull complete" } WslcImageProgressStatus;完整实战:创建会话并异步拉取镜像
端到端示例演示了PullImageOptions在完整生命周期中的位置:
// 1. 创建会话(4 CPU / 4 GB 内存) var sessionSettings = new SessionSettings("MyApp", @"C:\WslcData") { CpuCount = 4, MemorySizeInMB = 4096 }; var session = new Session(sessionSettings); session.Start(); // 2. 拉取镜像并输出进度 var pullOp = session.PullImageAsync(new PullImageOptions("docker.io/library/alpine:latest")); pullOp.Progress = (op, progress) => Console.WriteLine($"Pull: {progress.Status} {progress.CurrentBytes}/{progress.TotalBytes}"); await pullOp; // 3. 用拉下来的镜像创建容器 var containerSettings = new ContainerSettings("alpine:latest") { Name = "hello-container", InitProcess = new ProcessSettings { CommandLine = new[] { "/bin/echo", "Hello from WSL Container!" }, OutputMode = ProcessOutputMode.Event } }; var container = session.CreateContainer(containerSettings); container.Start();仓库中的 WSLC-NextCloud 示例则展示了同步版本的简写用法:session.PullImage(new PullImageOptions(imageName))——公共仓库镜像只需提供 URI 一个参数即可完成拉取。
错误语义与私有仓库认证(测试用例佐证)
单元测试 WslcSdkTests.cpp 的PullImage测试方法用真实场景验证了该选项类的边界行为,可据此建立可预期的错误处理:
| 场景 | 结果 |
|---|---|
| 从本地 registry 真实拉取镜像(先删除本地镜像确保是真实拉取) | 成功,HasImage校验通过,且拉取后可直接运行容器(输出 "Hello from Docker!") |
| 拉取 registry 中不存在的镜像 | 返回WSLC_E_IMAGE_NOT_FOUND |
uri为nullptr | 返回E_INVALIDARG |
| 私有 registry 未提供凭据 | WslcPullSessionImage返回E_FAIL并输出错误信息 |
| 提供错误凭据 | 返回E_FAIL |
对于私有仓库,测试用例(WslcSdkTests.cpp)展示了推荐凭据流:先调用WslcSessionAuthenticate换取认证串,其输出可以不做任何转换直接作为registryAuth传入:
VERIFY_SUCCEEDED(WslcSessionAuthenticate( m_defaultSession, registryAddress.c_str(), c_username, c_password, &authToken, nullptr, nullptr)); WslcPullImageOptions opts{}; opts.uri = image.c_str(); opts.registryAuth = authToken.get(); VERIFY_SUCCEEDED(WslcPullSessionImage(m_defaultSession, &opts, nullptr));即 C# 场景下的组合模式为:Session.Authenticate(...)获得认证结果 → 将其赋给PullImageOptions.RegistryAuth→ 调用PullImageAsync。这与 C 层registryAuth标注为_In_opt_且测试注释"output can be passed as registryAuth without any transformation"相吻合。
小结与相关文档
PullImageOptions仅两个属性:Uri(必填、不可为空)与RegistryAuth(可选,空串等价匿名拉取);- 选项类在参与一次拉取应用后应视为冻结,修改属性会抛
hresult_illegal_state_change; - 异步拉取通过
PullImageAsync的IAsyncActionWithProgress<ImageProgress>获得与docker pull一致的阶段化进度(Pulling/Downloading/Verifying/Extracting/Complete); - 错误语义已被单元测试覆盖:镜像不存在返回
WSLC_E_IMAGE_NOT_FOUND,参数非法返回E_INVALIDARG,凭据错误返回E_FAIL。
可继续深入的相关文档:
- C# API 总览 与 Session 核心类
- C API 的 WslcPullImageOptions 结构体 与 WslcPullSessionImage
- PushImageOptions、TagImageOptions(拉取/推送/打标构成镜像管理闭环)
- C++ 端到端示例(对照同构的 C++ 拉取流程)
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考