This guide provides detailed, end-to-end examples for using UiRealTimeCommunicator in real applications.
- Server Setup
- Define Hubs
- Server-to-Client Messaging (Sender Contracts)
- Client-to-Server Messaging (Handlers)
- Handlers with Context
- Connection Lifecycle Events
- Sending to Specific Connections
- Model Generation
- TypeScript Client Usage
- Multiple Hubs
- Custom Hub and Method Names
- Troubleshooting
Install the package:
dotnet add package UiRealTimeCommunicatorRegister the services and middleware:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddUiRealTimeCommunicator();
var app = builder.Build();
app.UseUiRealTimeCommunicator();
app.Run();Hubs are marker classes that identify a communication channel.
public class WeatherHub : IUiRtcHub
{
}By default, the hub name is the class name (WeatherHub). You can override it with [UiRtcHub] (see Custom Hub and Method Names).
Define a sender contract interface. Each method becomes a TypeScript subscription.
public interface WeatherSender : IUiRtcSenderContract<WeatherHub>
{
Task WeatherForecast(WeatherForecastModel forecast);
Task WeatherAlert(WeatherAlertModel alert);
}Use the sender contract in your services:
public class WeatherService(IUiRtcSenderService senderService)
{
public async Task PublishForecastAsync(WeatherForecastModel model)
{
await senderService.Send<WeatherSender>().WeatherForecast(model);
}
public async Task PublishAlertAsync(WeatherAlertModel model)
{
await senderService.Send<WeatherSender>().WeatherAlert(model);
}
}Handlers receive messages from the client. Each handler class becomes a TypeScript communication method.
[UiRtcMethod("GetWeatherForecast")]
public class GetWeatherForecastHandler : IUiRtcHandler<WeatherHub, WeatherForecastRequestModel>
{
public async Task ConsumeAsync(WeatherForecastRequestModel model)
{
// Handle request from client
}
}If you need connection IDs or other SignalR context, use IUiRtcContextHandler:
public class GetWeatherWithContextHandler : IUiRtcContextHandler<WeatherHub, WeatherForecastRequestModel>
{
public async Task ConsumeAsync(WeatherForecastRequestModel model, IUiRtcProxyContext context)
{
var connectionId = context.ConnectionId;
// Use connectionId if needed
}
}Implement IUiRtcConnection<THub> to receive connection events:
public class WeatherConnectionHandler : IUiRtcConnection<WeatherHub>
{
public Task OnConnectedAsync(string connectionId)
{
// Handle client connection
return Task.CompletedTask;
}
public Task OnDisconnectedAsync(string connectionId, Exception? exception)
{
// Handle client disconnection
return Task.CompletedTask;
}
}You can target specific connections when sending messages:
public class WeatherService(IUiRtcSenderService senderService)
{
public async Task SendToSpecificClientAsync(string connectionId, WeatherForecastModel model)
{
await senderService.Send<WeatherSender>(connectionId).WeatherForecast(model);
}
public async Task SendToMultipleClientsAsync(string[] connectionIds, WeatherAlertModel model)
{
await senderService.Send<WeatherSender>(connectionIds).WeatherAlert(model);
}
}Mark models with [TranspilationSource] so they are generated into TypeScript.
[TranspilationSource]
public class WeatherForecastModel
{
public required string City { get; set; }
public required double Temperature { get; set; }
public string? Summary { get; set; }
}
[TranspilationSource]
public class WeatherAlertModel
{
public required string Level { get; set; }
public required string Message { get; set; }
}
[TranspilationSource]
public class WeatherForecastRequestModel
{
public required string City { get; set; }
}Install SignalR:
npm install @microsoft/signalrInitialize connections:
import { uiRtc } from "./communication/contract";
await uiRtc.initAsync({
serverUrl: "http://localhost:5064/",
activeHubs: "All",
});Send messages to the server:
import { uiRtcCommunication, WeatherForecastRequestModel } from "./communication/contract";
await uiRtcCommunication.Weather.GetWeatherForecast({
city: "Kharkiv",
} as WeatherForecastRequestModel);Subscribe to messages from the server:
import { uiRtcSubscription, WeatherForecastModel } from "./communication/contract";
const subscription = uiRtcSubscription.Weather.WeatherForecast(
(data: WeatherForecastModel) => {
console.log("Forecast:", data);
}
);
// Unsubscribe when needed
subscription.unsubscribe();You can define multiple hubs and use them independently.
public class ChatHub : IUiRtcHub { }
public class WeatherHub : IUiRtcHub { }
public interface ChatSender : IUiRtcSenderContract<ChatHub>
{
Task Message(ChatMessageModel message);
}
public interface WeatherSender : IUiRtcSenderContract<WeatherHub>
{
Task Forecast(WeatherForecastModel forecast);
}TypeScript initialization can target all hubs or specific ones:
await uiRtc.initAsync({
serverUrl: "http://localhost:5064/",
activeHubs: ["Chat", "Weather"],
});Use attributes to customize hub and method names.
[UiRtcHub("Weather")]
public class WeatherHub : IUiRtcHub { }
[UiRtcMethod("GetForecast")]
public class GetWeatherHandler : IUiRtcHandler<WeatherHub, WeatherForecastRequestModel>
{
public Task ConsumeAsync(WeatherForecastRequestModel model)
{
return Task.CompletedTask;
}
}
public interface WeatherSender : IUiRtcSenderContract<WeatherHub>
{
[UiRtcMethod("Forecast")]
Task SendForecast(WeatherForecastModel forecast);
}- Ensure hub classes implement
IUiRtcHub - Ensure handler classes implement
IUiRtcHandler<THub>orIUiRtcHandler<THub, TModel> - Ensure sender contracts implement
IUiRtcSenderContract<THub>
- Ensure models are marked with
[TranspilationSource] - Ensure model types are in the project being transpiled
- Check
serverUrlincludes the correct base URL - Ensure you call
uiRtc.initAsync()before sending or subscribing
Install the generator tool:
dotnet tool install --global UiRealTimeCommunicator.TypeScriptGeneratorGenerate code:
dotnet-uirtc -p "./YourProject/YourProject.csproj" -o "./frontend/src/communication/contract.ts"If the output path is a directory, the file contract.ts is created automatically.