Official .NET SDK for OddSockets - Enterprise-ready real-time messaging with automatic load balancing and failover.
- Real-time messaging with automatic load balancing
- ⚡ Task-based async/await patterns for modern .NET
- 🔒 Strong typing with nullable reference types
- 🏗️ Dependency injection support for ASP.NET Core
- 📦 Bulk message publishing for high-throughput scenarios
- 📚 Message history and presence tracking
- 🔄 Automatic reconnection with exponential backoff
- 🧵 Thread-safe operations
- 📝 Comprehensive logging support
- 🎯 Multi-targeting (.NET 6.0, .NET 8.0, .NET Standard 2.0)
Install-Package OddSockets.DotNet.SDKdotnet add package OddSockets.DotNet.SDK<PackageReference Include="OddSockets.DotNet.SDK" Version="0.1.0-beta.1" />using OddSockets;
using OddSockets.Models;
// Create configuration
var config = new OddSocketsConfigBuilder()
.WithApiKey("ak_live_your_api_key_here")
.WithUserId("user123")
.Build();
// Create client
using var client = new OddSocketsClient(config);
// Connect
await client.ConnectAsync();
// Get a channel
var channel = client.Channel("my-channel");
// Subscribe to messages
await channel.SubscribeAsync(message =>
{
Console.WriteLine($"Received: {message.Data}");
});
// Publish a message
await channel.PublishAsync("Hello, OddSockets!");// Program.cs or Startup.cs
builder.Services.AddSingleton<OddSocketsConfig>(provider =>
new OddSocketsConfigBuilder()
.WithApiKey(builder.Configuration["OddSockets:ApiKey"])
.WithUserId("web-app-user")
.Build());
builder.Services.AddSingleton<OddSocketsClient>();
// In your controller or service
public class ChatController : ControllerBase
{
private readonly OddSocketsClient _oddSockets;
public ChatController(OddSocketsClient oddSockets)
{
_oddSockets = oddSockets;
}
[HttpPost("send")]
public async Task<IActionResult> SendMessage([FromBody] ChatMessage message)
{
var channel = _oddSockets.Channel("chat-room");
var result = await channel.PublishAsync(message);
return Ok(result);
}
}var config = new OddSocketsConfigBuilder()
.WithApiKey("ak_live_your_api_key_here")
.WithManagerUrl("https://manager1.oddsockets.tyga.network") // Optional
.WithUserId("user123") // Optional, auto-generated if not provided
.WithAutoConnect(true) // Optional, default: true
.WithReconnectAttempts(5) // Optional, default: 5
.WithHeartbeatInterval(30) // Optional, default: 30 seconds
.WithTimeout(10) // Optional, default: 10 seconds
.Build();var config = new OddSocketsConfig
{
ApiKey = "ak_live_your_api_key_here",
UserId = "user123",
AutoConnect = true,
ReconnectAttempts = 3
};using var client = new OddSocketsClient(config);
// Connection events
client.On(EventType.Connected, data =>
Console.WriteLine("Connected!"));
client.On(EventType.Disconnected, data =>
Console.WriteLine("Disconnected"));
client.On(EventType.Error, error =>
Console.WriteLine($"Error: {error}"));
// Manual connection control
await client.ConnectAsync();
await client.DisconnectAsync();
// Check connection status
if (client.IsConnected)
{
Console.WriteLine("Ready to send messages!");
}var channel = client.Channel("my-channel");
// Subscribe with options
await channel.SubscribeAsync(
message => Console.WriteLine($"Message: {message.Data}"),
SubscribeOptions.Builder()
.WithPresence(true)
.WithHistory(true)
.WithFilter("important")
.Build()
);
// Publish with options
var result = await channel.PublishAsync(
"Hello World!",
PublishOptions.Builder()
.WithTtl(3600) // 1 hour
.WithMetadata("priority", "high")
.WithHistory(true)
.Build()
);
Console.WriteLine($"Published: {result.MessageId}");var messages = new List<BulkMessage>
{
new("channel1", "Message 1"),
new("channel2", "Message 2"),
new("channel3", new { type = "notification", text = "Message 3" })
};
var results = await client.PublishBulkAsync(messages);
foreach (var result in results)
{
if (result.Success)
Console.WriteLine($"✅ {result.Result?.MessageId}");
else
Console.WriteLine($"❌ {result.Error}");
}var history = await channel.GetHistoryAsync(
HistoryOptions.Builder()
.WithLimit(50)
.WithStart(DateTime.UtcNow.AddHours(-1))
.WithReverse(true)
.Build()
);
foreach (var message in history)
{
Console.WriteLine($"{message.Timestamp}: {message.Data}");
}// Enable presence when subscribing
await channel.SubscribeAsync(
message => { /* handle message */ },
SubscribeOptions.Builder().WithPresence(true).Build()
);
// Get current presence
var presence = await channel.GetPresenceAsync();
Console.WriteLine($"{presence.Count} users online:");
foreach (var user in presence.Users)
{
Console.WriteLine($"- {user}");
}
// Listen for presence changes
channel.On(EventType.Presence, data =>
{
Console.WriteLine($"Presence update: {data}");
});try
{
await channel.PublishAsync("test message");
}
catch (OddSocketsConnectionException ex)
{
Console.WriteLine($"Connection error: {ex.Message}");
// Handle connection issues
}
catch (OddSocketsChannelException ex)
{
Console.WriteLine($"Channel error: {ex.Message}");
// Handle channel-specific issues
}
catch (OddSocketsException ex)
{
Console.WriteLine($"General error: {ex.Message}");
Console.WriteLine($"Error code: {ex.ErrorCode}");
// Handle other OddSockets errors
}using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(builder =>
builder.AddConsole().SetMinimumLevel(LogLevel.Debug));
var logger = loggerFactory.CreateLogger<OddSocketsClient>();
var client = new OddSocketsClient(config, logger);// Program.cs
builder.Services.AddLogging();
builder.Services.AddSingleton<OddSocketsConfig>(/* config */);
builder.Services.AddSingleton<OddSocketsClient>();
// Usage
public class MyService
{
private readonly OddSocketsClient _client;
private readonly ILogger<MyService> _logger;
public MyService(OddSocketsClient client, ILogger<MyService> logger)
{
_client = client;
_logger = logger;
}
public async Task SendNotificationAsync(string message)
{
try
{
var channel = _client.Channel("notifications");
await channel.PublishAsync(message);
_logger.LogInformation("Notification sent successfully");
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to send notification");
throw;
}
}
}public class ChatService
{
private readonly OddSocketsClient _client;
private readonly OddSocketsChannel _channel;
public ChatService(OddSocketsClient client)
{
_client = client;
_channel = _client.Channel("chat-room");
}
public async Task StartAsync()
{
await _client.ConnectAsync();
await _channel.SubscribeAsync(
OnMessageReceived,
SubscribeOptions.Builder()
.WithPresence(true)
.WithHistory(true)
.Build()
);
}
public async Task SendMessageAsync(string username, string message)
{
await _channel.PublishAsync(new
{
username,
message,
timestamp = DateTime.UtcNow
});
}
private void OnMessageReceived(Message message)
{
// Handle incoming chat message
Console.WriteLine($"Chat: {message.Data}");
}
}public class DashboardService
{
private readonly OddSocketsClient _client;
public DashboardService(OddSocketsClient client)
{
_client = client;
}
public async Task PublishMetricsAsync(object metrics)
{
var channel = _client.Channel("dashboard-metrics");
await channel.PublishAsync(metrics,
PublishOptions.Builder()
.WithTtl(60) // Metrics expire after 1 minute
.WithMetadata("type", "metrics")
.Build()
);
}
public async Task SubscribeToUpdatesAsync(Action<object> onUpdate)
{
var channel = _client.Channel("dashboard-metrics");
await channel.SubscribeAsync(
message => onUpdate(message.Data),
SubscribeOptions.Builder()
.WithFilter("metrics")
.Build()
);
}
}| Method | Description |
|---|---|
ConnectAsync() |
Connect to OddSockets platform |
DisconnectAsync() |
Disconnect from platform |
Channel(string) |
Get or create a channel |
PublishBulkAsync(IEnumerable<BulkMessage>) |
Publish multiple messages |
On(EventType, Func<object?, Task>) |
Add event handler |
Off(EventType, Func<object?, Task>?) |
Remove event handler |
| Method | Description |
|---|---|
SubscribeAsync(Func<Message, Task>, SubscribeOptions?) |
Subscribe to messages |
UnsubscribeAsync() |
Unsubscribe from messages |
PublishAsync(object?, PublishOptions?) |
Publish a message |
GetHistoryAsync(HistoryOptions?) |
Get message history |
GetPresenceAsync() |
Get presence information |
| Property | Type | Default | Description |
|---|---|---|---|
ApiKey |
string |
Required | Your OddSockets API key |
ManagerUrl |
string |
https://manager1.oddsockets.tyga.network |
Manager service URL |
UserId |
string? |
Auto-generated | User identifier |
AutoConnect |
bool |
true |
Auto-connect on creation |
ReconnectAttempts |
int |
5 |
Max reconnection attempts |
HeartbeatInterval |
int |
30 |
Heartbeat interval (seconds) |
Timeout |
int |
10 |
Request timeout (seconds) |
The SDK provides specific exception types for different error scenarios:
OddSocketsException- Base exception for all SDK errorsOddSocketsConnectionException- Connection-related errorsOddSocketsAuthenticationException- Authentication failuresOddSocketsChannelException- Channel operation errorsOddSocketsMessageException- Message publishing errors
The OddSockets .NET SDK is designed to be thread-safe:
- Multiple threads can safely call methods on the same client instance
- Channel operations are protected by internal synchronization
- Event handlers are invoked safely across threads
- Concurrent publish operations are supported
- Use bulk publishing for high-throughput scenarios
- Configure appropriate TTL values for messages
- Consider message filtering to reduce client-side processing
- Use presence tracking judiciously (only when needed)
- Implement proper connection pooling in web applications
- .NET 6.0 and later
- .NET 8.0 and later
- .NET Standard 2.0 (for .NET Framework 4.6.1+)
- ASP.NET Core 6.0+
- Blazor Server and WebAssembly
- MAUI applications
AI agents can sign up with a verified email in two steps — no dashboard, no human required.
Step 1: Request a verification code
curl -X POST https://oddsockets.com/api/agent-signup \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "agentName": "my-agent", "platform": "csharp"}'Step 2: Verify the 6-digit code from your email and get your API key
curl -X POST https://oddsockets.com/api/agent-signup/verify \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "code": "123456", "agentName": "my-agent"}'| Free | Starter | Pro | |
|---|---|---|---|
| Price | $0/mo | $49.99/mo | $299/mo |
| MAU | 100 | 1,000 | 50,000 |
| Concurrent connections | 50 | 1,000 | Unlimited |
| Messages/day | 10,000 | 4,320,000 | Unlimited |
| Channels | 10 | Unlimited | Unlimited |
| Storage | 100MB (24h) | 50GB (6 months) | Unlimited |
All limits are enforced in real time.
MIT License - Copyright (c) 2026 Joe Wee, Tyga.Cloud Ltd. See LICENSE for details.