Skip to main content

.NET Client SDK

The Titan.Client library provides a strongly-typed client for connecting to the Titan API.

Installation

dotnet add package Titan.Client

Or reference the project directly:

<ProjectReference Include="..\Titan.Client\Titan.Client.csproj" />

Quick Start

using Titan.Client;

// Create client
var client = new TitanClientBuilder()
.WithBaseUrl("https://api.example.com")
.WithAutoReconnect()
.Build();

// Login
await client.Auth.LoginAsync("mock:test-user", "Mock");

// Use typed hub clients
var accountClient = await client.GetAccountClientAsync();
var account = await accountClient.GetAccount();

Console.WriteLine($"Account: {account.AccountId}");

// Cleanup
await client.DisposeAsync();

Builder Configuration

var client = new TitanClientBuilder()
.WithBaseUrl("https://api.example.com")
.WithAutoReconnect() // Enable SignalR auto-reconnect
.WithLogging(loggerFactory) // Add logging
.Build();

TitanClientOptions

public class TitanClientOptions
{
public string BaseUrl { get; set; }
public bool EnableAutoReconnect { get; set; }
public ILoggerFactory? LoggerFactory { get; set; }
}

Authentication

Login

// Login with EOS token
var response = await client.Auth.LoginAsync(eosToken, "EOS");

// Login with Mock provider (development)
var response = await client.Auth.LoginAsync("mock:user-guid", "Mock");

// Response contains tokens
Console.WriteLine($"User: {response.UserId}");
Console.WriteLine($"Access Token expires in: {response.ExpiresInSeconds}s");

Token State

// Check authentication state
if (client.IsAuthenticated)
{
var userId = client.UserId;
var token = client.AccessToken;
}

Token Refresh

// Get auth hub for token operations
var authClient = await client.GetAuthHubClientAsync();

// Refresh tokens
var refreshResult = await authClient.RefreshToken(currentRefreshToken);
// (tokens are automatically updated in client)

Hub Clients

Each hub has a strongly-typed client interface.

AccountHub

var accountClient = await client.GetAccountClientAsync();

// Get account info
var account = await accountClient.GetAccount();

// Get all characters
var characters = await accountClient.GetCharacters();

// Create character
var newChar = await accountClient.CreateCharacter(
"season-1",
"MyHero",
CharacterRestrictions.Hardcore
);

CharacterHub

var charClient = await client.GetCharacterClientAsync();

// Get character details
var character = await charClient.GetCharacter(characterId, seasonId);

// Add experience
var updated = await charClient.AddExperience(characterId, seasonId, 1000);

InventoryHub

var invClient = await client.GetInventoryClientAsync();

// Get bag contents
var items = await invClient.GetBagItems(characterId, seasonId);

// Equip item
var result = await invClient.Equip(characterId, seasonId, itemId, EquipmentSlot.MainHand);

TradeHub

var tradeClient = await client.GetTradeClientAsync();

// Start a trade
var session = await tradeClient.StartTrade(myCharId, targetCharId, seasonId);

// Add item to offer
await tradeClient.AddItem(session.TradeId, itemId);

// Accept trade
var result = await tradeClient.AcceptTrade(session.TradeId);

Receiving Trade Updates

// Implement receiver interface
public class TradeReceiver : ITradeHubReceiver
{
public Task OnTradeUpdate(TradeUpdateEvent update)
{
Console.WriteLine($"Trade {update.TradeId}: {update.EventType}");
return Task.CompletedTask;
}
}

// Get client with receiver
var tradeClient = await client.GetTradeClientAsync(new TradeReceiver());
await tradeClient.JoinTradeSession(tradeId);

Dependency Injection

Register with ASP.NET Core DI:

services.AddTitanClient(options =>
{
options.BaseUrl = "https://api.example.com";
options.EnableAutoReconnect = true;
});

Then inject:

public class GameService
{
private readonly TitanClient _client;

public GameService(TitanClient client)
{
_client = client;
}
}

Reconnection Handling

With auto-reconnect enabled:

var connection = await client.GetHubConnectionAsync("/accountHub");

connection.Reconnecting += error =>
{
Console.WriteLine($"Connection lost, reconnecting...");
return Task.CompletedTask;
};

connection.Reconnected += connectionId =>
{
Console.WriteLine($"Reconnected: {connectionId}");
// Re-subscribe to groups if needed
return Task.CompletedTask;
};

connection.Closed += error =>
{
Console.WriteLine($"Connection closed: {error?.Message}");
return Task.CompletedTask;
};

Error Handling

Hub exceptions are thrown as HubException:

try
{
await accountClient.CreateCharacter("invalid-season", "Name", 0);
}
catch (HubException ex)
{
Console.WriteLine($"Error: {ex.Message}");
// "Season 'invalid-season' not found."
}

Complete Example

using Titan.Client;
using Titan.Abstractions.Models;

class Program
{
static async Task Main()
{
// Setup
var client = new TitanClientBuilder()
.WithBaseUrl("https://localhost:7001")
.WithAutoReconnect()
.Build();

try
{
// Login
await client.Auth.LoginAsync("mock:test-user", "Mock");
Console.WriteLine($"Logged in as {client.UserId}");

// Get account
var accountHub = await client.GetAccountClientAsync();
var account = await accountHub.GetAccount();

// List characters
var characters = await accountHub.GetCharacters();
Console.WriteLine($"Characters: {characters.Count}");

foreach (var c in characters)
{
Console.WriteLine($" - {c.Name} (Level {c.Level}) [{c.SeasonId}]");
}

// Create character if none exist
if (!characters.Any())
{
var newChar = await accountHub.CreateCharacter(
"standard",
"FirstHero",
CharacterRestrictions.None
);
Console.WriteLine($"Created: {newChar.Name}");
}
}
finally
{
await client.DisposeAsync();
}
}
}