| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [View Raw Code] [Original HTTPS Page] |
This document shows how to use the Events channel with reactive patterns.
The Events property exposes a ChannelReader<FileSystemEvent> which can be consumed directly:
var monitor = ResilientFileSystemMonitor
.Watch(@"C:\data")
.Build();
await foreach (var evt in monitor.Events.ReadAllAsync())
{
Console.WriteLine($"{evt.Kind}: {evt.FullPath}");
}var monitor = ResilientFileSystemMonitor
.Watch(@"C:\data")
.Build();
var lastProcessed = new Dictionary<string, DateTime>();
var throttleWindow = TimeSpan.FromMilliseconds(500);
await foreach (var evt in monitor.Events.ReadAllAsync())
{
if (evt.Kind == FileSystemEventKind.Changed)
{
var now = DateTime.UtcNow;
if (!lastProcessed.TryGetValue(evt.FullPath, out var last) ||
now - last > throttleWindow)
{
lastProcessed[evt.FullPath] = now;
Console.WriteLine($"Processing: {evt.FullPath}");
await ProcessFileAsync(evt.FullPath);
}
}
}If you want advanced reactive operators like Throttle, Buffer, DistinctUntilChanged, etc., you can convert the channel to an Observable:
dotnet add package System.Reactiveusing System.Reactive.Linq;
using System.Threading.Channels;
public static class ChannelExtensions
{
public static IObservable<T> AsObservable<T>(this ChannelReader<T> reader)
{
return Observable.Create<T>(async (observer, ct) =>
{
try
{
await foreach (var item in reader.ReadAllAsync(ct))
{
observer.OnNext(item);
}
observer.OnCompleted();
}
catch (Exception ex)
{
observer.OnError(ex);
}
});
}
}var monitor = ResilientFileSystemMonitor
.Watch(@"C:\data")
.Build();
var subscription = monitor.Events
.AsObservable()
.Where(e => e.Kind == FileSystemEventKind.Changed)
.Throttle(TimeSpan.FromMilliseconds(500))
.Subscribe(evt =>
{
Console.WriteLine($"Throttled change: {evt.FullPath}");
});
// Later: subscription.Dispose();var subscription = monitor.Events
.AsObservable()
.Buffer(TimeSpan.FromSeconds(5))
.Where(batch => batch.Any())
.Subscribe(batch =>
{
Console.WriteLine($"Processing batch of {batch.Count} events");
foreach (var evt in batch)
{
Console.WriteLine($" - {evt.Kind}: {evt.FullPath}");
}
});var subscription = monitor.Events
.AsObservable()
.Where(e => e.Kind == FileSystemEventKind.Changed)
.GroupBy(e => e.FullPath)
.SelectMany(group => group.Throttle(TimeSpan.FromMilliseconds(500)))
.Subscribe(evt =>
{
Console.WriteLine($"Distinct change: {evt.FullPath}");
});var monitor = ResilientFileSystemMonitor
.Watch(@"C:\data")
.OnCreated((s, e) => HandleEvent("Created", e.FullPath))
.OnChanged((s, e) => HandleEvent("Changed", e.FullPath))
.OnDeleted((s, e) => HandleEvent("Deleted", e.FullPath))
.OnRenamed((s, e) => HandleEvent("Renamed", e.FullPath))
.OnError((s, e) => HandleEvent("Error", ""))
.Build();Problems:
var monitor = ResilientFileSystemMonitor
.Watch(@"C:\data")
.Build();
await foreach (var evt in monitor.Events.ReadAllAsync())
{
switch (evt.Kind)
{
case FileSystemEventKind.Created:
case FileSystemEventKind.Changed:
case FileSystemEventKind.Deleted:
case FileSystemEventKind.Renamed:
HandleEvent(evt.Kind.ToString(), evt.FullPath);
break;
case FileSystemEventKind.Error:
HandleError(evt.Exception);
break;
}
}Benefits:
The Events channel uses an unbounded channel internally, so there's no performance penalty. Events are queued in memory and delivered as fast as your consumer can process them. The traditional event handlers still work exactly as before - both APIs can be used simultaneously if needed.
| Back | FazBrowse Home | New Git URL |