Zonit.Extensions 10.0.0-preview.15

This is a prerelease version of Zonit.Extensions.
dotnet add package Zonit.Extensions --version 10.0.0-preview.15
                    
NuGet\Install-Package Zonit.Extensions -Version 10.0.0-preview.15
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Zonit.Extensions" Version="10.0.0-preview.15" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zonit.Extensions" Version="10.0.0-preview.15" />
                    
Directory.Packages.props
<PackageReference Include="Zonit.Extensions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Zonit.Extensions --version 10.0.0-preview.15
                    
#r "nuget: Zonit.Extensions, 10.0.0-preview.15"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Zonit.Extensions@10.0.0-preview.15
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Zonit.Extensions&version=10.0.0-preview.15&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Zonit.Extensions&version=10.0.0-preview.15&prerelease
                    
Install as a Cake Tool

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.

NuGet Downloads

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 in Zonit.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.XmlXmlConvertible, a culture-invariant object ↔ XML helper for flat types.
  • Zonit.Extensions.ReflectionAssemblyProvider, 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 (Url is a plain struct so it can cache its parsed Uri; Schedule is a readonly record struct)
  • Empty static — which is default(T) — plus a HasValue flag. Price, Money and FileSize use Zero instead; Color uses Transparent.
  • A hand-written JsonConverter attached with [JsonConverter]: no registration, no reflection, no source-generator context needed on your side.
  • A TypeConverter for ASP.NET Core model binding and IConfiguration — except Price and Money, which you bind as decimal.
  • 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 notFormat 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

License

MIT — see LICENSE.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
Loading failed