// 3. Post‑hook (e.g., logging, decryption, metrics) await _hook.AfterReadAsync(_ctx, destination.Slice(0, bytesRead), cancellationToken) .ConfigureAwait(false);
The pattern mirrors Read ; the hook receives the buffer before the inner write and again after the write completes. 3.4 Seek , SetLength , Flush All these methods follow the same pre‑hook → inner operation → post‑hook flow. The async variants are implemented using ValueTask when possible to avoid allocations. 3.5 Disposal protected override void Dispose(bool disposing) StreamFab.KeepStreams.Generic.Hook-Smeagol-TheR...
// 2. Actual read from inner stream int bytesRead = await _inner.ReadAsync(destination, cancellationToken) .ConfigureAwait(false); The async variants are implemented using ValueTask when
public void BeforeWrite(IHookContext ctx, byte[] buffer, int offset, int count) /* … */ public void AfterWrite(IHookContext ctx, byte[] buffer, int offset, int count) /* … */ public void BeforeWrite(IHookContext ctx
if (disposing) // Hook gets notified first – it can release its own resources _hook.Dispose(_ctx);
services.AddSingleton<IHookFactory<MyCustomHook>, MyCustomHookFactory>(); services.AddTransient(typeof(Stream), provider =>