Zonit.Extensions
10.0.0-preview.12
See the version list below for details.
dotnet add package Zonit.Extensions --version 10.0.0-preview.12
NuGet\Install-Package Zonit.Extensions -Version 10.0.0-preview.12
<PackageReference Include="Zonit.Extensions" Version="10.0.0-preview.12" />
<PackageVersion Include="Zonit.Extensions" Version="10.0.0-preview.12" />
<PackageReference Include="Zonit.Extensions" />
paket add Zonit.Extensions --version 10.0.0-preview.12
#r "nuget: Zonit.Extensions, 10.0.0-preview.12"
#:package Zonit.Extensions@10.0.0-preview.12
#addin nuget:?package=Zonit.Extensions&version=10.0.0-preview.12&prerelease
#tool nuget:?package=Zonit.Extensions&version=10.0.0-preview.12&prerelease
Zonit.Extensions
Framework-agnostic value-object foundation for the Zonit.Extensions ecosystem. Trim- and AOT-clean, no ASP.NET Core dependency, no DI registration of any kind — you reference the package and name the types.
dotnet add package Zonit.Extensions
There is no AddZonitExtensions(). Anything that tells you to call a setup method for this package is
wrong.
Every other Zonit.Extensions.* package depends on this one, so these types are always available once
any of them is installed.
What's inside
Everything below is in namespace Zonit.Extensions.
| Category | Types |
|---|---|
| Identity / auth | Identity, Credential, Permission, Role |
| Tenancy | Organization, Project |
| Localization / time | Culture, Zone |
| Money | Price, Money, Currency |
| Text | Title, Description, Content, UrlSlug, Url, UrlPath |
| Files / visual | Asset (+ nested FileName, MimeType, SignatureType), FileSize, Color |
| Time | Schedule |
Plus a few utilities:
BaseException/BaseException<TErrorCode>(also inZonit.Extensions) — i18n-ready errors that keep key, template and parameters separable.Zonit.Extensions.Text— word/sentence counters, reading time, readability, whitespace and smart-quote normalization.Zonit.Extensions.Xml—XmlConvertible, a culture-invariant object ↔ XML helper for flat types.Zonit.Extensions.Reflection—AssemblyProvider, assembly/type scanning (explicitly not AOT-safe; both methods carry[RequiresUnreferencedCode]).
Sole third-party dependency: Diacritics, used by
UrlSlug to fold accented characters.
The shape every value object shares
readonly struct(Urlis a plainstructso it can cache its parsedUri;Scheduleis areadonly record struct)Emptystatic — which isdefault(T)— plus aHasValueflag.Price,MoneyandFileSizeuseZeroinstead;ColorusesTransparent.- A hand-written
JsonConverterattached with[JsonConverter]: no registration, no reflection, no source-generator context needed on your side. - A
TypeConverterfor ASP.NET Core model binding andIConfiguration— exceptPriceandMoney, which you bind asdecimal. IParsable<T>where a string representation makes sense.
The rule that matters most
Constructors and implicit string conversions throw. TryCreate / TryParse do not.
Title t1 = untrustedInput; // ArgumentException past 60 characters
Title.TryCreate(untrustedInput, out var t2); // false, t2 == Title.Empty
And because these are structs, != null compiles and is always true. Test HasValue.
Highlights
Permission — wildcard authorization tokens
Permission read = "orders.read";
Permission writeAll = "orders.*";
writeAll.Implies(read); // true
writeAll.Implies(new Permission("orders")); // true — trailing * matches zero tokens
writeAll.Implies(new Permission("orders.read.all")); // false — and only one token
A trailing * matches zero or one token, not the whole subtree. Drives
[RequirePermission("orders.read")] in Zonit.Extensions.Auth.
Identity — lightweight actor snapshot
var actor = new Identity(
id: userId,
name: new Title("Alice"),
roles: [new Role("admin")],
permissions: [new Permission("orders.*")]);
actor.IsInRole(new Role("admin")); // true
actor.HasPermission("orders.read"); // true (implicit string -> Permission)
actor.HasSnapshot; // true
Equality is by Id only, so a hydrated snapshot equals the bare Identity(id) it came from.
Credential — kind auto-detected from the value
new Credential("alice@example.com").Kind; // CredentialKind.Email
new Credential("+48 600 100 200").Kind; // CredentialKind.Phone (Value "+48600100200")
new Credential("alice").Kind; // CredentialKind.Username
new Credential(Guid.NewGuid()).Kind; // CredentialKind.Id
Input longer than 254 characters is rejected before any regex runs.
Money — culture-free parsing
var inv = CultureInfo.InvariantCulture;
Price.TryParse("19,99", null, out var a); // 19.99
Price.TryParse("19.99", null, out var b); // 19.99 — same value, whatever the host culture
Currency.PLN.Format(19.99m, inv); // "19.99 zł" — symbol after
Currency.USD.Format(19.99m, inv); // "$19.99" — symbol before
Currency.JPY.Format(1999m, inv); // "¥1,999" — 0 decimal digits
Parsing is culture-free by design; formatting is not — Format defaults to
CultureInfo.CurrentCulture for the number part, as do Price.ToString() and Money.ToString().
Asset — MIME from the magic bytes, not the file name
byte[] bytes = await File.ReadAllBytesAsync("upload.pdf");
var asset = new Asset(bytes, "upload.pdf");
asset.Signature; // e.g. SignatureType.Png if the bytes are really a PNG
asset.MediaType; // "image/png" — the content wins over the extension
asset.OriginalName; // "upload.pdf" — preserved as supplied
asset.Validate(AssetValidationOptions.Documents()).Errors;
// "File content is 'image/png' but the name 'upload.pdf' claims 'application/pdf'."
Asset takes ownership of the array you pass in — it does not copy. Do not mutate that array
afterwards.
Color — OKLCH
Color c = "#3498db";
c.Lighten(0.1).Hex; // "#58B8FD"
c.CssOklch; // "oklch(65.31% 0.1347 242.69)"
c.Mix(Color.FromHex("#e74c3c"), 0.5);
Persist Color.Hex, not CssOklch — the OKLCH string does not currently parse back to the same colour.
Persistence
Identity, Organization and Project persist as a single Guid column. Their name/slug/roles
snapshot is not stored and is not lazily loaded — after a plain read, HasSnapshot is false.
Hydration is an explicit, opt-in call in Zonit.Extensions.Databases; these value objects perform no
I/O of their own.
modelBuilder.Entity<Order>()
.Property(o => o.Author)
.HasConversion(v => v.Id, id => id == Guid.Empty ? Identity.Empty : new Identity(id));
Note that HasConversion takes an Expression, so the read side cannot contain an out var
declaration. String-backed value objects need a small static helper — the full recipe set is in the
docs below.
Documentation
The authoritative docs ship inside the package and are installed into a consuming repository's
.zonit/extensions/core/ (plus .cursor/rules/, .github/instructions/ and .claude/skills/ when
those editors are detected) at build time:
| File | Covers |
|---|---|
value-objects.md |
the creation contract, Empty/HasValue, JSON, the EF Core recipes |
auth-value-objects.md |
Identity, Permission, Role, Credential |
money.md |
Price, Money, Currency |
schedule.md |
Schedule, the 20-byte binary format, cron parsing |
assets.md |
Asset, FileSize, Color |
binding.md |
Blazor EditForm and model binding |
exceptions.md |
BaseException, plus the Text / Xml / Reflection utilities |
In this repository they live under
Instruction/extensions/core/. Disable the install with
<ZonitExtInstructions>false</ZonitExtInstructions>.
See also
- Zonit.Extensions.Auth — authorization built on
Permission/Role/Identity. - Zonit.Extensions.Cultures — translations and culture state built on
Culture. - Zonit.Extensions.Organizations — tenant context built on
Organization. - Zonit.Extensions.Projects — project context built on
Project. - Zonit.Extensions.Website — Blazor / ASP.NET Core integration.
License
MIT — see LICENSE.
| 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
- Diacritics (>= 4.1.8)
NuGet packages (10)
Showing the top 5 NuGet packages that depend on Zonit.Extensions:
| Package | Downloads |
|---|---|
|
Zonit.Extensions.Ai.Abstractions
Core abstractions and interfaces for Zonit.Extensions.Ai. Use this package when you only need the interfaces without implementation, perfect for defining prompts in domain layers. |
|
|
Zonit.Extensions.Website
ASP.NET Core and Blazor web extensions providing base components (PageBase, PageEditBase, PageViewBase), navigation services, breadcrumbs management, toast notifications, cookie handling, and data protection utilities for building modern web applications. |
|
|
Zonit.Extensions.Databases.SqlServer
SQL Server provider for Zonit.Extensions.Databases - Entity Framework Core repository with fluent query API, ThenInclude, DTO mapping, and full-text search support. |
|
|
Zonit.Extensions.Tenants
Per-domain tenant identity and settings for Zonit applications: ITenantSource (the data adapter you implement), the scoped ITenantRepository/ITenantProvider pair, plugin-aware Setting<T> models, and a source generator that gives every setting a strongly-typed accessor. Framework-agnostic: no ASP.NET Core dependency and no middleware here. Built on top of Zonit.Extensions value objects. |
|
|
Zonit.Extensions.Cultures
Culture, time-zone and translation services for Zonit applications. Provides ICultureState/ICultureManager (per-scope culture and time zone), ICultureProvider (translation rendering), ITranslationManager and its process-wide registry, ILanguageProvider with 17 built-in languages, and the Translation value object. Framework-agnostic: no HttpContext and no middleware here — the ASP.NET culture middleware lives in Zonit.Extensions.Website. Built on the Culture and TimeZone value objects from Zonit.Extensions. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.0-preview.15 | 40 | 8/7/2026 |
| 10.0.0-preview.14 | 52 | 8/6/2026 |
| 10.0.0-preview.13 | 57 | 8/6/2026 |
| 10.0.0-preview.12 | 48 | 8/6/2026 |
| 10.0.0-preview.11 | 88 | 8/4/2026 |
| 10.0.0-preview.10 | 85 | 8/3/2026 |
| 10.0.0-preview.9 | 128 | 5/16/2026 |
| 10.0.0-preview.6 | 87 | 5/15/2026 |
| 10.0.0-preview.2 | 89 | 5/12/2026 |
| 10.0.0-preview.1 | 84 | 5/8/2026 |
| 0.2.12 | 182 | 5/8/2026 |
| 0.2.11 | 9,207 | 4/19/2026 |
| 0.2.10 | 2,450 | 1/22/2026 |
| 0.2.9 | 457 | 1/21/2026 |
| 0.2.8 | 673 | 1/21/2026 |
| 0.2.7 | 2,259 | 1/16/2026 |
| 0.2.6 | 149 | 1/15/2026 |
| 0.2.4 | 164 | 1/15/2026 |
| 0.2.3 | 159 | 1/15/2026 |
| 0.2.2 | 146 | 1/15/2026 |