Lesson 5.1: Author a .NET protocol plugin

Difficulty: Intermediate | Duration: 18 min | Prerequisites: Unit 0; .NET 10 SDK

Runnable scaffold. This lesson ships start/ (a plugin that compiles + is discovered but surfaces no services — two TODOs) and completed/ (the working Pirate Speak protocol with a unary Translate method). cd start, fill the TODOs, then diff against completed/. Both build against the published Kuestenlogik.Bowire 2.1.0 package. This hand-written IBowireProtocol is the same shape dotnet new bowire-plugin emits — minus the test project + CI the template adds.

Overview

Build a protocol plugin, pack it as a NuGet, install it, and watch a fresh workbench discover it on startup. The contract is small: implement IBowireProtocol, ship the assembly, and Bowire's plugin pipeline does the rest.

Steps

1. Scaffold from the template

dotnet new install Kuestenlogik.Bowire.Templates
dotnet new bowire-plugin \
  -n Bowire.Plugin.Pirate --ProtocolId pirate \
  --DisplayName "Pirate Speak" --PluginClassName PirateProtocol --Author "You"
cd Bowire.Plugin.Pirate
dotnet build

The scaffold emits a .slnx with the plugin assembly (an IBowireProtocol stub), an xUnit test project asserting the discovered shape, pinned Directory.Packages.props, and a CI workflow.

2. Implement IBowireProtocol

The interface is the whole surface: advertise a service + methods (so discovery can render them), and handle invocation:

  • Discovery — return the services/methods the workbench shows in the sidebar.
  • InvokeAsync — unary call: take the request, return the response.
  • InvokeStreamAsync — server-streaming (yield frames); return an empty stream for unary-only protocols.
  • OpenChannelAsync — bidirectional; return null when unsupported.

Swap the stub's body for real wire work — HttpClient.SendAsync, MQTTnet.PublishAsync, GrpcChannel.ForAddress, or anything else.

Study a real one. Bowire.Protocol.Akka implements IBowireProtocol with a single server-streaming method (Tap/MonitorMessages) that yields TappedMessage envelopes from an Akka.NET mailbox tap — a genuine, shipped plugin with src/, tests/ and samples/ you can read end to end.

3. Pack + install (CLI shape)

dotnet pack -c Release -o nupkgs
bowire plugin install Bowire.Plugin.Pirate --source ./nupkgs
bowire plugin list

bowire plugin also covers download (offline nupkgs), uninstall, update, and inspect. Restart the workbench — your protocol appears in the sidebar.

4. Or reference it in an embedded host

In an embedded host (Unit 4), a plain <PackageReference Include="Bowire.Plugin.Pirate" /> is enough — AddBowire() discovers registered IBowireProtocol implementations through DI. Same NuGet, two install paths.

Key Takeaways

  1. IBowireProtocol is the contract — discovery + InvokeAsync / InvokeStreamAsync / OpenChannelAsync.
  2. dotnet new bowire-plugin scaffolds everything; dotnet packbowire plugin install (CLI) or PackageReference (embedded).
  3. Bowire.Protocol.Akka is a real, complete example to learn from.

What's Next

Continue:Lesson 5.2: Polyglot sidecar plugin

Reference