SignalR Protocol
The SignalR plugin auto-discovers mapped hubs and their methods via endpoint metadata scanning.
Package: Kuestenlogik.Bowire.Protocol.SignalR
Setup
dotnet add package Kuestenlogik.Bowire.Protocol.SignalR
builder.Services.AddSignalR();
var app = builder.Build();
app.MapHub<ChatHub>("/chathub");
app.MapBowire(); // Auto-discovers hubs
Hubs must be mapped with MapHub<T>() before MapBowire(). Bowire discovers them by scanning the application's EndpointDataSource for endpoints with HubMetadata.
Discovery
The SignalR plugin reflects each hub class to determine:
- Methods -- all public methods on the hub
- Parameter types -- displayed as proto-like type names (string, int32, etc.)
- Return types -- unwrapped from
Task<T>,ValueTask<T> - Streaming direction -- inferred from parameter and return types:
IAsyncEnumerable<T>orChannelReader<T>return = server streamingChannelReader<T>parameter = client streaming- Both = duplex
Call Types
Invoke (Unary)
Standard hub method invocation. Send a JSON object with parameter values, receive the return value.
Server Streaming
Hub methods returning IAsyncEnumerable<T> or ChannelReader<T> are treated as server streaming. Messages appear in the response viewer as they arrive.
Duplex
Hub methods that accept ChannelReader<T> and return a streaming type support duplex communication via interactive channels.
Separate targets (signalr@)
Method-level discovery needs the embedded endpoint metadata, but a standalone workbench can still drive a remote hub:
bowire --url signalr@https://api.example.com/hubs/chat
The plugin confirms hub-ness via the negotiate handshake and exposes an
ad-hoc SignalR Hub service with two generic entry points — SignalR has
no wire-level reflection, so you name the hub method yourself:
invoke-- calls a hub method once and returns its result.stream-- subscribes to a streaming hub method.
Both take the same payload: method (the hub method name) plus args,
one JSON value per positional parameter (42, "text", {"x":1} — bare
words are sent as strings):
{ "method": "Echo", "args": ["hello"] }
Limitations
- Method lists are embedded-only -- the ad-hoc
signalr@surface can call and stream, but listing a remote hub's methods is impossible without the in-process endpoint metadata; consult the target's own docs for method names. - Hub methods only -- broadcast methods invoked via
Clients.All.SendAsync()are not discoverable because they are not defined on the hub class.
Example
Given a hub:
public class ChatHub : Hub
{
public Task<string> Echo(string message) => Task.FromResult(message);
public async IAsyncEnumerable<int> Counter(int count, int delay)
{
for (var i = 0; i < count; i++)
{
yield return i;
await Task.Delay(delay);
}
}
}
Bowire discovers two methods:
Echo-- unary, takes a string parameter, returns a stringCounter-- server streaming, takes two int parameters, streams int responses
See also: Quick Start, Duplex Channels