Getting Started
This tutorial walks you through creating a simple client-server application using WitRPC. We will build a basic calculator service that exposes Add and Subtract methods. For simplicity, this example uses the Named Pipes transport, which is ideal for communication between processes on the same Windows machine.
Prerequisites
Before you begin, make sure you have the following installed:
-
.NET 6 SDK (or later).
-
IDE such as Visual Studio 2022 or Visual Studio Code.
-
OutWit.Communication NuGet package - you can add it to your project using the .NET CLI:
dotnet add package OutWit.Communication
Step 1: Defining the Service Contract
The first step in any WitRPC application is to define the service contract - a shared C# interface that both the server and client will use.
-
Create a new Class Library project named
Calculator.Shared. -
In that project, add a new interface file named
ICalculatorService.cs. -
Define an interface with the methods you want to expose remotely. For example:
// In Calculator.Shared/ICalculatorService.cs
namespace Calculator.Shared;
public interface ICalculatorService
{
Task<int> Add(int a, int b);
Task<int> Subtract(int a, int b);
}
This interface serves as the formal contract for our calculator service.
Step 2: Building and Hosting the Server
Next, create the server application that implements and hosts ICalculatorService:
-
Create a new Console App project named
Calculator.Server. -
Add a reference to the
Calculator.Sharedproject. -
Add the OutWit.Communication NuGet package to this project.
-
Create a class
CalculatorService.csin the server project that implements theICalculatorServiceinterface. For example:// In Calculator.Server/CalculatorService.cs
using Calculator.Shared;
namespace Calculator.Server;
public class CalculatorService : ICalculatorService
{
public Task<int> Add(int a, int b)
{
Console.WriteLine($"Received Add request for {a} + {b}");
return Task.FromResult(a + b);
}
public Task<int> Subtract(int a, int b)
{
Console.WriteLine($"Received Subtract request for {a} - {b}");
return Task.FromResult(a - b);
}
} -
Open
Program.csin the server project and configure the WitRPC server usingWitServerBuilder:// In Calculator.Server/Program.cs
using Calculator.Server;
using OutWit.Communication.Server;
Console.WriteLine("--- Calculator Server ---");
// 1. Instantiate the service implementation.
var serviceImplementation = new CalculatorService();
// 2. Configure and build the server.
var server = WitServerBuilder.Build(options =>
{
// 2a. Register the service implementation.
options.WithService(serviceImplementation);
// 2b. Choose the transport (use a Named Pipe called "CalculatorPipe").
options.WithNamedPipe("CalculatorPipe");
// 2c. Choose the serializer (JSON for simplicity).
options.WithJson();
// 2d. Enable built-in encryption for secure communication.
options.WithEncryption();
// 2e. Set a communication timeout.
options.WithTimeout(TimeSpan.FromSeconds(5));
});
// 3. Start the server and wait for incoming connections.
server.StartWaitingForConnection();
Console.WriteLine("Server started. Listening on pipe 'CalculatorPipe'. Press any key to exit.");
Console.ReadKey();
// 4. Stop the server gracefully.
server.StopWaitingForConnection();
Console.WriteLine("Server stopped.");
When you run the server application, it starts a WitRPC server listening on the named pipe CalculatorPipe.
Step 3: Building the Client and Consuming the Service
Finally, create the client application that will connect to the server and use the calculator service:
-
Create a new Console App project named
Calculator.Client. -
Add a reference to the
Calculator.Sharedproject. -
Add the OutWit.Communication NuGet package to this project.
-
Open
Program.csin the client project and useWitClientBuilderto configure the client and connect to the server:// In Calculator.Client/Program.cs
using Calculator.Shared;
using OutWit.Communication.Client;
using OutWit.Communication.Exceptions;
Console.WriteLine("--- Calculator Client ---");
// 1. Configure and build the client.
var client = WitClientBuilder.Build(options =>
{
// 1a. Match the server's transport.
options.WithNamedPipe("CalculatorPipe");
// 1b. Use the same serializer as the server.
options.WithJson();
// 1c. Enable encryption to match the server.
options.WithEncryption();
// 1d. Set the communication timeout.
options.WithTimeout(TimeSpan.FromSeconds(5));
});
try
{
// 2. Connect to the server.
Console.WriteLine("Connecting to the server...");
if (!await client.ConnectAsync(TimeSpan.FromSeconds(10), CancellationToken.None))
{
Console.WriteLine("Failed to connect to the server.");
return;
}
Console.WriteLine("Successfully connected!");
// 3. Get a proxy object for the remote service.
// This is where the magic happens�'calculator' is a local object
// that forwards calls to the remote server.
var calculator = client.GetService<ICalculatorService>();
// 4. Call the remote methods as if they were local.
int sum = await calculator.Add(10, 5);
Console.WriteLine($"Result of Add(10, 5): {sum}");
int difference = await calculator.Subtract(10, 5);
Console.WriteLine($"Result of Subtract(10, 5): {difference}");
}
catch (WitException ex)
{
// 5. Handle potential communication errors.
Console.WriteLine($"An error occurred: {ex.Message}");
}
finally
{
// 6. Disconnect and dispose of the client.
await client.DisconnectAsync();
Console.WriteLine("Client disconnected. Press any key to exit.");
Console.ReadKey();
}
To run the full application, start the Calculator.Server application first. Once the server is running and listening, launch Calculator.Client. The client will connect to the server, perform the calculations, print the results, and then disconnect.