Installation
dotnet add package Alibaba.OpenSandbox
Install-Package Alibaba.OpenSandbox
Quick Start
using OpenSandbox ;
using OpenSandbox . Config ;
using OpenSandbox . Core ;
var config = new ConnectionConfig ( new ConnectionConfigOptions
{
Domain = "api.opensandbox.io" ,
ApiKey = "your-api-key" ,
// Protocol = ConnectionProtocol.Https,
// RequestTimeoutSeconds = 60,
});
try
{
await using var sandbox = await Sandbox . CreateAsync ( new SandboxCreateOptions
{
ConnectionConfig = config ,
Image = "ubuntu" ,
TimeoutSeconds = 10 * 60 ,
});
var execution = await sandbox . Commands . RunAsync ( "echo 'Hello Sandbox!'" );
Console . WriteLine ( execution . Logs . Stdout . FirstOrDefault () ? . Text );
// Optional but recommended: terminate the remote instance when you are done.
await sandbox . KillAsync ();
}
catch ( SandboxException ex )
{
Console . Error . WriteLine ( $"Sandbox Error: [ { ex . Error . Code } ] { ex . Error . Message } " );
}
Core Features
Lifecycle Management
Manage the sandbox lifecycle, including renewal, pausing, and resuming.
var info = await sandbox . GetInfoAsync ();
Console . WriteLine ( $"State: { info . Status . State } " );
Console . WriteLine ( $"Created: { info . CreatedAt } " );
Console . WriteLine ( $"Expires: { info . ExpiresAt } " );
await sandbox . PauseAsync ();
// Resume returns a fresh, connected Sandbox instance.
var resumed = await sandbox . ResumeAsync ();
// Renew: expiresAt = now + timeoutSeconds
await resumed . RenewAsync ( 30 * 60 );
Connect to an Existing Sandbox
Use ConnectAsync when you already have a sandbox ID and need a new SDK instance bound to it.
var connected = await Sandbox . ConnectAsync ( new SandboxConnectOptions
{
SandboxId = "existing-sandbox-id" ,
ConnectionConfig = config
});
Custom Health Check
Define custom logic to determine whether the sandbox is ready/healthy.
var sandbox = await Sandbox . CreateAsync ( new SandboxCreateOptions
{
ConnectionConfig = config ,
Image = "nginx:latest" ,
HealthCheck = async ( sbx ) =>
{
// Example: consider the sandbox healthy when port 80 endpoint becomes available
var ep = await sbx . GetEndpointAsync ( 80 );
return ! string . IsNullOrEmpty ( ep . EndpointAddress );
},
});
Command Execution & Streaming
Execute commands and handle output streams in real-time.
using OpenSandbox . Models ;
var handlers = new ExecutionHandlers
{
OnStdout = msg => { Console . WriteLine ( $"STDOUT: { msg . Text } " ); return Task . CompletedTask ; },
OnStderr = msg => { Console . Error . WriteLine ( $"STDERR: { msg . Text } " ); return Task . CompletedTask ; },
OnExecutionComplete = c => { Console . WriteLine ( $"Finished in { c . ExecutionTimeMs } ms" ); return Task . CompletedTask ; },
};
await sandbox . Commands . RunAsync (
"for i in 1 2 3; do echo \" Count $i \" ; sleep 0.2; done" ,
handlers : handlers
);
Background Commands
For background commands, you can poll status and incremental logs:
var execution = await sandbox . Commands . RunAsync (
"python /app/server.py" ,
options : new RunCommandOptions
{
Background = true ,
TimeoutSeconds = 120 ,
});
var status = await sandbox . Commands . GetCommandStatusAsync ( execution . Id ! );
var logs = await sandbox . Commands . GetBackgroundCommandLogsAsync ( execution . Id ! , cursor : 0 );
Console . WriteLine ( $"running= { status . Running } , cursor= { logs . Cursor } " );
File Operations
Manage files and directories, including read, write, list/search, and delete.
await sandbox . Files . CreateDirectoriesAsync ( new []
{
new CreateDirectoryEntry { Path = "/tmp/demo" , Mode = 755 }
});
await sandbox . Files . WriteFilesAsync ( new []
{
new WriteEntry { Path = "/tmp/demo/hello.txt" , Data = "Hello World" , Mode = 644 }
});
var content = await sandbox . Files . ReadFileAsync ( "/tmp/demo/hello.txt" );
Console . WriteLine ( $"Content: { content } " );
var files = await sandbox . Files . SearchAsync ( new SearchEntry { Path = "/tmp/demo" , Pattern = "*.txt" });
foreach ( var file in files )
{
Console . WriteLine ( file . Path );
}
await sandbox . Files . DeleteDirectoriesAsync ( new [] { "/tmp/demo" });
// Delete one or more files directly.
await sandbox . Files . DeleteFilesAsync ( new [] { "/tmp/demo/hello.txt" });
Endpoints
GetEndpointAsync() returns an endpoint without a scheme (for example "localhost:44772"). Use GetEndpointUrlAsync() if you want a ready-to-use absolute URL.
var endpoint = await sandbox . GetEndpointAsync ( 44772 );
Console . WriteLine ( endpoint . EndpointAddress );
var url = await sandbox . GetEndpointUrlAsync ( 44772 );
Console . WriteLine ( url ); // e.g., "http://localhost:44772"
Sandbox Management (Admin)
Use SandboxManager for administrative tasks and finding existing sandboxes.
await using var manager = SandboxManager . Create ( new SandboxManagerOptions
{
ConnectionConfig = config
});
var list = await manager . ListSandboxInfosAsync ( new SandboxFilter
{
States = new [] { SandboxStates . Running },
PageSize = 10
});
foreach ( var s in list . Items )
{
Console . WriteLine ( s . Id );
}
Configuration
Connection Configuration
The ConnectionConfig class manages API server connection settings.
Parameter Description Default Environment Variable ApiKeyAPI key for authentication Optional OPEN_SANDBOX_API_KEYDomainSandbox service domain (host[:port]) localhost:8080OPEN_SANDBOX_DOMAINProtocolHTTP protocol (Http/Https) Http- RequestTimeoutSecondsRequest timeout applied to SDK HTTP calls 30- UseServerProxyRequest server-proxied sandbox endpoint URLs false- HeadersExtra headers applied to every request {}-
using OpenSandbox . Config ;
var config = new ConnectionConfig ( new ConnectionConfigOptions
{
Domain = "api.opensandbox.io" ,
ApiKey = "your-key" ,
RequestTimeoutSeconds = 60 ,
});
// Custom headers
var config = new ConnectionConfig ( new ConnectionConfigOptions
{
Domain = "api.opensandbox.io" ,
ApiKey = "your-key" ,
Headers = new Dictionary < string , string >
{
[ "X-Custom-Header" ] = "value"
},
// UseServerProxy = true, // Useful when client cannot access sandbox endpoint directly
});
Diagnostics and Logging
The SDK uses Microsoft.Extensions.Logging abstractions.
using Microsoft . Extensions . Logging ;
using OpenSandbox . Config ;
using var loggerFactory = LoggerFactory . Create ( builder =>
{
builder . SetMinimumLevel ( LogLevel . Debug );
builder . AddConsole ();
});
var sandbox = await Sandbox . CreateAsync ( new SandboxCreateOptions
{
Image = "python:3.11" ,
ConnectionConfig = new ConnectionConfig (),
Diagnostics = new SdkDiagnosticsOptions
{
LoggerFactory = loggerFactory
}
});
Sandbox Creation Configuration
Sandbox.CreateAsync() allows configuring the sandbox environment.
Parameter Description Default ImageDocker image to use Required TimeoutSecondsAutomatic termination timeout (server-side TTL) 10 minutes EntrypointContainer entrypoint command ["tail","-f","/dev/null"]ResourceCPU and memory limits (string map) {"cpu":"1","memory":"2Gi"}EnvEnvironment variables {}MetadataCustom metadata tags {}NetworkPolicyOptional outbound network policy (egress) - VolumesOptional storage mounts (Host / PVC, supports ReadOnly and SubPath) - ExtensionsExtra server-defined fields {}SkipHealthCheckSkip readiness checks (Running + health check) falseHealthCheckCustom readiness check - ReadyTimeoutSecondsMax time to wait for readiness 30 seconds HealthCheckPollingIntervalPoll interval while waiting (milliseconds) 200 ms
var sandbox = await Sandbox . CreateAsync ( new SandboxCreateOptions
{
ConnectionConfig = config ,
Image = "python:3.11" ,
NetworkPolicy = new NetworkPolicy
{
DefaultAction = NetworkRuleAction . Deny ,
Egress = new List < NetworkRule >
{
new () { Action = NetworkRuleAction . Allow , Target = "pypi.org" }
}
},
Volumes = new []
{
new Volume
{
Name = "workspace" ,
Host = new Host { Path = "/tmp/opensandbox-e2e/host-volume-test" },
MountPath = "/workspace" ,
ReadOnly = false
}
}
});
Timeout and Retry Behavior
ConnectionConfig.RequestTimeoutSeconds controls timeout for SDK HTTP calls.
RunCommandOptions.TimeoutSeconds controls command execution timeout for command runs.
SandboxCreateOptions.TimeoutSeconds controls sandbox server-side TTL.
ReadyTimeoutSeconds controls how long CreateAsync / ConnectAsync waits for readiness.
The SDK does not automatically retry failed API requests; implement retries in caller code where appropriate.
Resource Cleanup
Both Sandbox and SandboxManager implement IAsyncDisposable. Use await using or call DisposeAsync() when done.
await using var sandbox = await Sandbox . CreateAsync ( options );
// ... use sandbox ...
// Automatically disposed when leaving scope
Error Handling
The SDK throws SandboxException (and derived exceptions such as SandboxApiException, SandboxReadyTimeoutException, and InvalidArgumentException) when operations fail.
try
{
var execution = await sandbox . Commands . RunAsync ( "echo 'Hello Sandbox!'" );
Console . WriteLine ( execution . Logs . Stdout . FirstOrDefault () ? . Text );
}
catch ( SandboxReadyTimeoutException )
{
Console . Error . WriteLine ( "Sandbox did not become ready before the configured timeout." );
}
catch ( SandboxApiException ex )
{
Console . Error . WriteLine ( $"API Error: status= { ex . StatusCode } , requestId= { ex . RequestId } , message= { ex . Message } " );
}
catch ( SandboxException ex )
{
Console . Error . WriteLine ( $"Sandbox Error: [ { ex . Error . Code } ] { ex . Error . Message } " );
}
Supported Frameworks
The SDK supports a wide range of .NET platforms:
.NET Standard 2.0 (for maximum compatibility with .NET Framework 4.6.1+, .NET Core 2.0+, Mono, Xamarin, etc.)
.NET Standard 2.1
.NET 6.0 (LTS)
.NET 7.0
.NET 8.0 (LTS)
.NET 9.0
.NET 10.0
API Reference
Sandbox
Main class for interacting with sandboxes.
Methods
Creates and initializes a new sandbox instance. Parameters:
options (SandboxCreateOptions): Configuration options
Returns: Task<Sandbox>
Connects to an existing sandbox by ID. Parameters:
options (SandboxConnectOptions): Connection options including sandbox ID
Returns: Task<Sandbox>
Access to command execution operations. Returns: CommandsClient
Access to file system operations. Returns: FilesClient
Extends the sandbox expiration time. Parameters:
timeoutSeconds (int): Extension duration in seconds
Returns: Task
Pauses the sandbox (suspends all processes). Returns: Task
Resumes this paused sandbox. Returns: Task<Sandbox>
Terminates the sandbox immediately. Returns: Task
Retrieves current sandbox information. Returns: Task<SandboxInfo>
Gets the external endpoint for a port (without scheme). Parameters:
port (int): Internal port number
Returns: Task<SandboxEndpoint>
Gets the full URL for a port (with scheme). Parameters:
port (int): Internal port number
Returns: Task<string>
Examples
Running a C# Script
await sandbox . Files . WriteFilesAsync ( new []
{
new WriteEntry
{
Path = "/app/Program.cs" ,
Data = @"
using System;
Console.WriteLine($" . NET version : { Environment . Version } ") ;
Console . WriteLine ( "Hello from OpenSandbox!" );
" ,
Mode = 644
}
});
var execution = await sandbox . Commands . RunAsync ( "dotnet script /app/Program.cs" );
foreach ( var line in execution . Logs . Stdout )
{
Console . WriteLine ( line . Text );
}
Network Policy Example
var sandbox = await Sandbox . CreateAsync ( new SandboxCreateOptions
{
ConnectionConfig = config ,
Image = "mcr.microsoft.com/dotnet/sdk:8.0" ,
NetworkPolicy = new NetworkPolicy
{
DefaultAction = NetworkRuleAction . Deny ,
Egress = new List < NetworkRule >
{
new () { Action = NetworkRuleAction . Allow , Target = "nuget.org" },
new () { Action = NetworkRuleAction . Allow , Target = "api.nuget.org" },
}
},
});
Port Forwarding
// Start a web server in the sandbox
await sandbox . Commands . RunAsync (
"dotnet run --project /app/WebApp.csproj" ,
options : new RunCommandOptions { Background = true }
);
// Get the external URL
var url = await sandbox . GetEndpointUrlAsync ( 5000 );
Console . WriteLine ( $"Access your server at: { url } " );
Next Steps
Python SDK Explore the Python SDK
JavaScript SDK Explore the JavaScript/TypeScript SDK
API Reference Detailed API documentation
Examples Browse more code examples