WSL C# SDK 镜像推送:PushImageOptions 完整配置指南
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
本文围绕 WSL(Windows Subsystem for Linux)容器 SDK(WSLC)C# 投影中的PushImageOptions配置类展开,讲解如何将 WSL 容器会话内的镜像推送至远程镜像仓库,涵盖参数语义、底层调用链、错误处理与异步进度用法。读完本文,你将掌握 WSL C# SDK 中PushImageOptions的完整配置与实战调用方式,并理解其与底层 C/WinRT 实现的对应关系。
一、概述:PushImageOptions 是什么
PushImageOptions是 WSL 容器 SDK 中用于配置"镜像推送(Push)"操作的参数对象。在 WSL 容器工作流中,开发者通常先在本地构造、拉取或导入镜像,随后需要将其推送到 Docker Registry 等远程仓库以便分发或备份,此时即可使用Session.PushImage/Session.PushImageAsync配合PushImageOptions完成。
该类的定位与PullImageOptions、TagImageOptions同属 SDK 的"设置类(Settings Classes)"一族,相关的类索引见 doc/docs/api-reference/csharp/settings-classes/index.md。
类定义与构造
根据 doc/docs/api-reference/csharp/settings-classes/pushimageoptions.md,该类在 C# 投影中的定义为:
public sealed class PushImageOptions { public PushImageOptions(string image, string registryAuth); public string Image { get; set; } public string RegistryAuth { get; set; } }要点:
- 构造时需同时提供
image与registryAuth两个参数; Image与RegistryAuth均提供可读写的属性;- 类是
sealed(密封)的,不可被继承,表明其作为纯数据承载对象使用。
与底层 API 的对应关系
PushImageOptions并非凭空设计,它在 SDK 各语言层有一一对应的实现:
- C# 层(本文主角):
src/windows/WslcSDK/csharp/下的投影类,作为 WinRT 投影暴露给 C# 开发者; - WinRT 层:
src/windows/WslcSDK/winrt/PushImageOptions.h与 PushImageOptions.cpp 中的winrt::Microsoft::WSL::Containers::implementation::PushImageOptions; - MIDL 定义:
src/windows/WslcSDK/winrt/wslcsdk.idl中的runtimeclass PushImageOptions,它是 WinRT 投影的契约来源:runtimeclass PushImageOptions { PushImageOptions(String image, String registryAuth); String Image; String RegistryAuth; }; - C API 层:
WslcPushImageOptions结构体,定义见 doc/docs/api-reference/c/structures/wslcpushimageoptions.md,结构体比 C# 类多出progressCallback与progressCallbackContext两个用于进度回调的字段。
二、字段详解
2.1 Image(镜像引用)
Image指定要推送的镜像引用。它必须包含完整的仓库地址(registry 主机 + 仓库路径 + 标签),例如:
var pushOptions = new PushImageOptions("registry.example.com/demo:latest", authToken);镜像引用通常形如registry.example.com/demo:latest,其中:
| 片段 | 说明 | 示例 |
|---|---|---|
| registry 主机 | 镜像仓库服务器地址(含端口可省略) | registry.example.com |
| 仓库路径 | 仓库与命名空间 | demo |
| 标签 | 版本标签,缺省一般为latest | latest |
实战提示:推送前通常先用
TagImage将本地镜像打上带 registry 前缀的标签,再执行推送。测试代码 test/windows/WslcSdkWinRTTests.cpp 中正是先TagImage(imageName, registryRepo, tag),再构造带 registry 前缀的PushImageOptions进行推送,并在推送后用DELETE_IMAGE_ON_SCOPE_EXIT清理临时镜像。
2.2 RegistryAuth(注册表认证)
RegistryAuth指定访问私有镜像仓库所需的认证信息。从 C API 注释可知,该字段语义是Base64 编码的X-Registry-AuthHTTP 请求头值(见 doc/docs/api-reference/c/structures/wslcpushimageoptions.md)。也就是说,推送私有仓库镜像时,需要把 Docker 风格的认证令牌(token)或用户名/密码构造为 registry auth 头,再进行 Base64 编码后传入。
SDK 内部在src/windows/WslcSDK/wslcsdk.cpp中提供了BuildRegistryAuthHeader辅助逻辑,用于在认证后生成合法的 registry auth 头字符串,说明该字段承载的是完整的鉴权头载荷,而非裸的用户名密码。
三、构造约束与校验规则
从 PushImageOptions.cpp 的实现可以总结出以下严格的参数校验规则:
3.1 空值校验(E_INVALIDARG)
无论是构造函数还是属性 setter,image与registryAuth都不允许为空字符串:
// 以下均会抛出异常: new PushImageOptions("", authToken); // Image cannot be empty new PushImageOptions("repo/img:tag", ""); // Registry auth cannot be empty对应 WinRT 实现抛出的异常为hresult_invalid_argument(HRESULTE_INVALIDARG),错误信息分别为"Image cannot be empty"与"Registry auth cannot be empty"。测试代码 test/windows/WslcSdkWinRTTests.cpp 中亦有对应验证:
VERIFY_THROWS_HR(m_defaultSession.PushImageAsync(WSLCSDK::PushImageOptions(L"", winrt::to_hstring(xRegistryAuth))).get(), E_INVALIDARG);3.2 应用后锁定(E_ILLEGAL_STATE_CHANGE)
PushImageOptions在把参数转换为底层结构体(ToStruct())之后,属性值即被锁定。若在选项已被应用后再尝试修改Image或RegistryAuth,会抛出hresult_illegal_state_change,错误信息为"Cannot change value after options have been applied"。这保证了在一次推送操作中参数的一致性,避免调用中途静默篡改配置。
因此推荐的最佳实践是:先完整构造并配置好PushImageOptions,再调用Session.PushImage/PushImageAsync,不要在调用后复用并修改同一个选项对象。
四、与 Session 的协作:从选项到推送完成
4.1 底层调用链
PushImageOptions最终通过Session的推送方法发挥作用。以异步版本为例,Session.cpp 中PushImageAsync的实现流程为:
- 空指针检查:
options为 null 时抛出hresult_error(E_POINTER, "Options for push cannot be null"); EnsureStarted():确保 Session 已启动,否则操作无法执行;GetStruct(options):将 WinRT 对象转换为底层WslcPushImageOptions结构体(即触发ToStruct()与应用后锁定);- 挂接
progressCallback与progressCallbackContext(异步版本将进度事件桥接到 WinRT 的IAsyncActionWithProgress<ImageProgress>); - 调用 C API
WslcPushSessionImage(ToHandle(), &pushOptions, errorMessage.put())(见 wslcsdk.cpp),并在失败时抛出携带错误消息的 HRESULT 异常。
同步版本PushImage的流程与此一致,只是不挂接进度回调。C API 的签名定义在 doc/docs/api-reference/c/image-apis/wslcpushsessionimage.md:
STDAPI WslcPushSessionImage(_In_ WslcSession session, _In_ const WslcPushImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);C API 层同样会校验options、options->image、options->registryAuth不为空(空则返回E_INVALIDARG),随后调用内部运行时internalType->session->PushImage(...)。
4.2 同步与异步两种调用方式
// 同步方式:阻塞直到推送完成或抛异常 session.PushImage(pushOptions); // 异步方式:返回带进度的 IAsyncActionWithProgress<ImageProgress> var progress = session.PushImageAsync(pushOptions);异步版本可配合Progress<ImageProgress>接收推送过程中的阶段事件。进度事件类型ImageProgress在wslcsdk.idl中定义,包含Id、Status、CurrentBytes、TotalBytes等字段,可用于展示推送的拉取/下载/校验/解压等阶段状态。
4.3 完整调用示例
综合以上内容,一次完整的镜像推送流程如下:
// 1. 构造推送选项(image 与 registryAuth 均不能为空) var pushOptions = new PushImageOptions("registry.example.com/demo:latest", authToken); // 2. 通过已启动的 Session 执行推送(异步 + 进度) var progress = session.PushImageAsync(pushOptions); progress.Progress = (asyncInfo, imageProgress) => { Console.WriteLine($"Image {imageProgress.Id}: {imageProgress.Status}, " + $"{imageProgress.CurrentBytes}/{imageProgress.TotalBytes} bytes"); }; await progress;五、常见错误与排查
| 场景 | 表现 | 原因与对策 |
|---|---|---|
image或registryAuth为空 | 抛出E_INVALIDARG("Image/Registry auth cannot be empty") | 构造参数不合法,检查是否传入了空字符串 |
| 选项对象为 null 传入 Session | 抛出E_POINTER("Options for push cannot be null") | 未实例化选项,先new PushImageOptions(...) |
| Session 未启动 | 抛出无效状态相关错误 | 先调用Session.Start()再推送 |
| 推送不存在的镜像 | 测试中以E_FAIL捕获(如推送"does-not-exist") | 确认镜像已在会话内存在(先用PullImage/ImportImage/TagImage准备) |
| 修改已应用的选项 | 抛出E_ILLEGAL_STATE_CHANGE | 不要复用已用于推送的选项对象,重新构造新实例 |
| 私有仓库认证失败 | 推送报错 | 确认registryAuth是 Base64 编码的X-Registry-Auth头值 |
依据 test/windows/WslcSdkWinRTTests.cpp 中的相关测试,空镜像参数(
L"")会按E_INVALIDARG捕获,而推送不存在的镜像则按E_FAIL处理,可作为异常语义的参考。
六、小结
PushImageOptions是 WSL 容器 SDK C# 投影中面向"镜像推送"场景的配置对象,核心只有两个字段:Image(目标镜像引用)与RegistryAuth(Base64 编码的 registry 认证头)。使用时需注意三点:两个字段均不可为空;选项在应用(调用Session.PushImage/PushImageAsync)后即锁定;推送前确保 Session 已启动且镜像已在会话中。其实现横跨 MIDL 契约(wslcsdk.idl)、WinRT 包装(PushImageOptions.cpp)与 C API(wslcsdk.cpp),并得到 WinRT 测试(WslcSdkWinRTTests.cpp)的覆盖验证,是理解 WSL 容器镜像分发链路的一个典型切入点。
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考