OrionResult
One error-model vocabulary for the Orion family. Most "failures" in real code are expected — validation rejected the input, the resource wasn't found, the caller isn't authorized — and modelling those as exceptions gives you invisible control flow, stack-trace tax, and forty different catch shapes at the HTTP boundary. So teams reach for a Result type, and now there are five of them, none agreeing on how a failure becomes a response.
OrionResult gives the family one Result/Option/Error vocabulary: a zero-alloc Result<T> struct, a structured Error (stable code + kind, not free-text), and the family's IOrionResult contract — so failures flow as data, not as control flow.
Features
Result<T>— areadonly struct, so the success path allocates nothing. Success carries the value; failure carries one or moreErrors. Railway composition withMap,Bind,Match,Ensure,Tap,OrElse.- Structured
Error— a machine-readableCode, a humanMessage, anErrorKindcategory, and optional field-level errors and extensions. Factory helpers (Error.NotFound,Error.Validation, …). Bridges to the spine'sOrionError. Option<T>— "maybe absent", distinct from "failed with a reason".Map/Bind/Match/OrElse,ToResult,FirstOrNone.- Implicit conversions keep call sites clean:
return value;is a success,return Error.NotFound(...);is a failure. - Implements
IOrionResult<T>— cross-cutting code (and, in a later wave, the RFC 9457ProblemDetailsbridge) reads any Orion result the same way. - AOT- and trim-clean, verified by a native-binary smoke test in CI; no reflection in the core. Multi-targets
net8.0,net9.0,net10.0.
Install
dotnet add package OrionResult
Quick start
using Moongazing.OrionResult;
Result<User> FindUser(UserId id) =>
repo.TryGet(id) is { } user
? user // implicit T -> success
: Error.NotFound("user.not_found", $"No user {id}"); // implicit Error -> failure
// Railway composition: each step runs only if the previous succeeded.
Result<ReceiptDto> Pay(UserId id, decimal amount) =>
FindUser(id)
.Ensure(u => u.IsActive, Error.Conflict("user.inactive", "User is deactivated"))
.Bind(u => ChargeCard(u, amount))
.Map(charge => new ReceiptDto(charge));
// Collapse to a value by handling both cases.
string message = Pay(id, 10m).Match(
receipt => $"charged {receipt.Total}",
errors => $"failed: {errors[0].Code}");
Option<T> for "maybe absent":
Option<Email> primary = user.Emails.FirstOrNone(e => e.IsPrimary);
Email best = primary.OrElse(Email.Empty);
// Turn absence into a typed failure when you need a Result.
Result<Email> required = primary.ToResult(Error.Validation("email.required", "A primary email is required"));
Catch a boundary exception once and convert it — a deliberate, local escape hatch:
Result<Config> parsed = Result.Try(
() => Config.Parse(raw),
ex => Error.Validation("config.invalid", ex.Message));
Versioning
Follows Semantic Versioning. Multi-targets net8.0, net9.0, and net10.0. Binds to Orion.Abstractions 1.x. The RFC 9457 ProblemDetails / ToHttpResult HTTP mapping and async combinators arrive in later waves; this release is the core value types.
Documentation
- CHANGELOG.md — release notes.
Contributing
Contributions are welcome. See CONTRIBUTING.md and the CODE_OF_CONDUCT.md.
More from the Orion family
Focused .NET libraries built to one quality bar. Each is usable on its own; several share the small Orion.Abstractions contracts spine, but there is no deep dependency web — pick only what you need:
- OrionGuard — validation, guard clauses, DDD primitives, domain events
- Orion.Abstractions — the shared contracts spine: telemetry, options, result, clock
- OrionAudit — automatic EF Core change-audit trail
- OrionBeacon — leader election with fencing tokens
- OrionClock — testable time, TTLs, and deadlines
- OrionGrant — permission / authorization checks
- OrionKey — source-generated strongly-typed IDs
- OrionLedger — API-key issuance, verification, and rotation
- OrionLens — ambient correlation-context propagation
- OrionLock — distributed locks with fencing tokens
- OrionOnce — idempotency keys for exactly-once request handling
- OrionPatch — transactional outbox for EF Core
- OrionRelay — outbound webhook delivery (HMAC, retries, backoff)
- OrionSaga — sagas / process managers for long-running workflows
- OrionShade — sensitive-data redaction for logs and telemetry
- OrionStream — server-sent events / streaming hub
- OrionVault — field-level encryption for EF Core
See it all working together in OrionShowcase, a production-shaped banking sample.
License
MIT.
Packages
| Package | Version | Downloads |
|---|---|---|
| OrionResult | 0.9.0 | 239 |