WormholeRelay.Server 0.2.2

dotnet add package WormholeRelay.Server --version 0.2.2
                    
NuGet\Install-Package WormholeRelay.Server -Version 0.2.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="WormholeRelay.Server" Version="0.2.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="WormholeRelay.Server" Version="0.2.2" />
                    
Directory.Packages.props
<PackageReference Include="WormholeRelay.Server" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add WormholeRelay.Server --version 0.2.2
                    
#r "nuget: WormholeRelay.Server, 0.2.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package WormholeRelay.Server@0.2.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=WormholeRelay.Server&version=0.2.2
                    
Install as a Cake Addin
#tool nuget:?package=WormholeRelay.Server&version=0.2.2
                    
Install as a Cake Tool

WormholeRelay

NuGet Downloads build

Debug a deployed ASP.NET Core application on your own machine, without redeploying.

Add two lines to your app, connect the desktop client, and incoming HTTP requests are handed to a locally running copy of the same application — so you can set breakpoints on real traffic from a real client. Disconnect and the deployed app serves requests itself again.

It exists for the case where you cannot run the caller locally: the site calling your API is built by another team, or lives in an environment you do not control, and your only feedback loop is a slow deploy.

   browser / caller ──▶  your deployed app  ──(SignalR)──▶  WormholeRelay client  ──▶  localhost
                              (interceptor)                   (on your machine)        (breakpoints)

Install — two halves, and they only work together

Neither piece does anything on its own. The server package goes into the application you want to debug and can intercept requests, but only ever hands them to a client that has connected. The desktop client runs on your machine, holds the tunnel open and replays each request against your localhost. Without the client, the deployed app behaves exactly as it always did.

Where it goes How you get it
WormholeRelay.Server the deployed application dotnet add package WormholeRelay.Server
WormholeRelay.exe your own Windows machine latest release

Both are built and published from the same commit, so keep them on the same version. They agree on hub method names through the shared WormholeRelay.Contracts assembly; if those names ever change between versions, a mismatched pair connects and then quietly fails to relay anything.

The client is portable and self-contained: double-click the .exe and it runs. No installer, no admin rights, and no .NET needed on the machine. Delete the file to uninstall. Its title bar shows the version, which is the only way to tell two downloaded copies apart.

Wire it up

// Only register it where you intend to allow it. The package treats no environment as special,
// so this check is your policy.
if (builder.Environment.IsEnvironment("Test"))
    builder.Services.AddWormholeRelay(builder.Configuration, builder.Environment);

// ...

// Early in the pipeline: after CORS so browser callers still get their headers, but before response
// compression and authentication so requests are forwarded exactly as they arrived.
if (app.Environment.IsEnvironment("Test"))
    app.UseWormholeRelay();

Then configure it:

"WormholeRelay": {
  "Enabled": true,
  "AllowedEnvironments": [ "Test" ],   // no default: unset means the relay cannot start
  "JoiningKey": "<a long random secret>",
  "MaxSessionMinutes": 45,
  "RoutePrefixes": []                  // empty = all traffic; narrow it on a shared environment
}

Both extension methods are safe to call unconditionally — they do nothing unless enabled — but gating them as above means the relay is not even registered elsewhere.

Using the client

Start your local copy of the application first, then run WormholeRelay.exe, fill in the fields and press Connect. The status line next to the button reports what is actually happening — connecting, connected with the session expiry, or the reason it was refused.

Field What it is Example
Server URL the deployed application you want to divert https://your-app.example.com
Hub path must match HubPath on the server /hubs/wormhole-relay
Joining key the JoiningKey from the server's configuration masked as you type
Local redirect URL your locally running copy, the target for replayed requests https://localhost:5001
Log folder where the session log file is written C:\LogFiles\WormholeRelay

Remember key stores the joining key between runs; clear it and you retype the key each time. Enable logging writes the file, Verbose adds full header and body detail, and Open opens the log folder in Explorer. The live pane mirrors the same information, with Copy and Clear beside it.

Everything except the key is stored as plain JSON per Windows user under %APPDATA%\WormholeRelay. The key itself is encrypted with DPAPI, so it is readable only by your Windows account on that machine — not held in the clear, and not portable to another user or PC.

Press Disconnect when you are done. That releases the session on the server immediately rather than leaving it to time out, and traffic goes back to the deployed app. Closing the window does the same.

What the log gives you

A daily rolling file, with a blank line between requests: method, path, query string, every header and a body preview, then the response status, headers and how long your local machine took. Authorization values are recorded as present-but-hidden rather than written out, and binary bodies are noted by size instead of dumped.

It is the record of what actually crossed the wire, which makes it the first place to look when a request behaves differently through the relay than it did against the deployed app. It also means the file can hold real request data — see below.

