DragoAnt.System.Text.Json.Observer
2.0.0-beta.1
dotnet add package DragoAnt.System.Text.Json.Observer --version 2.0.0-beta.1
NuGet\Install-Package DragoAnt.System.Text.Json.Observer -Version 2.0.0-beta.1
<PackageReference Include="DragoAnt.System.Text.Json.Observer" Version="2.0.0-beta.1" />
<PackageVersion Include="DragoAnt.System.Text.Json.Observer" Version="2.0.0-beta.1" />
<PackageReference Include="DragoAnt.System.Text.Json.Observer" />
paket add DragoAnt.System.Text.Json.Observer --version 2.0.0-beta.1
#r "nuget: DragoAnt.System.Text.Json.Observer, 2.0.0-beta.1"
#:package DragoAnt.System.Text.Json.Observer@2.0.0-beta.1
#addin nuget:?package=DragoAnt.System.Text.Json.Observer&version=2.0.0-beta.1&prerelease
#tool nuget:?package=DragoAnt.System.Text.Json.Observer&version=2.0.0-beta.1&prerelease
DragoAnt.System.Text.Json.Observer
Mask or extract JSON values by property-path rules in a single streaming pass from Utf8JsonReader to Utf8JsonWriter — no deserialization, no DOM. Built for logging: it never throws, even on cut-off or invalid JSON, and never writes a masked value in clear.
Targets net8.0 and net10.0; depends only on DragoAnt.Observer.Core, whose DragoAnt.Observer namespace (MaskTag, MaskResult, ValuePolicy, …) the package imports into every C# file (<DragoAntObserverImplicitUsing>false</DragoAntObserverImplicitUsing> opts out).
Quick start
using DragoAnt.System.Text.Json.Observer;
using static DragoAnt.Observer.ValuePolicy;
using static DragoAnt.System.Text.Json.Observer.JsonValuePolicy;
var masker = JsonObserver.Obj(AnyDepth(rules => rules
.Match("password").Mask("***")
.Path("card", "number").Mask(MaskTag.Last4),
BlockList));
Console.WriteLine(masker.Mask("""{"user":"alice","password":"s3cret","card":{"number":"4111111111111111"}}"""));
// Output:
// {"user":"alice","password":"***","card":{"number":"***1111"}}
Build an observer once and share it: it is thread-safe. AnyDepth rules match the end of a property's path at any depth; rules passed straight to JsonObserver.Obj(root => …) follow the path from the root. Values no rule names get the default policy: AllowList (the default) writes every string, number and boolean as "***", BlockList writes them unchanged, NullList as null.
Every Mask* rule masks the whole value whatever its JSON type; an object or array under a mask rule is skipped unread.
Mask and extract
using DragoAnt.System.Text.Json.Observer;
var observer = JsonObserver.Obj<Order>(
rules => rules
.Match("id").ReadInt((id, order) => order.Id = id)
.Match("card").Mask("***"),
ValuePolicy.BlockList);
var order = new Order();
Console.WriteLine(observer.Mask("""{"id":42,"card":"4111111111111111"}""", order));
Console.WriteLine(order.Id);
// Output:
// {"id":42,"card":"***"}
// 42
sealed class Order
{
public int? Id { get; set; }
}
Cut-off JSON and the UTF-8 API
MaskResult.Status is Masked, Truncated (the payload ended early, hit MaxOutputBytes, or a string was cut to MaxValueBytes), Invalid or Unrecognized. Whatever the status, the output is valid JSON holding only masked values. The string and the UTF-8 API produce the same output.
using System.Buffers;
using System.Text;
using DragoAnt.System.Text.Json.Observer;
using static DragoAnt.Observer.ValuePolicy;
using static DragoAnt.System.Text.Json.Observer.JsonValuePolicy;
var masker = JsonObserver.Obj(AnyDepth(rules => rules.Match("password").Mask("***"), BlockList));
var output = new ArrayBufferWriter<byte>(1024);
MaskResult result = masker.Mask("""{"user":"alice","password":"secret","roles":["admin","de"""u8, output);
Console.WriteLine($"{result.Status} {Encoding.UTF8.GetString(output.WrittenSpan)}");
// Output:
// Truncated {"user":"alice","password":"***","roles":["admin"]}
More
- Documentation: rule kinds, custom mask strategies,
Explain(path), allow-lists from your types (JsonShape),ReadOnlySequence<byte>input, options, performance. - Changelog, including the breaking changes from 1.x.
DragoAnt.System.Text.Json.Observer.Httplogs maskedHttpClientrequest and response bodies.- Issues
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- DragoAnt.Observer.Core (>= 1.0.0-beta.1)
-
net8.0
- DragoAnt.Observer.Core (>= 1.0.0-beta.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on DragoAnt.System.Text.Json.Observer:
| Package | Downloads |
|---|---|
|
DragoAnt.System.Text.Json.Observer.Http
HTTP message handler and extensions for logging and masking JSON request and response bodies using DragoAnt.System.Text.Json.Observer. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-beta.1 | 70 | 10/22/2026 |
| 1.0.2 | 267 | 6/5/2025 |