ServiceWire is an RPC library for .NET processes that already trust each other. You write a plain C# interface, implement it once, host it, and call it from another process as if it were local. There is no IDL, no code generator, no attributes and no build step — the client proxy is emitted at runtime from the interface you already have.
| If you want to… | Read |
|---|---|
| Get a host and a client talking in ten minutes | Getting started |
| Know what you can put in a method signature | Designing contracts |
| Choose between named pipes and TCP | Transports and endpoints |
| Send your own types, or swap the serializer | Serialization and compression |
| Authenticate callers and encrypt the link | Security |
| See logs, timings and listener health | Logging and diagnostics |
| Add timing, auditing or retries around a method | Interception |
| Understand what actually goes over the wire | Wire protocol |
| Make it faster, or know what "fast" means here | Performance |
| Move from 6.x to 7.0 | Migrating to 7.0 |
| Fix something that is broken | Troubleshooting |
dotnet add package ServiceWireThe package targets netstandard2.0 and net8.0, so it runs on .NET Framework 4.6.1+, .NET Core, and every modern .NET. The net8.0 assembly has no package dependencies.
Upgrading from 6.x? You can move hosts and clients independently — every mixed pairing interoperates.
// 1. A contract both processes reference
public interface IMath
{
int Add(int a, int b);
}
// 2. An implementation, hosted as a singleton
public class MathService : IMath
{
public int Add(int a, int b) => a + b;
}
// 3. A host
using var host = new TcpHost(8098);
host.AddService<IMath>(new MathService());
host.Open();
// 4. A client
using var client = new TcpClient<IMath>(new TcpEndPoint(new IPEndPoint(IPAddress.Loopback, 8098)));
int sum = client.Proxy.Add(2, 3); // 5Swap TcpHost/TcpClient for NpHost/NpClient and the same code runs over a named pipe. Nothing else changes.
The full three-project walkthrough, including the .csproj files and how to run it, is in Getting started.
- On connect, the client sends the interface's type name and the host answers with a method map: an integer identifier for every method, its parameter types, and the capabilities the host supports. This happens once per interface per endpoint and is cached process-wide.
- On each call, the proxy writes the method identifier and the parameter values, then blocks until the matching response arrives.
- On the host, one thread per connection reads the request, invokes your singleton through a compiled delegate, and writes back the return value plus any
outandrefvalues. - If your method throws, the exception is carried back and rethrown on the caller's thread. The connection stays up.
Two things follow from this that surprise people, so they are worth saying up front:
- Your service is a singleton. One instance answers every client on the host. Make it thread-safe, or guard it yourself. The host does execute one connection's requests in order, but different connections run concurrently.
- Calls are synchronous.
Task-returning methods work, but the task is unwrapped on the wire and your method runs synchronously on a host thread. See Async and Task returns.
| Type | Namespace | What it is |
|---|---|---|
TcpHost |
ServiceWire.TcpIp |
Listens on an IPEndPoint |
TcpClient<T> |
ServiceWire.TcpIp |
Owns a connection; exposes Proxy |
TcpEndPoint |
ServiceWire.TcpIp |
Address plus timeouts and wire options |
TcpZkEndPoint |
ServiceWire.TcpIp |
The same, with a username and password |
NpHost |
ServiceWire.NamedPipes |
Listens on a named pipe |
NpClient<T> |
ServiceWire.NamedPipes |
Owns a pipe connection; exposes Proxy |
NpEndPoint |
ServiceWire.NamedPipes |
Server name, pipe name, timeout, wire options |
Host |
ServiceWire |
Base class: AddService, Open, Close, Status, UseCompression |
ISerializer |
ServiceWire |
Plug in your own object serializer |
ICompressor |
ServiceWire |
Plug in your own compression |
ILog, IStats |
ServiceWire |
Plug in logging and timing |
IZkRepository |
ServiceWire.ZeroKnowledge |
Look up a user's stored password hash |
Interceptor |
ServiceWire.Aspects |
Wrap any local object with pre/post/exception hooks |
These are built and tested on every commit, so they never drift from the library:
| Sample | What it shows |
|---|---|
src/Demo/DemoCommon/Contracts.cs |
A shared contract assembly with complex types and out parameters |
src/Demo/DemoHost/Program.cs |
Hosting four interfaces on one TCP endpoint |
src/Demo/DemoClient/Program.cs |
Client usage, including the zero-knowledge variant |
src/Tests/Unit/ServiceWireTests/TcpTests.cs |
TCP hosting and calls, end to end |
src/Tests/Unit/ServiceWireTests/NpTests.cs |
The same over named pipes |
src/Tests/Unit/ServiceWireTests/TcpZkTests.cs |
Zero-knowledge authentication |
src/Tests/Unit/ServiceWireTests/InterceptionTests.cs |
Cross-cutting concerns |
src/Tests/Unit/ServiceWireTests/PipeliningTests.cs |
Many threads sharing one proxy |
src/Tests/Unit/ServiceWireTests/AsyncTests.cs |
A custom serializer and a thrown exception |