OrionResult 0.9.0

dotnet add package OrionResult --version 0.9.0
                    
NuGet\Install-Package OrionResult -Version 0.9.0
                    
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="OrionResult" Version="0.9.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OrionResult" Version="0.9.0" />
                    
Directory.Packages.props
<PackageReference Include="OrionResult" />
                    
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 OrionResult --version 0.9.0
                    
#r "nuget: OrionResult, 0.9.0"
                    
#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 OrionResult@0.9.0
                    
#: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=OrionResult&version=0.9.0
                    
Install as a Cake Addin
#tool nuget:?package=OrionResult&version=0.9.0
                    
Install as a Cake Tool

<p align="center"> <img src="docs/logo.png" alt="OrionResult" width="150" /> </p>

OrionResult

CI/CD NuGet

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> — a readonly struct, so the success path allocates nothing. Success carries the value; failure carries one or more Errors. Railway composition with Map, Bind, Match, Ensure, Tap, OrElse.
  • Structured Error — a machine-readable Code, a human Message, an ErrorKind category, and optional field-level errors and extensions. Factory helpers (Error.NotFound, Error.Validation, …). Bridges to the spine's OrionError.
  • 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 9457 ProblemDetails bridge) 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

Contributing

Contributions are welcome. See CONTRIBUTING.md and the CODE_OF_CONDUCT.md.

License

MIT.

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

NuGet packages (2)

Showing the top 2 NuGet packages that depend on OrionResult:

Package Downloads
OrionEnvelope

One HTTP contract for the whole API: every success is a typed { data, meta }, every failure is an RFC 9457 problem+json, and pagination metadata rides in the same envelope — projected mechanically from OrionResult's Result<T> instead of hand-serialized per endpoint. Source-gen JSON, reflection-free and AOT-clean. Wave 1 is the types and the projection; the ASP.NET filters and OpenAPI schema land in later waves.

OrionCache

Cache-aside with per-key single-flight, OrionClock-driven expiration, case-sensitive tag invalidation, Option-returning reads, and OpenTelemetry. AOT-clean in-memory core; Redis L2 is planned.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.9.0 252 7/27/2026