Purview.Containers.Wsl
1.0.0-prerelease.5
dotnet add package Purview.Containers.Wsl --version 1.0.0-prerelease.5
NuGet\Install-Package Purview.Containers.Wsl -Version 1.0.0-prerelease.5
<PackageReference Include="Purview.Containers.Wsl" Version="1.0.0-prerelease.5" />
<PackageVersion Include="Purview.Containers.Wsl" Version="1.0.0-prerelease.5" />
<PackageReference Include="Purview.Containers.Wsl" />
paket add Purview.Containers.Wsl --version 1.0.0-prerelease.5
#r "nuget: Purview.Containers.Wsl, 1.0.0-prerelease.5"
#:package Purview.Containers.Wsl@1.0.0-prerelease.5
#addin nuget:?package=Purview.Containers.Wsl&version=1.0.0-prerelease.5&prerelease
#tool nuget:?package=Purview.Containers.Wsl&version=1.0.0-prerelease.5&prerelease
Purview.Containers.Wsl
The WSL Containers (WSLC) backend for Purview.Containers.Core:
throwaway Linux containers for .NET integration testing built directly on the Microsoft.WSL.Containers
managed API, with no Docker installation and no wslc.exe/wsl.exe/docker CLI, Docker.DotNet or
Testcontainers dependency.
dotnet add package Purview.Containers.Wsl
Reference this package (or a service module) and containers run on WSLC. The package is
multi-target: a net10.0 build (a portable facade) and a net10.0-windows10.0.19041.0 build (the
implementation). A Windows-targeting project binds the implementation; a net10.0 project binds the
facade, which loads the implementation at run time on a Windows host and reports wsl as unavailable
elsewhere. It registers itself as the wsl backend in the consuming assembly. To also run the same test
code on Docker in Linux CI, reference
Purview.Containers.Docker (or the umbrella
Purview.Containers, which brings both backends).
Running in CI, or on a machine without WSL Containers? With only this package referenced,
wslis reported unavailable and there is no backend to fall back to. AddPurview.Containers.Dockeror use the umbrellaPurview.Containers, andauto(the default) falls through to Docker. Pin instead withPURVIEW_CONTAINERS_BACKEND=wsl|dockerorContainerBackends.Use(...)— see Backends: WSLC or Docker.
Requirements
- Windows 10/11 with WSL Containers (
wsl --install --no-distribution), verified against WSL 3.0.1.0. - A .NET 10 project. The recommended target framework is platform-neutral (
net10.0): it binds the facade and gives you automatic WSLC-or-Docker selection. A Windows target framework (net10.0-windows10.0.19041.0, x64 or arm64) binds the implementation directly. Anything older than .NET 10, or a Windows TFM below Windows 10.0.19041.0, fails the build withPCC0001; a 32-bit Windows consumer fails withPCC0002; and without the packages' MSBuild defaults a staleWindowsSdkPackageVersionfails withCS1705. - This package supplies the
buildTransitivedefaults forWindowsSdkPackageVersionandPlatformTargetthat every module package inherits, and (for a platform-neutral consumer on a Windows build host) copies the Windows implementation payload next to the output. The full contract, the error reference and theEnableWindowsTargetingworkaround for non-Windows CI agents are in the consumer requirements. - Verify the host with
wsl --versionandwslc version. The library never installs or updates WSL itself;WslContainerRuntime.GetInfoAsync()reports what is missing. - Experimental: this is an experiment in driving WSL Containers. The public API, defaults and packaging rules can change between prereleases, and there is no production support guarantee.
Quick start
using Purview.Containers.Wsl;
using Purview.Containers.Waiting;
await using var container = new ContainerBuilder()
.WithImage("docker.io/library/redis:latest")
.WithPortBinding(6379, assignRandomHostPort: true)
.WithWaitStrategy(Wait.ForTcpPort(6379))
.Build();
await container.StartAsync();
ushort port = container.GetMappedPublicPort(6379);
Build() snapshots the accumulated builder state into an immutable configuration and validates it, so
invalid images, ports and mounts fail during configuration rather than at pull time.
Builder surface
| Member | Purpose |
|---|---|
WithImage(string), WithImage(Image), WithTag(string) |
Image reference; parsed and validated eagerly (Image.Parse). |
WithName, WithHostname, WithDomainName |
Container identity. Names are generated uniquely when unset. |
WithEnvironment(string, string), WithEnvironment(IReadOnlyDictionary<string, string>) |
Init-process environment. |
WithCommand(params string[]), WithWorkingDirectory |
Init-process argv (no shell) and working directory. |
WithPortBinding(ushort, bool assignRandomHostPort), WithPortBinding(ushort, ushort hostPort, ...), WithPortBinding(PortBinding) |
Host port mappings; random host ports use native windowsPort=0 allocation. |
WithBindMount(string hostPath, string containerPath, bool readOnly = false) |
Bind-mount a Windows directory. |
WithVolumeMount(string name, string containerPath, bool readOnly = false) |
Named volume on the session VHD. |
WithNetworkMode, WithPrivileged, WithGPU, WithAutoRemove, WithPullPolicy, WithStartupTimeout, WithWaitStrategy, WithRegistryCredentials, WithRuntime |
Runtime behaviour and readiness. |
Container API
IContainer (and WslContainer) exposes StartAsync, StopAsync, ExecAsync, GetMappedPublicPort,
GetMappedPublicPorts, GetLogsAsync(LogOutput?) and a tailing IAsyncEnumerable<ContainerLogEntry>
GetLogsAsync(CancellationToken). Id, Name, State and Image describe the running container.
DisposeAsync stops and deletes the container and is idempotent; it never terminates the shared session.
Wait strategies
Wait composes readiness checks that run inside StartAsync:
| Factory | Ready when |
|---|---|
Wait.ForContainerRunning() |
The init process is running (started, not necessarily a ready service). |
Wait.ForTcpPort(port) |
A TCP connection to the mapped host port succeeds. |
Wait.ForHttp(path) |
An HTTP(S) request succeeds; configure ForPort, ForStatusCode, ForHeader, AllowInsecureTls. |
Wait.ForLogMessage(string) / Wait.ForLogMessage(Regex) |
Accumulated init-process output matches. |
Wait.ForCommand(params string[]) |
A command executed in the container exits with the expected code. |
Wait.ForCustom(predicate) |
An arbitrary predicate returns true. |
Wait.ForAll(...) / Wait.ForAny(...) |
All / any contained strategy succeeds. |
Every strategy supports .WithTimeout(...), .WithInterval(...) and .WithRetries(...). The default
timeout is the container's StartupTimeout (5 minutes). Timeouts throw ContainerTimeoutException with
a diagnostic naming the container, image, state, mapped ports, strategy and a bounded, secret-redacted log tail.
Runtime, sessions and storage
WslContainerRuntime.Instance owns a single lazily started, process-wide WSLC session named
wslc-{pid}-{random8}. Images are shared by default (StorageMode.Shared): every session uses
%LOCALAPPDATA%\Purview\WslContainers\images, so images are pulled once and reused across process runs.
A session exclusively locks its storage.vhdx; when a concurrent process holds the default shared store the
runtime verifies the store once and transparently falls back to an isolated per-process store (removed when
that session terminates).
To place the image store somewhere other than the local profile, set the process-wide override
PURVIEW_CONTAINERS_STORAGE_PATH (the pre-rename WSL_CONTAINERS_STORAGE_PATH is still honoured as a
fallback), or configure the backend in code:
ContainerBackends.Use(new WslContainerBackend(WslContainerRuntimeOptions.Default with
{
StoragePath = @"D:\wslc-images",
StorageMode = StorageMode.Shared,
}));
The full WslContainerRuntimeOptions set (CPU, memory, GPU, session name, StoragePath, StorageMode,
timeout) is honoured on both a platform-neutral (net10.0) consumer — where the facade forwards it to the
Windows build at run time — and a Windows target framework, where the Windows build applies it directly.
The Microsoft types (Session, Container, Process, …) stay behind the public interfaces; the only escape
hatch is the opt-in accessor for Inspect() and raw handles.
Diagnostics
System.Diagnostics.ActivitySource("Purview.Containers") emits session, pull, container lifecycle, exec
and wait spans. Credentials and other sensitive values are wrapped in Secret and redacted from ToString()
and diagnostics.
Documentation
See the project wiki:
Getting Started,
Architecture,
Lifecycle,
Networking and
Wait Strategies.
Ready-made service modules ship as Purview.Containers.PostgreSql, Redis, MsSql, RabbitMq,
Azurite, Nats and MySql.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. net10.0-windows10.0.19041 is compatible. |
-
net10.0
- Microsoft.Extensions.Telemetry.Abstractions (>= 10.10.0)
- Purview.Containers.Core (>= 1.0.0-prerelease.5)
-
net10.0-windows10.0.19041
- Microsoft.Extensions.Telemetry.Abstractions (>= 10.10.0)
- Microsoft.WSL.Containers (>= 3.0.1)
- Purview.Containers.Core (>= 1.0.0-prerelease.5)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Purview.Containers.Wsl:
| Package | Downloads |
|---|---|
|
Purview.Containers
Purview.Containers: the umbrella package. Brings the abstractions (Purview.Containers.Core) and both backends (WSL Containers and Docker), so one reference runs the same tests on WSLC on Windows and Docker everywhere else. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-prerelease.5 | 40 | 10/2/2026 |
| 1.0.0-prerelease.4 | 41 | 10/2/2026 |
| 1.0.0-prerelease.3 | 41 | 10/2/2026 |
| 1.0.0-prerelease.2 | 36 | 10/1/2026 |