Building a C# Client
C# is an industry standard for enterprise applications and Windows-based service architectures.
A simple file poller
This console application uses a simple loop to monitor the SUB_DIR for new, non-hidden files.
using System;
using System.IO;
using System.Linq;
using System.Threading;
// 🔥 set this to the path configured in your hypermass-config.yaml subscription-targets
const string SUB_DIR = @"<<YOUR PATH HERE>>";
Console.WriteLine($"Monitoring Hypermass folder {SUB_DIR}...");
while (true)
{
ScanAndProcess();
Thread.Sleep(5000); // Wait 5 seconds
}
void ScanAndProcess()
{
var dir = new DirectoryInfo(SUB_DIR);
if (!dir.Exists) return;
// List files, ignoring hidden files (like .hypermass metadata)
// Sort by LastWriteTime (oldest first)
var files = dir.GetFiles()
.Where(f => !f.Attributes.HasFlag(FileAttributes.Hidden) && !f.Name.StartsWith("."))
.OrderBy(f => f.LastWriteTime)
.ToList();
foreach (var file in files)
{
Console.WriteLine($"Processing: {file.Name}");
try
{
// ⚠️⚠️⚠️ YOUR LOGIC HERE ⚠️⚠️⚠️
// string content = File.ReadAllText(file.FullName);
// Delete once processed
file.Delete();
}
catch (Exception ex)
{
Console.WriteLine($"Error processing {file.Name}: {ex.Message}");
// Break to preserve order - try again on next scan
break;
}
}
}
About this code
We suggest starting with this and modifying it to suit your needs. Some notes about the approach;
- LINQ Filtering: We use
.Whereto easily filter out hidden files including the.hypermassmetadata folder. - LastWriteTime Sorting: Using
OrderBy(f => f.LastWriteTime)ensures that data is processed in the sequence it was received on disk. - Atomic Safety: Because the Hypermass CLI performs an atomic "Move" into the directory,
file.Delete()will not interfere with active writes.
The hypermass sync command relies on the hidden .hypermass directory for tracking progress. The logic above ensures your code ignores this system folder while keeping it intact.
How to productionize this code example
Moving from a Console App to a robust production service:
Small file subscriptions
For standard JSON or XML files, File.ReadAllText() or File.ReadAllBytes() is usually sufficient for files up to
50MB at low message cadences.
Large file subscriptions
If you are processing larger files, use FileStream to avoid memory exhaustion:
- JSON: Use System.Text.Json with
Utf8JsonReaderfor high-performance streaming. - XML: Use XmlReader for a memory-efficient "forward-only" stream.
Stop on fail
In the example above, the break inside the catch block is intentional - you may want to go further and stop the
poller completely. In many enterprise scenarios, if payload #5 fails, you should not move on to payload #6 until the
issue is resolved to maintain data integrity.
Structure
You'll likely want to convert this over to a class based approach so that you can more easily control and interact with various instances.
Using Worker Services
For a modern .NET approach to persistent background services, you may want to wrap this logic in a BackgroundService.
This simplifies the management of the background thread and integrates well with the program life cycle.
public class HypermassSubscriptionWorker : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
ScanAndProcess();
await Task.Delay(5000, stoppingToken);
}
}
}