Working on engineering systems that often involve legacy components, I frequently face challenges in integrating outdated elements with modern platforms. For example, you may encounter scenarios requiring support for obsolete file formats that can only be opened by a 32-bit component. This limitation poses a dilemma: either remain on an outdated platform, foregoing modern framework advantages like 64-bit addressing, or isolate the legacy component’s logic into a separate process with which the main application communicates.
There are numerous scenarios for inter-process communication (IPC) on the same machine, including:
- Supporting components built for a different platform than the main system.
- Running multiple parallel, independent processes to overcome system limitations.
- Enabling data exchange between several concurrently running applications. Many others.
Why WitCom?
For years, I relied on WCF for its flexibility, particularly its support for selecting optimized transports like named pipes for local interactions. However, WCF was no longer fully available when I migrated to .NET Core. While recent .NET versions have reintroduced support for WCF, its current status remains uncertain.
One of WCF’s standout features was ServiceContract, which allows defining a service interface. This approach simplifies development: a client integrating a WCF service generates the required wrapper code automatically, eliminating guesswork about function names or parameters. Unfortunately, both SignalR and gRPC require method calls using plain text method names, complicating code maintenance.
Enter WitCom
A few years ago, I discovered the IpcServiceFramework, which uses interfaces to define services and leverages reflection to unpack and invoke methods on the service side. While promising, the project was no longer maintained. Inspired by its core concept, I developed my own implementation, which evolved into WitCom.
WitCom is a WCF-like communication framework designed for .NET. It enables developers to define service interfaces, choose a transport, and establish full-duplex communication with minimal effort. Supported transports include common options like Named Pipes, TCP, and WebSocket, as well as unique support for memory-mapped files. This enables ultra-fast, low-latency duplex communication on a local machine, ideal for transferring large volumes of data with maximum efficiency.
Example: Inter-process Communication with WitCom
You can find an example implementation in the WitCom GitHub repository.
Step 1: Define the Service Contract
public interface IExampleService
{
event ExampleServiceEventHandler ProcessingStarted;
event ExampleServiceProgressEventHandler ProgressChanged;
event ExampleServiceProcessingEventHandler ProcessingCompleted;
bool StartProcessing();
void StopProcessing();
}
public delegate void ExampleServiceEventHandler();
public delegate void ExampleServiceProgressEventHandler(double progress);
public delegate void ExampleServiceProcessingEventHandler(ProcessingStatus status);
WitCom supports full-duplex communication natively using event callbacks, with any delegate type (e.g., PropertyChangedEventHandler
) supported.
Step 2: Implement the Service in the Agent
The agent process hosts the service:
public class ExampleService : IExampleService
{
public event ExampleServiceEventHandler ProcessingStarted = delegate { };
public event ExampleServiceProgressEventHandler ProgressChanged = delegate { };
public event ExampleServiceProcessingEventHandler ProcessingCompleted = delegate { };
private CancellationTokenSource? CancellationTokenSource { get; set; }
public bool StartProcessing()
{
if (CancellationTokenSource != null) return false;
CancellationTokenSource = new CancellationTokenSource();
Task.Run(Process);
ProcessingStarted();
return true;
}
public void StopProcessing()
{
CancellationTokenSource?.Cancel();
}
private void Process()
{
ProcessingStatus status = ProcessingStatus.Success;
for (int i = 1; i <= 100; i++)
{
if (CancellationTokenSource?.IsCancellationRequested == true)
{
status = ProcessingStatus.Interrupted;
break;
}
ProgressChanged(i);
Thread.Sleep(100);
}
ProcessingCompleted(status);
CancellationTokenSource = null;
}
}
Step 3: Start the Agent Process
The host process launches the agent as a separate process, passing the communication address via command-line arguments. For example:
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "Agent.exe",
Arguments = "--address=ExampleMemoryMap",
UseShellExecute = false,
}
};
process.Start();
Step 4: Start the Server in the Agent
The agent starts the server and listens for connections using the received address:
var server = WitComServerBuilder.Build(options =>
{
options.WithService(new ExampleService());
options.WithMemoryMappedFile("ExampleMemoryMap");
options.WithEncryption();
options.WithJson();
options.WithAccessToken("SecureAccessToken");
options.WithTimeout(TimeSpan.FromSeconds(1));
});
server.StartWaitingForConnection();
Step 5: Create the Client in the Host
The host process connects to the agent:
var client = WitComClientBuilder.Build(options =>
{
options.WithMemoryMappedFile("ExampleMemoryMap");
options.WithEncryption();
options.WithJson();
options.WithAccessToken("SecureAccessToken");
options.WithTimeout(TimeSpan.FromSeconds(1));
});
if (!await client.ConnectAsync(TimeSpan.FromSeconds(5), CancellationToken.None))
{
Console.WriteLine("Failed to connect.");
return;
}
var service = client.GetService<IExampleService>();
service.ProcessingStarted += () => Console.WriteLine("Processing started!");
service.ProgressChanged += progress => Console.WriteLine($"Progress: {progress}%");
service.ProcessingCompleted += status => Console.WriteLine($"Processing completed: {status}");
Key Advantages of WitCom
- Service Contracts: Define service interfaces for a clean and maintainable API.
- Multiple Transports: Choose from Named Pipes, TCP, WebSocket, or memory-mapped files.
- Full-Duplex Communication: Events and callbacks are natively supported.
- Encryption: Secure communication with AES/RSA-based encryption.
- Authorization: Token-based authentication ensures only authorized clients can connect.
- High Performance: Optimize IPC for the local machine using memory-mapped files.
- Easy Error Handling: Use WitComExceptionFault to handle communication errors.
Conclusion
WitCom is a robust and modern alternative for inter-process communication in .NET, combining the best features of WCF with modern transport options. For more information, visit WitCom’s documentation and explore examples on GitHub.
Top comments (0)