Read this before enabling it anywhere shared

  • A connected client receives all traffic for the host, not just yours. On a shared test environment you are diverting your colleagues' requests too. Use RoutePrefixes to narrow it.
  • The joining key is a real credential. Anyone holding it can redirect that host's traffic to their own machine. Keep it in a secret store, not in source control, and rotate it if it leaks.
  • Sessions expire after MaxSessionMinutes and only one is active at a time, so a forgotten client cannot hold traffic indefinitely.
  • Never enable it in production. The package deliberately contains no special case for an environment named "Production" — that policy belongs to your host, so make your registration condition narrow and keep it that way.
  • Every failure path falls through to normal handling: no client connected, a request that times out, a body over the size limit, or a local target that cannot be reached all mean "the deployed app answers as usual".

Responsible use, and your own risk

Be clear-eyed about what this tool is. To divert traffic it has to intercept HTTP requests and replay them somewhere else, and the requests it carries are real ones from real callers. That is a debugging aid on a system you control, and it is wiretapping on one you do not. The mechanism does not know the difference — you do.

Use it only where you are authorised to. Run it against systems you own, or where the owner has given you permission to debug. Pointing it at anyone else's service, or using it to capture traffic you have no right to see, is unauthorised interception of communications and is a criminal offence in most jurisdictions. Do not use it to intercept credentials, harvest data, bypass access controls, or watch other people's sessions. Nothing about the tool being open source changes any of that.

It is for debugging, and nothing else. It is not a proxy, not a load balancer, not a tunnelling service, and not a way to expose a private machine to the internet. It has no throughput guarantees, no chunking for large bodies and a hard session timeout, because none of those matter for stepping through a request in a debugger — and all of them matter for anything you might mistake it for.

Real data will pass through your machine. Requests are replayed on your PC and, with logging on, written to a file there. On any environment carrying live or production-like data, that means personal data leaves its controlled environment and lands on a laptop. Check that this is allowed under your organisation's data-protection rules before you connect, keep the log folder off shared drives, and delete logs when you are finished with them.

No warranty. This is MIT-licensed software provided as is, with no warranty of any kind, express or implied. Running it means you accept the risk: a diverted environment is a broken environment for anyone else using it, and misconfiguring it in a place it does not belong is your responsibility. The authors are not liable for lost data, downtime, leaked information or anything else that follows from using it. Read the licence — the disclaimer there is the binding version of this paragraph.

If you are unsure whether a particular use is legitimate, the honest test is simple: could you explain what you are doing to the owner of that system and to whoever's traffic you are diverting, and would both agree? If not, do not do it.

Try it without a deployed app

WormholeRelay.TestHost runs both ends on one machine — a stand-in "remote" on port 5099 with the relay enabled, and a stub local target on 5098 with a live request monitor page:

dotnet run --project WormholeRelay.TestHost

It prints the exact values to type into the client. Open http://localhost:5098/ to watch requests arrive in real time, then curl http://localhost:5099/whoami and see the answer change from REMOTE to LOCAL once you connect.

Projects

Project
WormholeRelay.Server the hub, the interceptor and the extension methods — the NuGet package you install
WormholeRelay.Contracts messages shared by both sides, no dependencies
WormholeRelay.App the WinForms client, published as WormholeRelay.exe
WormholeRelay.TestHost the local rig described above

Limitations

  • Bodies larger than MaxBodyBytes (1 MB by default) are not relayed; those requests are handled by the deployed app instead. Chunking is not implemented.
  • With in-process SignalR the tunnel lives on one instance, so run a single instance while relaying, or set AzureSignalRConnectionString to let any instance reach the connected client.
  • WebSockets must be enabled on the host. On Azure App Service they are off by default.
  • The client is Windows-only, because it is a WinForms application. The server package is not.

Releasing

Every push to main publishes a release. There is no tag to push and no version file to edit: the workflow builds, packs, pushes both packages to NuGet, and creates a GitHub release with the portable executable attached.

Publishing uses trusted publishing, so no API key is stored here. nuget.org exchanges a GitHub OIDC token for a key that lives one hour, which requires a policy on nuget.org naming this repository and release.yml.

Versions are <VersionMajorMinor>.<github run number> — VersionMajorMinor lives in Directory.Build.props and the run number supplies an always-increasing patch. Bump the major or minor by hand for a deliberate feature or breaking release; the patch takes care of itself.

Work on develop or a feature branch, where build proves the solution compiles, both packages pack and the executable publishes — without releasing anything. Merge to main when you want it out.

To rebuild a specific version, run the release workflow manually and give it the version.

License

MIT — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.2 160 8/13/2026
0.2.1 107 8/13/2026
0.1.3 99 8/10/2026
0.1.2 107 8/10/2026