MicroResult 1.0.1

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

MicroResult

MicroResult banner

MicroResult is a tiny library for returning either a successful value or an error without throwing exceptions in normal control flow.

It is designed for modern .NET applications that want predictable flow, low overhead, and a minimal API surface.

Features

Zero Dependencies — Just add and use
Zero Allocations — Readonly struct, stack-only
🚀 AOT Friendly — Native AOT compilation ready
🎯 Minimal API Surface — Only essential methods (Match, Map, Bind, Ensure)
🔗 Fluent Chaining — Composable, functional error handling
Clean DX — Implicit conversions + Match patterns

Installation

dotnet add package MicroResult

What It Does

Instead of throwing exceptions for expected failures, MicroResult returns a value that is either:

  • a success containing T
  • a failure containing Error

That makes business flow explicit and easy to compose.

public Result<User> GetUser(Guid id)
{
    var user = db.Users.Find(id);

    if (user is null)
        return new Error("NotFound", "User not found");

    return user;
}

You then handle both outcomes deliberately:

var result = GetUser(id);

return result.Match(
    user => Results.Ok(user),
    error => Results.BadRequest(error));

Quick Start

Basic Usage

using MicroResult;

// Define errors
public static class Errors
{
    public static readonly Error NotFound = new("NotFound", "User not found");
    public static readonly Error Invalid = new("Invalid", "Invalid user");
}

// Return Result<T>
public Result<User> GetUser(Guid id)
{
    var user = db.Users.Find(id);
    if (user == null)
        return Errors.NotFound;  // Implicit conversion!
    
    return user;  // Implicit conversion!
}

// Consume with Match
var result = GetUser(id);
return result.Match(
    onSuccess: user => Ok(user),
    onFailure: error => BadRequest(error)
);

Chaining with Bind & Map

var result = GetUser(id)
    .Bind(ValidateUser)
    .Map(user => new UserDto(user));

return result.Match(
    user => Ok(user),
    error => BadRequest(error)
);

Why Chaining Helps

var result = GetUser(id)
    .Bind(ValidateUser)
    .Map(user => new UserDto(user));

Each step only runs when the previous step succeeded. If any step returns an error, the chain stops and preserves that failure.

Core API

Error

public readonly struct Error
{
    public string Code { get; }
    public string Message { get; }
    
    public Error(string code, string message);
    public override string ToString(); // "Code: Message"
}

Result<T>

public readonly struct Result<T>
{
    public bool IsSuccess { get; }
    public bool IsFailure { get; }
    public T Value { get; }           // Throws if failure
    public Error Error { get; }       // Throws if success
    
    // Factory methods
    public static Result<T> Success(T value);
    public static Result<T> Failure(Error error);
    
    // Core methods
    public TResult Match<TResult>(Func<T, TResult> onSuccess, Func<Error, TResult> onFailure);
    public Result<TResult> Map<TResult>(Func<T, TResult> func);
    public Result<TResult> Bind<TResult>(Func<T, Result<TResult>> func);
    public Result<T> Ensure(Func<T, bool> predicate, Error error);
    
    // Implicit conversions
    public static implicit operator Result<T>(T value);
    public static implicit operator Result<T>(Error error);
}

Extensions

// Side effects
public static Result<T> Tap<T>(this Result<T> result, Action<T> action);
public static Result<T> OnFailure<T>(this Result<T> result, Action<Error> action);

Real-World Use Cases

// Validation
return age >= 18
    ? user
    : new Error("InvalidAge", "Must be 18 or older");
// Database lookup
return entity is null
    ? new Error("NotFound", "Entity not found")
    : entity;
// API response mapping
return result.Match(
    value => Results.Ok(value),
    error => Results.BadRequest(error));

Optional ASP.NET Core Integration

The published package keeps the core library dependency-free.

If you want a ToHttpResult() extension for Minimal APIs, add the optional HttpExtensions.optional.cs helper from the repository to your ASP.NET Core project and reference the required ASP.NET package there.

return result.ToHttpResult();

Examples

Validation Pattern

public Result<User> ValidateUser(User user)
{
    return Result<User>.Success(user)
        .Ensure(u => !string.IsNullOrEmpty(u.Email), Errors.InvalidEmail)
        .Ensure(u => u.Age >= 18, Errors.UnderAge)
        .Ensure(u => u.Email.Contains("@"), Errors.InvalidFormat);
}

Railway-Oriented Programming

public Result<UserDto> CreateUser(CreateUserRequest req)
{
    return ValidateRequest(req)
        .Bind(r => CheckEmailExists(r.Email))
        .Bind(r => HasPermission(r))
        .Map(r => new User { Email = r.Email, Name = r.Name })
        .Tap(user => _db.Users.Add(user))
        .Map(user => new UserDto(user));
}

Performance Characteristics

  • Value Type: Stack allocation only, no GC pressure
  • No Exceptions in Happy Path: Functional error handling
  • AOT Compatible: Full Native AOT support, no reflection

Supported Frameworks

  • .NET 10
  • .NET 8.0
  • .NET Standard 2.0

Design Philosophy

Brutally minimal. Every line of code must earn its place.

  • No async wrappers (use C# async/await natively)
  • No advanced LINQ operators
  • No abstract base classes
  • No external dependencies
  • No magic

Feedback

Issues and PRs are welcome on GitHub.

License

MIT — Use freely in personal and commercial projects.


MicroResult: The Result type you won't outgrow. 🚀

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.

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
1.0.1 101 3/18/2026
1.0.0 103 3/18/2026

Update repository metadata, add MIT license and GitHub Actions workflow, and improve public README assets.