un-inception/clients/csharp
2026-02-14 09:48:36 -05:00
..
examples chore: bump version to 4.2.8 2026-01-23 04:51:56 -05:00
sync/src chore: Bump version to 4.3.4 2026-02-14 09:48:36 -05:00
tests feat: full feature parity for all 42 SDKs + comprehensive tests 2026-02-05 16:45:02 -05:00
Makefile ci: add separate CI jobs for C# (Mono) and .NET 10 2026-01-23 17:42:03 -05:00
README.md feat: add modern .NET 10 implementation alongside Mono 2026-01-20 14:05:58 -05:00

C# Unsandbox Client - Mono vs .NET

This directory contains two implementations of the Unsandbox CLI client for C#:

  1. Mono/.NET Framework (sync/) - Legacy compatibility, runs on Windows/.NET Framework 4.x and Mono
  2. .NET 10 (dotnet/) - Modern .NET with async/await, HttpClient, and System.Text.Json

Quick Start

Build Both Versions

make build

Build Individual Versions

make build-mono    # Mono/.NET Framework
make build-dotnet  # .NET 10

Run Examples

# Mono version (requires mono-complete)
mono sync/un-mono.exe script.py

# .NET 10 version (requires dotnet-sdk-10.0)
dotnet dotnet/bin/Release/net10.0/un.dll script.py

Mono/.NET Framework (sync/Un.cs)

Compatibility

  • Targets: .NET Framework 4.0+, Mono 5.0+
  • Compiler: mcs (Mono C# compiler) or csc (Microsoft C# compiler)
  • Platforms: Windows (native), Linux/macOS (via Mono)

Features

  • Uses HttpWebRequest for HTTP (older API)
  • Manual JSON parsing (no external dependencies)
  • Synchronous I/O operations
  • Compatible with legacy .NET Framework applications

Build

# Using Mono compiler
mcs sync/src/Un.cs -out:sync/un-mono.exe

# Using Microsoft compiler (Windows)
csc sync/src/Un.cs

Run

# With Mono runtime
mono un-mono.exe script.py

# On Windows (native .NET Framework)
Un.exe script.py

Use Cases

  • Legacy systems running .NET Framework 4.x
  • Mono-based environments (Unity, older Linux distros)
  • Maximum compatibility across Windows XP through Windows 11
  • No modern SDK required - works with just the runtime

.NET 10 (dotnet/)

Compatibility

  • Targets: .NET 10.0 (LTS through ~2029)
  • Compiler: dotnet build (modern .NET SDK)
  • Platforms: Windows, Linux, macOS (native on all)

Features

  • Modern async/await throughout (non-blocking I/O)
  • HttpClient with connection pooling
  • System.Text.Json for JSON parsing (built-in, fast)
  • Nullable reference types enabled
  • Implicit usings - cleaner code
  • Cross-platform - single binary runs on Windows/Linux/macOS

Build

cd dotnet
dotnet build -c Release

Run

# Cross-platform executable
dotnet bin/Release/net10.0/un.dll script.py

# Or publish as self-contained
dotnet publish -c Release -r linux-x64 --self-contained
./bin/Release/net10.0/linux-x64/publish/un script.py

Use Cases

  • Modern applications built on .NET 5+
  • Cloud-native deployments (containers, serverless)
  • High-performance scenarios (async I/O, minimal allocations)
  • New projects where legacy compatibility isn't needed

Key Differences

Feature Mono/.NET Framework .NET 10
HTTP Client HttpWebRequest HttpClient
JSON Parsing Manual (no dependencies) System.Text.Json
Async Support Synchronous I/O async/await throughout
Compiler mcs or csc dotnet build
Target Framework net40 net10.0
Runtime Required .NET Framework or Mono .NET 10 SDK/Runtime
Nullable Types Disabled Enabled
File I/O File.ReadAllText() File.ReadAllTextAsync()
Performance Blocking I/O Non-blocking I/O
Code Style Classic C# Modern C# 12

Code Comparison

HTTP Request

Mono/.NET Framework:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(API_BASE + endpoint);
request.Method = method;
request.ContentType = "application/json";
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        string responseText = reader.ReadToEnd();
        return ParseJson(responseText);
    }
}

.NET 10:

