Class BowireGrpcProtocol

Namespace
Kuestenlogik.Bowire.Protocol.Grpc
Assembly
Kuestenlogik.Bowire.Protocol.Grpc.dll

gRPC protocol plugin for Bowire. Discovers services via gRPC Server Reflection and invokes methods using dynamic protobuf marshalling.

Implements IBowireProtocolServices so that builder.Services.AddBowire() automatically registers AddGrpcReflection() and app.MapBowire() maps MapGrpcReflectionService() — no manual setup required.

public sealed class BowireGrpcProtocol : IBowireProtocol, IBowireProxySupport, IBowireProtocolServices, IBowireStreamingWithWireBytes
Inheritance
BowireGrpcProtocol
Implements
Inherited Members

Constructors

BowireGrpcProtocol()

public BowireGrpcProtocol()

Fields

TransportMetadataKey

Metadata key callers use to opt into gRPC-Web transport for a single call. Value is "web" (case-insensitive) for gRPC-Web, anything else (or absence) for the default native HTTP/2 gRPC. Symmetric to the grpcweb@ URL hint, which Bowire's discovery + invoke endpoints translate into this header before dispatching to the plugin.

Spelled X-Bowire-Grpc-Transport so it travels safely through every HTTP intermediary as a regular request header — gRPC strips HTTP/2 pseudo-headers, but custom x--prefixed entries pass through both native gRPC trailers and gRPC-Web's HTTP framing.

public const string TransportMetadataKey = "X-Bowire-Grpc-Transport"

Field Value

string

Properties

Description

One-line description shown next to the plugin's display name in Settings → Plugins. Optional; defaults to empty so the row falls back to "DisplayName + version" without the description line. Keep it short (≤ 100 characters) — the row truncates anything wider than the manage panel.

public string Description { get; }

Property Value

string

DescriptionKey

#691 — optional catalogue key for Description. When the workbench's active locale has an entry for it, that entry is shown; otherwise Description is, exactly as before. Third-party plugins leave it empty and keep today's behaviour.

public string DescriptionKey { get; }

Property Value

string

IconSvg

SVG icon for the protocol tab.

public string IconSvg { get; }

Property Value

string

Id

Short identifier (e.g., "grpc", "signalr").

public string Id { get; }

Property Value

string

Name

Protocol name shown in UI tabs.

public string Name { get; }

Property Value

string

ProxyNote

One sentence on what goes direct and why, for Partial and None.

public string? ProxyNote { get; }

Property Value

string

ProxyNoteKey

The catalogue key for ProxyNote (#691): the workbench shows the translation and falls back to the English note.

public string? ProxyNoteKey { get; }

Property Value

string

ProxySupport

How far this plugin's connections follow the proxy.

public BowireProxySupport ProxySupport { get; }

Property Value

BowireProxySupport

Methods

ConfigureServices(IServiceCollection)

Registers gRPC Reflection services so Bowire can discover gRPC services automatically. Called by builder.Services.AddBowire(). Idempotent — safe to call even if the host already called AddGrpcReflection().

public void ConfigureServices(IServiceCollection services)

Parameters

services IServiceCollection

DiscoverAsync(string, bool, IReadOnlyDictionary<string, string>?, CancellationToken)

public Task<List<BowireServiceInfo>> DiscoverAsync(string serverUrl, bool showInternalServices, IReadOnlyDictionary<string, string>? metadata, CancellationToken ct = default)

Parameters

serverUrl string
showInternalServices bool
metadata IReadOnlyDictionary<string, string>
ct CancellationToken

Returns

Task<List<BowireServiceInfo>>

Remarks

Discovery was the one operation with no way to carry configuration, and it is the operation that decides whether anything else can run at all. A gRPC server with reflection switched off could be invoked once a descriptor set was supplied, but could not be enumerated — so a scan could not find the methods it was meant to test, and mTLS-protected servers could not be reflected against at all.

A default implementation that drops the metadata, so a plugin with no per-environment configuration to honour stays exactly as it is. Only a plugin that already reads a marker out of metadata elsewhere has any reason to override it.

DiscoverAsync(string, bool, CancellationToken)

Discover available services and methods.

public Task<List<BowireServiceInfo>> DiscoverAsync(string serverUrl, bool showInternalServices, CancellationToken ct)

Parameters

serverUrl string
showInternalServices bool
ct CancellationToken

Returns

Task<List<BowireServiceInfo>>

Initialize(IServiceProvider?)

Called after registration to inject the app's service provider (embedded mode).

public void Initialize(IServiceProvider? serviceProvider)

Parameters

serviceProvider IServiceProvider

InvokeAsync(string, string, string, List<string>, bool, Dictionary<string, string>?, CancellationToken)

Invoke a unary or client-streaming call.

public Task<InvokeResult> InvokeAsync(string serverUrl, string service, string method, List<string> jsonMessages, bool showInternalServices, Dictionary<string, string>? metadata, CancellationToken ct)

Parameters

serverUrl string
service string
method string
jsonMessages List<string>
showInternalServices bool
metadata Dictionary<string, string>
ct CancellationToken

Returns

Task<InvokeResult>

InvokeStreamAsync(string, string, string, List<string>, bool, Dictionary<string, string>?, CancellationToken)

Invoke a server-streaming or duplex call.

public IAsyncEnumerable<string> InvokeStreamAsync(string serverUrl, string service, string method, List<string> jsonMessages, bool showInternalServices, Dictionary<string, string>? metadata, CancellationToken ct)

Parameters

serverUrl string
service string
method string
jsonMessages List<string>
showInternalServices bool
metadata Dictionary<string, string>
ct CancellationToken

Returns

IAsyncEnumerable<string>

InvokeStreamWithFramesAsync(string, string, string, List<string>, bool, Dictionary<string, string>?, CancellationToken)

Binary-aware server-streaming invocation. Yields each frame's wire bytes alongside its JSON rendering so the Bowire recorder can persist the binary payload per frame — Phase-2d gRPC-streaming mock replay needs the original bytes to re-emit without runtime JSON→protobuf re-encoding.

public IAsyncEnumerable<StreamFrame> InvokeStreamWithFramesAsync(string serverUrl, string service, string method, List<string> jsonMessages, bool showInternalServices, Dictionary<string, string>? metadata, CancellationToken ct)

Parameters

serverUrl string
service string
method string
jsonMessages List<string>
showInternalServices bool
metadata Dictionary<string, string>
ct CancellationToken

Returns

IAsyncEnumerable<StreamFrame>

MapDiscoveryEndpoints(IEndpointRouteBuilder)

Maps the gRPC Reflection endpoint so clients (including Bowire's own discovery) can query the server's service descriptors at runtime. Called by app.MapBowire().

public void MapDiscoveryEndpoints(IEndpointRouteBuilder endpoints)

Parameters

endpoints IEndpointRouteBuilder

OpenChannelAsync(string, string, string, bool, Dictionary<string, string>?, CancellationToken)

Open an interactive channel (for duplex/client-streaming).

public Task<IBowireChannel?> OpenChannelAsync(string serverUrl, string service, string method, bool showInternalServices, Dictionary<string, string>? metadata, CancellationToken ct)

Parameters

serverUrl string
service string
method string
showInternalServices bool
metadata Dictionary<string, string>
ct CancellationToken

Returns

Task<IBowireChannel>