Vyrn.Ratatoskr.AspNetCore 0.4.0

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

Vyrn.Ratatoskr

A small result library for .NET 10.

Use Result when an operation can succeed or fail. Expected failures become values that your code can return and handle. Exceptions stay available for unexpected failures.

Packages

Package Use it for
Vyrn.Ratatoskr Results, errors, validation, and result pipelines
Vyrn.Ratatoskr.AspNetCore MVC and Minimal API ProblemDetails responses

Install

Install the core package:

dotnet add package Vyrn.Ratatoskr

For ASP.NET Core, also install:

dotnet add package Vyrn.Ratatoskr.AspNetCore

Quick Start

Return a value when the operation succeeds. Return a Rejection when it fails.

using Vyrn.Ratatoskr;

public Result<Order> FindOrder(string id)
{
    var order = orders.Find(order => order.Id == id);

    if (order is null)
    {
        return Rejection.NotFound(
            "Orders.NotFound",
            $"Order '{id}' was not found.");
    }

    return order;
}

Use Match to handle both outcomes:

string message = FindOrder("42").Match(
    order => $"Found {order.Name}",
    error => error.Description);

Create Results

Result.Success();
Result.Success(order);

Result.Failure(Error.Unexpected("Orders.Failed", "The order could not be saved."));
Result.Failure<Order>(Error.NotFound("Orders.NotFound", "The order was not found."));

Rejection is a shorter way to return a failure. It works with Result and Result<T>.

return Rejection.Validation("Orders.Name.Required", "Name is required.");
return Rejection.NotFound("Orders.NotFound", "The order was not found.");
return Rejection.Conflict("Orders.Exists", "The order already exists.");
return Rejection.Unexpected("Orders.Failed", "The order could not be saved.");

Work With Results

Method What it does
Map Changes a successful value
Bind Runs the next operation after success
Match Handles success and failure
Ensure Checks a successful value
Tap Runs an action after success
TapFailure Runs an action after failure
Sequence Combines a collection of results
Traverse Transforms a collection with a result-producing function
UnwrapOr Returns the value or a fallback
UnwrapOrElse Creates a fallback from the error

Failures keep their error in Map, Bind, and Ensure.

public Result<OrderDto> GetOrder(string id)
    => FindOrder(id)
        .Ensure(
            order => order.IsActive,
            Rejection.Validation("Orders.Inactive", "The order is not active."))
        .Map(order => new OrderDto(order.Id, order.Name));

Map, Bind, Match, Ensure, Tap, and TapFailure also work on Task<Result> and Task<Result<T>>:

Result<OrderDto> result = await FindOrderAsync(id)
    .Map(order => new OrderDto(order.Id, order.Name));

Validate Input

Use Result.Ensure for one check. Use Result.Validate to run several checks.

Result validation = Result.Validate(
    Result.Ensure(
        !string.IsNullOrWhiteSpace(name),
        Rejection.Validation("Orders.Name.Required", "Name is required.")),
    Result.Ensure(
        quantity > 0,
        Rejection.Validation("Orders.Quantity.Invalid", "Quantity must be greater than zero.")));

One failed check returns its error. Several failed checks return a ValidationError with all errors in Details.

Combine Results

Use Sequence when you already have a collection of results. It returns all successful values in source order, or the first failure:

Result<IReadOnlyList<Order>> orders = orderResults.Sequence();

Use Traverse to transform a collection with a result-producing function and combine the results in one operation:

Result<IReadOnlyList<Order>> orders = orderIds.Traverse(FindOrder);

Both operations stop at the first failure. Exceptions from enumeration or transformation continue normally so the application's exception boundary can handle them.

Define Reusable Errors

Use ErrorCatalog when one area of your application has many errors.

public static class OrderErrors
{
    private static readonly ErrorCatalog Catalog = new("Orders");

    public static Rejection NotFound(string id)
        => Catalog.NotFound("NotFound", $"Order '{id}' was not found.");

    public static Rejection SaveFailed()
        => Catalog.Unexpected("SaveFailed", "The order could not be saved.");
}

Call sites stay short:

return OrderErrors.NotFound(id);

ASP.NET Core

Add the namespace and convert the result in an MVC controller:

using Vyrn.Ratatoskr.AspNetCore;

[HttpGet("{id}")]
public async Task<ActionResult> Get(string id)
{
    Result<OrderDto> result = await service.GetOrder(id);
    return result.ToActionResult();
}

Default responses:

Result HTTP response
Result.Success() 204
Result.Success(value) 200
Validation failure 400
Not found failure 404
Conflict failure 409
Dependency failure 502
Timeout failure 504
Payload too large 413
Unsupported media 415
Unexpected failure 500

Failures use ProblemDetails. The error code and category are in the code and category extensions. A ValidationError also adds an errors extension. Attached exceptions are never included in the HTTP response.

Use a success factory when you need another success response:

return result.ToActionResult(
    order => CreatedAtAction(nameof(Get), new { id = order.Id }, order));

Minimal APIs keep success and failure mapping explicit:

static async Task<IResult> GetOrder(
    string id,
    CancellationToken cancellationToken)
{
    if (string.IsNullOrWhiteSpace(id))
    {
        return Rejection.Validation("Orders.Id.Required", "An order ID is required.")
            .ToProblemHttpResult();
    }

    var result = await LoadOrder(id, cancellationToken);
    if (result.IsFailure)
    {
        return result.Error.ToProblemHttpResult();
    }

    return TypedResults.Ok(result.Value);
}

Use ASP.NET Core's built-in TypedResults for successful Minimal API responses. Check failures explicitly and convert the error with ToProblemHttpResult():

if (result.IsFailure)
{
    return result.Error.ToProblemHttpResult();
}

return TypedResults.Created($"orders/{result.Value.Id}", result.Value);

ProblemHttpResult has a dynamic status. Declare the successful response with .Produces(...) and add .ProducesProblem(status) for each failure status so OpenAPI describes the complete endpoint contract.

Showcase

The Pokemon showcase is a small ASP.NET Core application that demonstrates validation, reusable errors, and exception conversion against the public PokeAPI. Its browser UI is one search form that loads a Razor card with HTMX.

Run it locally:

dotnet run --project Samples/Vyrn.Ratatoskr.Showcase

Then open http://localhost:5000 and search for a Pokemon.

Main Types

Type Purpose
Result Success or failure without a value
Result<T> Success with a value, or failure
Error Error code, description, type, and optional exception
ErrorType The stable category of an error
Rejection A failure that converts to any result type
ValidationError Several validation errors
ErrorCatalog Reusable errors with a shared code prefix

More Information

Run the project locally with:

dotnet test vyrn.ratatoskr.slnx
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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.4.0 124 7/28/2026
0.3.0 115 7/25/2026
0.2.0 104 7/24/2026
0.1.0 114 7/24/2026