MicroResult 1.0.1
dotnet add package MicroResult --version 1.0.1
NuGet\Install-Package MicroResult -Version 1.0.1
<PackageReference Include="MicroResult" Version="1.0.1" />
<PackageVersion Include="MicroResult" Version="1.0.1" />
<PackageReference Include="MicroResult" />
paket add MicroResult --version 1.0.1
#r "nuget: MicroResult, 1.0.1"
#:package MicroResult@1.0.1
#addin nuget:?package=MicroResult&version=1.0.1
#tool nuget:?package=MicroResult&version=1.0.1
MicroResult
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 | Versions 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. |
-
.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.
Update repository metadata, add MIT license and GitHub Actions workflow, and improve public README assets.