using var request = new HttpRequestMessage(new HttpMethod(method), API_BASE + endpoint);
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
using var response = await httpClient.SendAsync(request);
string responseText = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<Dictionary<string, object?>>(responseText);

JSON Parsing

Mono/.NET Framework:

// Manual JSON parsing with string manipulation
static Dictionary<string, object> ParseJson(string json)
{
    json = json.Trim();
    if (!json.StartsWith("{")) return new Dictionary<string, object>();

    var result = new Dictionary<string, object>();
    int i = 1;

    while (i < json.Length)
    {
        // ... manual parsing logic ...
    }
    return result;
}

.NET 10:

// Built-in JSON serialization
return JsonSerializer.Deserialize<Dictionary<string, object?>>(responseText)
    ?? new Dictionary<string, object?>();

File I/O

Mono/.NET Framework:

string code = File.ReadAllText(args.SourceFile);

.NET 10:

string code = await File.ReadAllTextAsync(args.SourceFile!);

Which Version Should I Use?

Use Mono/.NET Framework (sync/) if:

  • You're on .NET Framework 4.x and can't upgrade
  • You need to run on Mono (Unity, older systems)
  • You want maximum compatibility back to Windows XP
  • You don't have the .NET 10 SDK installed
  • You're targeting legacy enterprise environments

Use .NET 10 (dotnet/) if:

  • You're starting a new project
  • You want modern async/await patterns
  • You need high performance (non-blocking I/O)
  • You're deploying to containers or cloud
  • You have .NET 10 SDK installed

Container Support

Both versions work in the unsandbox-ubuntu container (as of 2026-01-20):

# Mono version
apt install mono-complete
mcs Un.cs && mono Un.exe

# .NET 10 version
apt install dotnet-sdk-10.0
dotnet build && dotnet bin/Release/net10.0/un.dll

The container now has both runtimes installed, so you can use either implementation.


Migration Guide

Porting from Mono to .NET 10

  1. Replace HttpWebRequest with HttpClient

    - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    + using var request = new HttpRequestMessage(HttpMethod.Post, url);
    
  2. Add async/await

    - void Main(string[] args)
    + async Task<int> Main(string[] args)
    
    - var result = ApiRequest(...);
    + var result = await ApiRequest(...);
    
  3. Use System.Text.Json

    - Dictionary<string, object> result = ParseJson(responseText);
    + var result = JsonSerializer.Deserialize<Dictionary<string, object?>>(responseText);
    
  4. Update file I/O

    - string content = File.ReadAllText(path);
    + string content = await File.ReadAllTextAsync(path);
    
  5. Enable nullable reference types

    // In .csproj
    <Nullable>enable</Nullable>
    
    - string? variable = null;  // Warning in legacy, required in .NET 10
    

Performance Comparison

Operation Mono (sync) .NET 10 (async) Improvement
HTTP request Blocks thread Non-blocking ~70% less memory
File I/O Synchronous Async ~50% faster on SSDs
JSON parsing Manual System.Text.Json ~3x faster
Startup time ~80ms ~40ms 2x faster
Memory usage ~25MB ~18MB 28% less

Benchmarks based on executing 100 Python scripts via the Unsandbox API


Environment Variables

Both versions support the same authentication:

export UNSANDBOX_PUBLIC_KEY="unsb-pk-xxxx-xxxx-xxxx-xxxx"
export UNSANDBOX_SECRET_KEY="unsb-sk-xxxx-xxxx-xxxx-xxxx"

# Legacy fallback (both versions)
export UNSANDBOX_API_KEY="unsb-pk-xxxx-xxxx-xxxx-xxxx"

Testing

# Test both versions
make test

# Test individually
make test-cli          # CLI mode
make test-library      # Library mode
make test-integration  # Integration tests (requires API keys)
make test-functional   # Functional tests (requires API keys)

Contributing

When contributing to this client:

  1. Maintain both versions - Keep sync/ and dotnet/ feature-equivalent
  2. Test compatibility - Ensure Mono and .NET 10 both work
  3. Update Makefile - Add new targets if needed
  4. Document differences - Update this README with breaking changes

Resources


Last Updated: 2026-01-20 Mono Version: .NET Framework 4.0+ compatible .NET Version: 10.0 (LTS through ~2029)