![]() |
VOOZH | about |
dotnet add package Tharga.Communication --version 0.2.1
NuGet\Install-Package Tharga.Communication -Version 0.2.1
<PackageReference Include="Tharga.Communication" Version="0.2.1" />
<PackageVersion Include="Tharga.Communication" Version="0.2.1" />Directory.Packages.props
<PackageReference Include="Tharga.Communication" />Project file
paket add Tharga.Communication --version 0.2.1
#r "nuget: Tharga.Communication, 0.2.1"
#:package Tharga.Communication@0.2.1
#addin nuget:?package=Tharga.Communication&version=0.2.1Install as a Cake Addin
#tool nuget:?package=Tharga.Communication&version=0.2.1Install as a Cake Tool
A SignalR-based communication framework for .NET with built-in message handler patterns for request-response and fire-and-forget messaging.
builder.AddThargaCommunicationServer(options =>
{
options.RegisterClientStateService<MyClientStateService>();
options.RegisterClientRepository<MemoryClientRepository<ClientConnectionInfo>, ClientConnectionInfo>();
});
app.UseThargaCommunicationServer();
Add to appsettings.json:
{
"Tharga": {
"Communication": {
"ServerAddress": "https://localhost:5001"
}
}
}
builder.AddThargaCommunicationClient();
By default, the server accepts all connections. To require API keys, set ApiKeys on the server options:
builder.AddThargaCommunicationServer(options =>
{
options.ApiKeys = ["my-secret-key", "rotation-key"];
options.RegisterClientStateService<MyClientStateService>();
options.RegisterClientRepository<MemoryClientRepository<ClientConnectionInfo>, ClientConnectionInfo>();
});
Clients send the key via CommunicationOptions.ApiKey (or appsettings.json):
builder.AddThargaCommunicationClient(o => o.ApiKey = "my-secret-key");
For more advanced scenarios (per-key lookup in a database, per-IP allowlists, integration with Tharga.Platform's API key management, etc.), register an IApiKeyValidator:
public class MyApiKeyValidator : IApiKeyValidator
{
private readonly IApiKeyAdministrationService _keys;
public MyApiKeyValidator(IApiKeyAdministrationService keys) => _keys = keys;
public async Task<ApiKeyValidationResult> ValidateAsync(string apiKey, CancellationToken ct = default)
{
var key = await _keys.GetByValueAsync(apiKey, ct);
return key is null
? new() { IsValid = false }
: new() { IsValid = true, KeyId = key.Id.ToString(), KeyName = key.Name };
}
}
builder.AddThargaCommunicationServer(options =>
{
options.RegisterApiKeyValidator<MyApiKeyValidator>();
// …
});
The validator decides everything — including whether to accept empty keys (return IsValid = true, KeyId = null to allow anonymous), or how to identify the matched key. KeyId and KeyName flow through to IClientConnectionInfo, where consumers can use them for admin UIs and audit logs.
Need HTTP context? Inject
IHttpContextAccessorinto your validator if you need access to the request (IP allowlists, custom headers, etc.). The framework intentionally does not passHttpContextto keepIApiKeyValidatornarrow and testable.
The client sends four self-reported identity headers during connection: Instance (Guid generated per process run), Machine, Type (assembly name), and Version. Two of those — Machine and Type — can be overridden via options:
builder.AddThargaCommunicationClient(o =>
{
o.ServerAddress = "https://localhost:5001";
o.ClientType = "monitor-agent"; // override; defaults to entry assembly name
o.ClientMachine = "us-east-prod-1"; // override; defaults to Environment.MachineName
});
Useful when one assembly hosts multiple roles, or when containerized hosts have meaningless hash-based hostnames.
// Fire-and-forget
public class MyHandler : PostMessageHandlerBase<MyMessage>
{
public override Task Handle(MyMessage message) => Task.CompletedTask;
}
// Request-response
public class PingHandler : SendMessageHandlerBase<PingRequest, PingResponse>
{
public override Task<PingResponse> Handle(PingRequest message) =>
Task.FromResult(new PingResponse("Pong"));
}
Subscriptions allow the server to signal clients whether anyone is consuming a particular message type, so clients can skip sending data when no dashboard or consumer is active.
// Type-based: subscribe to all messages of a type
await using var sub = await serverCommunication.SubscribeAsync<CollectionDto>();
// Data-based: subscribe to a specific entity
await using var sub = await serverCommunication.SubscribeAsync<FarmDetailsDto>(farmId.ToString());
// Monitor active subscriptions
IReadOnlyDictionary<string, int> active = serverCommunication.GetSubscriptions();
In Blazor, tie the subscription to the page lifecycle:
@implements IAsyncDisposable
@inject IServerCommunication ServerCommunication
@code {
private IAsyncDisposable? _subscription;
protected override async Task OnInitializedAsync()
{
_subscription = await ServerCommunication.SubscribeAsync<FarmDetailsDto>(FarmId.ToString());
}
public async ValueTask DisposeAsync()
{
if (_subscription != null) await _subscription.DisposeAsync();
}
}
// Check before sending
if (clientCommunication.HasSubscribers<FarmDetailsDto>(farmId.ToString()))
await clientCommunication.PostAsync(farmDetails);
// Or use the convenience method (no-ops when no subscribers)
await clientCommunication.PostIfSubscribedAsync(farmDetails, farmId.ToString());
// React to subscription changes
clientCommunication.SubscriptionChanged += (sender, e) =>
{
Console.WriteLine($"{e.Topic}:{e.Key} → {(e.HasSubscribers ? "active" : "inactive")}");
};
SubscribeAsync<T>() without key): wildcard — HasSubscribers<T>("anyKey") returns true.SubscribeAsync<T>("1") with key): specific — only HasSubscribers<T>("1") returns true.For full documentation and examples, see the GitHub repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 3 NuGet packages that depend on Tharga.Communication:
| Package | Downloads |
|---|---|
|
Tharga.MongoDB.Monitor.Client
Forwards MongoDB monitoring data to a central server via Tharga.Communication. |
|
|
Tharga.MongoDB.Monitor.Server
Receives MongoDB monitoring data from remote agents via Tharga.Communication and aggregates it into the local IDatabaseMonitor. |
|
|
Tharga.Communication.Mcp
Exposes Tharga.Communication runtime data (connected clients, active subscriptions, registered handlers) via MCP (Model Context Protocol). Plugs into Tharga.Mcp. |
This package is not used by any popular GitHub repositories.