NetworkInspector.Limits
0.21.0
dotnet add package NetworkInspector.Limits --version 0.21.0
NuGet\Install-Package NetworkInspector.Limits -Version 0.21.0
<PackageReference Include="NetworkInspector.Limits" Version="0.21.0" />
<PackageVersion Include="NetworkInspector.Limits" Version="0.21.0" />
<PackageReference Include="NetworkInspector.Limits" />
paket add NetworkInspector.Limits --version 0.21.0
#r "nuget: NetworkInspector.Limits, 0.21.0"
#:package NetworkInspector.Limits@0.21.0
#addin nuget:?package=NetworkInspector.Limits&version=0.21.0
#tool nuget:?package=NetworkInspector.Limits&version=0.21.0
NetworkInspector.Limits
Trust-boundary limits for any .NET application. It depends on nothing application-specific: the package references the .NET runtime and no other package.
A limit is a bound that protects your application at a trust boundary: the largest file you read, the deepest nesting you follow, the longest time you wait. Written as a bare constant, a limit is invisible, cannot be changed, and fails without telling anyone why. This package makes each limit one declaration that everything else reads: the setting, the command-line option, the help text, the message when the limit is hit, and any user interface.
What you get
The package has a small core and an optional utility part. The core never uses the utility part.
| Part | Type | What it is |
|---|---|---|
| Core | LimitDefinition |
The record: key, unit, fixed default, hard range, allowOff, readOnly, and seven texts (the title is the UI name). The constructor refuses an inconsistent declaration, such as a default outside the range |
| Core | LimitValue |
A number in the base unit or off; 0 never means off |
| Core | Limit |
The read side of the live holder for hot loops: Ceiling is one volatile read, no lock, no allocation; it cannot change the value |
| Core | LimitWriter |
The owner of one Limit and the only way to change it: TrySet checks the range and the flags |
| Core | ILimitUnit |
The seam to the unit of the values: five members; implement it for a unit that is not table-shaped |
| Core | LimitCatalog.Check |
Duplicate keys in a list of definitions |
Utility |
UnitWordSet, TableUnit |
Compose a unit from words: Binary("B"), Decimal("bit/s"), Of("ms").With("s", 1000) |
Utility |
LimitUnits |
The ready units Count, Bytes, Duration |
Utility |
LimitMessages.HitMessage |
One sentence for every hit: what happened, the limit in effect, the key, and how to change it |
| Term | Meaning |
|---|---|
LimitDefinition |
What the limit is (static, shared, immutable) |
LimitValue |
One value of it |
Limit |
The cell that enforcing code reads; it has no way to change itself |
LimitWriter |
Owns one Limit and changes it; create one per consumer, not per definition, and keep it in the store |
Quickstart
Prerequisites: .NET 10 or later.
dotnet add package NetworkInspector.Limits
using NetworkInspector.Limits;
using NetworkInspector.Limits.Utility;
TextWriter output = Console.Out;
// 1. Declare the limit once: key, unit, default, hard range, and the seven texts that explain it.
LimitDefinition maxEntrySize = new(
"archive.maxEntrySize",
LimitUnits.Bytes,
defaultValue: 128L * 1024 * 1024,
minimum: 1024,
maximum: 1L << 40,
new LimitTexts(
Title: "Largest archive entry",
Description: "The largest size of one entry that is read from an archive.",
Reason: "A hostile archive could otherwise claim an entry that uses all memory.",
Benefit: "A broken or hostile archive is refused with a clear message.",
SmallerValues: "Entries above the value are refused: 1 MiB refuses a 2 MiB entry.",
LargerValues: "More memory may be used per entry: 1 GiB lets a 900 MiB entry through.",
OffEffect: "Every entry is accepted and a hostile archive can use all memory."));
// 2. Show the default.
output.WriteLine(maxEntrySize.Format(maxEntrySize.DefaultValue));
// 3. Parse what a user wrote: a whole number with a unit, or off. Everything else is refused with a suggestion.
if (!maxEntrySize.TryParse("256 MiB", out LimitValue chosen, out string? problem))
{
output.WriteLine(problem);
}
output.WriteLine(maxEntrySize.Format(chosen));
if (!maxEntrySize.TryParse("256 MB", out _, out problem))
{
output.WriteLine(problem);
}
// 4. Hold the live value and read it in the hot loop: one volatile read, no allocation, no lookup.
LimitWriter writer = new(maxEntrySize);
Limit live = writer.Limit;
if (!writer.TrySet(chosen, out problem))
{
output.WriteLine(problem);
}
long entrySize = 300L * 1024 * 1024;
if (entrySize > live.Ceiling)
{
// Report the hit with the standard sentence; the application supplies how to change the limit.
output.WriteLine(maxEntrySize.HitMessage("Entry is 300 MiB", live.Value, "Change it with app set archive.maxEntrySize <value>."));
}
// 5. Check the catalog once in a test: duplicate keys.
IReadOnlyList<LimitCatalogProblem> problems = LimitCatalog.Check([maxEntrySize, maxEntrySize]);
output.WriteLine(problems[0].Message);
Output:
128 MiB
256 MiB
archive.maxEntrySize: 'MB' is a decimal unit and is not accepted; use 256 MiB
Entry is 300 MiB. Limit: 256 MiB (setting archive.maxEntrySize). Change it with app set archive.maxEntrySize <value>.
The key 'archive.maxEntrySize' appears twice; a key names one limit.
Value grammar
A user writes a value as a whole number with an optional unit word, or off. Digits may be separated by _ (10_000); case of
off and of unit words is ignored. The parser is a hand-written single pass, so a hostile value cannot make it slow.
| Unit | Unit words | Notes |
|---|---|---|
LimitUnits.Bytes |
B, KiB, MiB, GiB, TiB |
1 KiB = 1024 B; decimal units such as MB are refused with the binary replacement |
LimitUnits.Duration |
ms, s, min, h, d, w |
A word is required; a bare number does not say seconds. A month or a year has no fixed length and is an unknown word |
LimitUnits.Count |
none | A plain whole number |
your own TableUnit |
the words you compose | See the guide |
| any | off |
The limit is switched off; Limit.Ceiling is then long.MaxValue. A definition may refuse it |
No sign, no fraction, no hexadecimal form. An ambiguous or inexact text is refused with the exact text to write instead.
Words compare ignoring case, so Mbit/s and mbit/s are the same word of a decimal set.
What your application decides
The library has no opinion on these; each is a parameter or your own code.
| Decision | Where it enters |
|---|---|
| The default number | defaultValue of the LimitDefinition constructor: one fixed number inside the range, chosen for the machine you size the application for |
| The sentence that says how a user changes a limit | changeHint of LimitMessages.HitMessage (required) |
| Who may change a limit, and through which front end | Your settings and your command line; the library only parses and validates |
Whether a limit offers off to your users |
allowOff of the constructor (default true); a ceiling that protects other users says false |
| Whether a limit can change after creation | readOnly of the constructor (default false); a read-only limit accepts only its default |
| Units of your domain (frames, connections, bit rates) | new TableUnit(...) with a UnitWordSet, or your own ILimitUnit |
Build and test
dotnet build NetworkInspector.Limits/NetworkInspector.Limits.csproj -c Release
dotnet test NetworkInspector.Limits.Tests/NetworkInspector.Limits.Tests.csproj -c Release
Documentation
Guide: declare, expose, and report a limit
License
MIT. See the license in the repository root.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on NetworkInspector.Limits:
| Package | Downloads |
|---|---|
|
NetworkInspector.Core
High-performance protocol analysis stack for network packet dissection. Provides the core framework for protocol registration, field trees, packet parsing, and cross-packet indexing. Includes a Roslyn source generator for declarative protocol definitions. |
|
|
NetworkInspector.Settings
Typed application settings for any .NET application: typed values, JSON and text forms, sparse persistence, profiles, and safe concurrent saving. It depends on nothing application-specific. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.21.0 | 68 | 11/10/2026 |