![]() |
VOOZH | about |
dotnet add package ErrorOr --version 2.1.1
NuGet\Install-Package ErrorOr -Version 2.1.1
<PackageReference Include="ErrorOr" Version="2.1.1" />
<PackageVersion Include="ErrorOr" Version="2.1.1" />Directory.Packages.props
<PackageReference Include="ErrorOr" />Project file
paket add ErrorOr --version 2.1.1
#r "nuget: ErrorOr, 2.1.1"
#:package ErrorOr@2.1.1
#addin nuget:?package=ErrorOr&version=2.1.1Install as a Cake Addin
#tool nuget:?package=ErrorOr&version=2.1.1Install as a Cake Tool
<div align="center">
<img src="assets/icon.png" alt="drawing" width="700px"/></br>
👁 Build
👁 publish ErrorOr to nuget
👁 GitHub contributors
👁 GitHub Stars
👁 GitHub license
👁 codecov
dotnet add package ErrorOr
</div>
ErrorOr instance
Then, FailIf, Else, Switch, Match)Result.Success, ..)ErrorOr 🤝Loving it? Show your support by giving this project a star!
ErrorOr<T>This 👇
public float Divide(int a, int b)
{
if (b == 0)
{
throw new Exception("Cannot divide by zero");
}
return a / b;
}
try
{
var result = Divide(4, 2);
Console.WriteLine(result * 2); // 4
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return;
}
Turns into this 👇
public ErrorOr<float> Divide(int a, int b)
{
if (b == 0)
{
return Error.Unexpected(description: "Cannot divide by zero");
}
return a / b;
}
var result = Divide(4, 2);
if (result.IsError)
{
Console.WriteLine(result.FirstError.Description);
return;
}
Console.WriteLine(result.Value * 2); // 4
Or, using Then/Else and Switch/Match, you can do this 👇
Divide(4, 2)
.Then(val => val * 2)
.SwitchFirst(
onValue: Console.WriteLine, // 4
onFirstError: error => Console.WriteLine(error.Description));
Internally, the ErrorOr object has a list of Errors, so if you have multiple errors, you don't need to compromise and have only the first one.
public class User(string _name)
{
public static ErrorOr<User> Create(string name)
{
List<Error> errors = [];
if (name.Length < 2)
{
errors.Add(Error.Validation(description: "Name is too short"));
}
if (name.Length > 100)
{
errors.Add(Error.Validation(description: "Name is too long"));
}
if (string.IsNullOrWhiteSpace(name))
{
errors.Add(Error.Validation(description: "Name cannot be empty or whitespace only"));
}
if (errors.Count > 0)
{
return errors;
}
return new User(name);
}
}
The ErrorOr object has a variety of methods that allow you to work with it in a functional way.
This allows you to chain methods together, and handle the result in a clean and concise way.
return await _userRepository.GetByIdAsync(id)
.Then(user => user.IncrementAge()
.Then(success => user)
.Else(errors => Error.Unexpected("Not expected to fail")))
.FailIf(user => !user.IsOverAge(18), UserErrors.UnderAge)
.ThenDo(user => _logger.LogInformation($"User {user.Id} incremented age to {user.Age}"))
.ThenAsync(user => _userRepository.UpdateAsync(user))
.Match(
_ => NoContent(),
errors => errors.ToActionResult());
ErrorOr<string> foo = await "2".ToErrorOr()
.Then(int.Parse) // 2
.FailIf(val => val > 2, val => Error.Validation(description: $"{val} is too big")) // 2
.ThenDoAsync(Task.Delay) // Sleep for 2 milliseconds
.ThenDo(val => Console.WriteLine($"Finished waiting {val} milliseconds.")) // Finished waiting 2 milliseconds.
.ThenAsync(val => Task.FromResult(val * 2)) // 4
.Then(val => $"The result is {val}") // "The result is 4"
.Else(errors => Error.Unexpected(description: "Yikes")) // "The result is 4"
.MatchFirst(
value => value, // "The result is 4"
firstError => $"An error occurred: {firstError.Description}");
ErrorOr<string> foo = await "5".ToErrorOr()
.Then(int.Parse) // 5
.FailIf(val => val > 2, val => Error.Validation(description: $"{val} is too big")) // Error.Validation()
.ThenDoAsync(Task.Delay) // Error.Validation()
.ThenDo(val => Console.WriteLine($"Finished waiting {val} milliseconds.")) // Error.Validation()
.ThenAsync(val => Task.FromResult(val * 2)) // Error.Validation()
.Then(val => $"The result is {val}") // Error.Validation()
.Else(errors => Error.Unexpected(description: "Yikes")) // Error.Unexpected()
.MatchFirst(
value => value,
firstError => $"An error occurred: {firstError.Description}"); // An error occurred: Yikes
ErrorOr instanceThere are implicit converters from TResult, Error, List<Error> to ErrorOr<TResult>
ErrorOr<int> result = 5;
ErrorOr<int> result = Error.Unexpected();
ErrorOr<int> result = [Error.Validation(), Error.Validation()];
public ErrorOr<int> IntToErrorOr()
{
return 5;
}
public ErrorOr<int> SingleErrorToErrorOr()
{
return Error.Unexpected();
}
public ErrorOr<int> MultipleErrorsToErrorOr()
{
return [
Error.Validation(description: "Invalid Name"),
Error.Validation(description: "Invalid Last Name")
];
}
ErrorOrFactoryErrorOr<int> result = ErrorOrFactory.From(5);
ErrorOr<int> result = ErrorOrFactory.From<int>(Error.Unexpected());
ErrorOr<int> result = ErrorOrFactory.From<int>([Error.Validation(), Error.Validation()]);
ErrorOr<int> result = await ErrorOrFactory.FromAsync(5);
ErrorOr<int> result = await ErrorOrFactory.FromAsync<int>(Error.Unexpected());
ErrorOr<int> result = await ErrorOrFactory.FromAsync<int>([Error.Validation(), Error.Validation()]);
public ErrorOr<int> GetValue()
{
return ErrorOrFactory.From(5);
}
public ErrorOr<int> SingleErrorToErrorOr()
{
return ErrorOrFactory.From<int>(Error.Unexpected());
}
public ErrorOr<int> MultipleErrorsToErrorOr()
{
return ErrorOrFactory.From([
Error.Validation(description: "Invalid Name"),
Error.Validation(description: "Invalid Last Name")
]);
}
public async Tak<ErrorOr<int>> GetValueAsync()
{
return await ErrorOrFactory.FromAsync(5);
}
public async Tak<ErrorOr<int>> SingleErrorToErrorOrAsync()
{
return await ErrorOrFactory.FromAsync<int>(Error.Unexpected());
}
public async Tak<ErrorOr<int>> MultipleErrorsToErrorOrAsync()
{
return await ErrorOrFactory.FromAsync([
Error.Validation(description: "Invalid Name"),
Error.Validation(description: "Invalid Last Name")
]);
}
ToErrorOr Extension MethodErrorOr<int> result = 5.ToErrorOr();
ErrorOr<int> result = await Task.FromResult(5).ToErrorOrAsync();
ErrorOr<int> result = Error.Unexpected().ToErrorOr<int>();
ErrorOr<int> result = new[] { Error.Unauthorized(), Error.Validation() }.ToErrorOr<int>();
Task<Error> errorTask = Task.FromResult(Error.Validation());
ErrorOr<int> result = errorTask.ToErrorOrAsync<int>();
List<Error> errors = [Error.Unauthorized(), Error.Validation()];
Task<List<Error>> errorsTask = Task.FromResult(errors);
ErrorOr<int> result = await errorsTask.ToErrorOrAsync<int>();
IsErrorErrorOr<int> result = User.Create();
if (result.IsError)
{
// the result contains one or more errors
}
IsSuccessErrorOr<int> result = User.Create();
if (result.IsSuccess)
{
// the result contains no errors
}
ValueErrorOr<int> result = User.Create();
if (!result.IsError) // the result contains a value
{
Console.WriteLine(result.Value);
}
ErrorsErrorOr<int> result = User.Create();
if (result.IsError)
{
result.Errors // contains the list of errors that occurred
.ForEach(error => Console.WriteLine(error.Description));
}
FirstErrorErrorOr<int> result = User.Create();
if (result.IsError)
{
var firstError = result.FirstError; // only the first error that occurred
Console.WriteLine(firstError == result.Errors[0]); // true
}
ErrorsOrEmptyListErrorOr<int> result = User.Create();
if (result.IsError)
{
result.ErrorsOrEmptyList // List<Error> { /* one or more errors */ }
return;
}
result.ErrorsOrEmptyList // List<Error> { }
MatchThe Match method receives two functions, onValue and onError, onValue will be invoked if the result is success, and onError is invoked if the result is an error.
Matchstring foo = result.Match(
value => value,
errors => $"{errors.Count} errors occurred.");
MatchAsyncstring foo = await result.MatchAsync(
value => Task.FromResult(value),
errors => Task.FromResult($"{errors.Count} errors occurred."));
MatchFirstThe MatchFirst method receives two functions, onValue and onError, onValue will be invoked if the result is success, and onError is invoked if the result is an error.
Unlike Match, if the state is error, MatchFirst's onError function receives only the first error that occurred, not the entire list of errors.
string foo = result.MatchFirst(
value => value,
firstError => firstError.Description);
MatchFirstAsyncstring foo = await result.MatchFirstAsync(
value => Task.FromResult(value),
firstError => Task.FromResult(firstError.Description));
SwitchThe Switch method receives two actions, onValue and onError, onValue will be invoked if the result is success, and onError is invoked if the result is an error.
Switchresult.Switch(
value => Console.WriteLine(value),
errors => Console.WriteLine($"{errors.Count} errors occurred."));
SwitchAsyncawait result.SwitchAsync(
value => { Console.WriteLine(value); return Task.CompletedTask; },
errors => { Console.WriteLine($"{errors.Count} errors occurred."); return Task.CompletedTask; });
SwitchFirstThe SwitchFirst method receives two actions, onValue and onError, onValue will be invoked if the result is success, and onError is invoked if the result is an error.
Unlike Switch, if the state is error, SwitchFirst's onError function receives only the first error that occurred, not the entire list of errors.
result.SwitchFirst(
value => Console.WriteLine(value),
firstError => Console.WriteLine(firstError.Description));
SwitchFirstAsyncawait result.SwitchFirstAsync(
value => { Console.WriteLine(value); return Task.CompletedTask; },
firstError => { Console.WriteLine(firstError.Description); return Task.CompletedTask; });
ThenThenThen receives a function, and invokes it only if the result is not an error.
ErrorOr<int> foo = result
.Then(val => val * 2);
Multiple Then methods can be chained together.
ErrorOr<string> foo = result
.Then(val => val * 2)
.Then(val => $"The result is {val}");
If any of the methods return an error, the chain will break and the errors will be returned.
ErrorOr<int> Foo() => Error.Unexpected();
ErrorOr<string> foo = result
.Then(val => val * 2)
.Then(_ => GetAnError())
.Then(val => $"The result is {val}") // this function will not be invoked
.Then(val => $"The result is {val}"); // this function will not be invoked
ThenAsyncThenAsync receives an asynchronous function, and invokes it only if the result is not an error.
ErrorOr<string> foo = await result
.ThenAsync(val => DoSomethingAsync(val))
.ThenAsync(val => DoSomethingElseAsync($"The result is {val}"));
ThenDo and ThenDoAsyncThenDo and ThenDoAsync are similar to Then and ThenAsync, but instead of invoking a function that returns a value, they invoke an action.
ErrorOr<string> foo = result
.ThenDo(val => Console.WriteLine(val))
.ThenDo(val => Console.WriteLine($"The result is {val}"));
ErrorOr<string> foo = await result
.ThenDoAsync(val => Task.Delay(val))
.ThenDo(val => Console.WriteLine($"Finsihed waiting {val} seconds."))
.ThenDoAsync(val => Task.FromResult(val * 2))
.ThenDo(val => $"The result is {val}");
ThenEnsure and ThenEnsureAsyncThenEnsure and ThenEnsureAsync are similar to ThenDo and ThenDoAsync, but they receive a function that can return errors.
If no errors are returned, the original value is preserved and the ensure function's success value is ignored.
ErrorOr<User> CacheUser(User user)
{
ErrorOr<Success> result = _cache.Set(user);
return result.IsError ? result.Errors : user;
}
ErrorOr<User> userOrError = _userRepository
.GetById(userId)
.ThenEnsure(CacheUser);
// Success: userOrError is the original user from GetById.
// Failure: userOrError contains cache errors from CacheUser.
async Task<ErrorOr<User>> CacheUserAsync(User user)
{
ErrorOr<Success> result = await _cache.SetAsync(user);
return result.IsError ? result.Errors : user;
}
ErrorOr<User> userOrError = await _userRepository
.GetByIdAsync(userId)
.ThenEnsureAsync(CacheUserAsync);
// Success: userOrError is the original user from GetByIdAsync.
// Failure: userOrError contains cache errors from CacheUserAsync.
Then, ThenDo, ThenAsync, ThenDoAsyncYou can mix and match Then, ThenDo, ThenAsync, ThenDoAsync methods.
ErrorOr<string> foo = await result
.ThenDoAsync(val => Task.Delay(val))
.Then(val => val * 2)
.ThenAsync(val => DoSomethingAsync(val))
.ThenDo(val => Console.WriteLine($"Finsihed waiting {val} seconds."))
.ThenAsync(val => Task.FromResult(val * 2))
.Then(val => $"The result is {val}");
FailIfFailIf receives a predicate and an error. If the predicate is true, FailIf will return the error. Otherwise, it will return the value of the result.
ErrorOr<int> errorOrInt = 3;
ErrorOr<int> foo = errorOrInt
.FailIf(val => val > 2, val => Error.Validation(description: $"{val} is too big"));
Once an error is returned, the chain will break and the error will be returned.
var result = "2".ToErrorOr()
.Then(int.Parse) // 2
.FailIf(val => val > 1, val => Error.Validation(description: $"{val} is too big")) // validation error
.Then(num => num * 2) // this function will not be invoked
.Then(num => num * 2); // this function will not be invoked
ElseElse receives a value or a function. If the result is an error, Else will return the value or invoke the function. Otherwise, it will return the value of the result.
ElseErrorOr<string> foo = result
.Else("fallback value");
ErrorOr<string> foo = result
.Else(errors => $"{errors.Count} errors occurred.");
ElseAsyncErrorOr<string> foo = await result
.ElseAsync(Task.FromResult("fallback value"));
ErrorOr<string> foo = await result
.ElseAsync(errors => Task.FromResult($"{errors.Count} errors occurred."));
ElseDo and ElseDoAsyncElseDo and ElseDoAsync are similar to Else and ElseAsync, but instead of invoking a function that returns an error, they invoke an action.
ErrorOr<string> foo = result
.Else(errors => Error.Unexpected())
.ElseDo(error => Console.WriteLine(error.FirstError.Description));
ErrorOr<string> foo = await result
.ElseDoAsync(HandleErrorAsync);
Then, FailIf, Else, Switch, Match)You can mix Then, FailIf, Else, Switch and Match methods together.
ErrorOr<int> errorOrInt = 500;
ErrorOr<string> foo = await errorOrInt
.ThenDoAsync(val => Task.Delay(val))
.FailIf(val => val > 2, val => Error.Validation(description: $"{val} is too big"))
.ThenDo(val => Console.WriteLine($"Finished waiting {val} seconds."))
.ThenAsync(val => Task.FromResult(val * 2))
.Then(val => $"The result is {val}")
.Else(errors => Error.Unexpected())
.MatchFirst(
value => value,
firstError => $"An error occurred: {firstError.Description}");
When working in cross-cutting concerns such as logging, auditing, or middleware pipelines, you may hold a reference to IErrorOr without knowing the concrete TValue type. The IRecordable interface provides a format-agnostic way to obtain a representation of the current state in these scenarios.
Because IErrorOr inherits from IRecordable, GetRecording(IRecordingSerializer<TOutput>) is available directly on any IErrorOr reference — no cast required.
GetRecording<TOutput> accepts any IRecordingSerializer<TOutput> implementation. The TOutput type parameter determines what GetRecording returns — a string, a byte[], or any other type. The library calls SerializeValue<TValue>(TValue value) with the fully-typed value, so no boxing is visible to your implementation:
public interface IRecordingSerializer<TOutput>
{
TOutput SerializeValue<TValue>(TValue value);
TOutput SerializeErrors(List<Error> errors);
}
Create a serializer that uses System.Text.Json by implementing IRecordingSerializer<string>:
using System.Text.Json;
using System.Text.Json.Serialization;
using ErrorOr;
public class SystemTextJsonRecordingSerializer : IRecordingSerializer<string>
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true,
Converters = { new JsonStringEnumConverter() },
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
};
public string SerializeValue<TValue>(TValue value)
=> JsonSerializer.Serialize(value, JsonOptions);
public string SerializeErrors(List<Error> errors)
=> JsonSerializer.Serialize(errors, JsonOptions);
}
Then pass an instance to GetRecording:
var serializer = new SystemTextJsonRecordingSerializer();
void Log(IErrorOr result)
{
Console.WriteLine(result.GetRecording(serializer));
}
// Value state:
// {
// "Name": "Alice",
// "MiddleName": null,
// "Age": 30
// }
// Error state:
// [
// {
// "Code": "User.NotFound",
// "Description": "User was not found.",
// "Type": "NotFound",
// "NumericType": 3,
// "Metadata": null
// }
// ]
Any output type is supported — implement IRecordingSerializer<TOutput> to produce plain text, binary payloads, or anything else:
// Plain text — returns string
public class PlainTextRecordingSerializer : IRecordingSerializer<string>
{
public string SerializeValue<TValue>(TValue value)
=> value?.ToString() ?? string.Empty;
public string SerializeErrors(List<Error> errors)
=> string.Join(", ", errors.Select(e => $"{e.Code}: {e.Description}"));
}
// Binary — returns byte[] (e.g. for Protobuf, MessagePack, AVRO)
public class ProtobufRecordingSerializer : IRecordingSerializer<byte[]>
{
public byte[] SerializeValue<TValue>(TValue value)
=> ProtoBuf.Serializer.SerializeWithLengthPrefix<TValue>(value);
public byte[] SerializeErrors(List<Error> errors)
=> ProtoBuf.Serializer.SerializeWithLengthPrefix(errors);
}
Each Error instance has a Type property, which is an enum value that represents the type of the error.
The following error types are built in:
public enum ErrorType
{
Failure,
Unexpected,
Validation,
Conflict,
NotFound,
Unauthorized,
Forbidden,
}
Each error type has a static method that creates an error of that type. For example:
var error = Error.NotFound();
optionally, you can pass a code, description and metadata to the error:
var error = Error.Unexpected(
code: "User.ShouldNeverHappen",
description: "A user error that should never happen",
metadata: new Dictionary<string, object>
{
{ "user", user },
});
The ErrorType enum is a good way to categorize errors.
You can create your own error types if you would like to categorize your errors differently.
A custom error type can be created with the Custom static method
public static class MyErrorTypes
{
public const int ShouldNeverHappen = 12;
}
var error = Error.Custom(
type: MyErrorTypes.ShouldNeverHappen,
code: "User.ShouldNeverHappen",
description: "A user error that should never happen");
You can use the Error.NumericType method to retrieve the numeric type of the error.
var errorMessage = Error.NumericType switch
{
MyErrorType.ShouldNeverHappen => "Consider replacing dev team",
_ => "An unknown error occurred.",
};
Result.Success, ..)There are a few built in result types:
ErrorOr<Success> result = Result.Success;
ErrorOr<Created> result = Result.Created;
ErrorOr<Updated> result = Result.Updated;
ErrorOr<Deleted> result = Result.Deleted;
Which can be used as following
ErrorOr<Deleted> DeleteUser(Guid id)
{
var user = await _userRepository.GetByIdAsync(id);
if (user is null)
{
return Error.NotFound(description: "User not found.");
}
await _userRepository.DeleteAsync(user);
return Result.Deleted;
}
A nice approach, is creating a static class with the expected errors. For example:
public static partial class DivisionErrors
{
public static Error CannotDivideByZero = Error.Unexpected(
code: "Division.CannotDivideByZero",
description: "Cannot divide by zero.");
}
Which can later be used as following 👇
public ErrorOr<float> Divide(int a, int b)
{
if (b == 0)
{
return DivisionErrors.CannotDivideByZero;
}
return a / b;
}
ErrorOr 🤝A common approach when using MediatR is to use FluentValidation to validate the request before it reaches the handler.
Usually, the validation is done using a Behavior that throws an exception if the request is invalid.
Using ErrorOr, we can create a Behavior that returns an error instead of throwing an exception.
This plays nicely when the project uses ErrorOr, as the layer invoking the Mediator, similar to other components in the project, simply receives an ErrorOr and can handle it accordingly.
Here is an example of a Behavior that validates the request and returns an error if it's invalid 👇
public class ValidationBehavior<TRequest, TResponse>(IValidator<TRequest>? validator = null)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
where TResponse : IErrorOr
{
private readonly IValidator<TRequest>? _validator = validator;
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
if (_validator is null)
{
return await next();
}
var validationResult = await _validator.ValidateAsync(request, cancellationToken);
if (validationResult.IsValid)
{
return await next();
}
var errors = validationResult.Errors
.ConvertAll(error => Error.Validation(
code: error.PropertyName,
description: error.ErrorMessage));
return (dynamic)errors;
}
}
If you have any questions, comments, or suggestions, please open an issue or create a pull request 🙂
This project is licensed under the terms of the MIT license.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 5 NuGet packages that depend on ErrorOr:
| Package | Downloads |
|---|---|
|
GymManager.Common
A agrouped common entities for GymManager |
|
|
ErrorOrAspNetCoreExtensions
A collection of ErrorOr extension methods designed to reduce the amount of boilerplate code needed when returning appropriate HTTP responses. |
|
|
FEE.Remit.Generic.Endpoint
Endpoint Helper |
|
|
ErrorOr.Extensions
Package Description |
|
|
RealmDigital.Common
Common classes and interfaces used when building .NET 8+ applications |
Showing the top 11 popular GitHub repositories that depend on ErrorOr:
| Repository | Stars |
|---|---|
|
evolutionary-architecture/evolutionary-architecture-by-example
Navigate the complex landscape of .NET software architecture with our step-by-step, story-like guide. Unpack the interplay between modular monoliths, microservices, domain-driven design, and various architectural patterns. Go beyond the one-size-fits-all solutions and understand how to blend these approaches based on your unique needs.
|
|
|
amantinband/clean-architecture
The ultimate clean architecture template for .NET applications 💪
|
|
|
nadirbad/VerticalSliceArchitecture
Vertical Slice Architecture solution template in .NET 10
|
|
|
Jorixon/JASM
Just Another Skin Manager
|
|
|
amantinband/buber-breakfast
A REST API which supports Creating, Reading, Updating and Deleting breakfasts
|
|
|
SSWConsulting/SSW.VerticalSliceArchitecture
An enterprise ready solution template for Vertical Slice Architecture. This template is just one way to apply the Vertical Slice Architecture.
|
|
|
logicpulse/logicPOS
Logicpulse's Open Source POS System
|
|
|
SSWConsulting/SSW.CleanArchitecture
SSW Clean Architecture Template
|
|
| asesidaa/EXVS2-POC | |
|
mohammadKarimi/SwiftLink
SwiftLink is a modern URL shortener with Asp.net Core 8
|
|
|
PanKunik/buber-dinner
This repository follows Amichai Mantinband course on REST API DDD CLEAN ARCHITECTURE.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 2.1.1 | 81,494 | 5/15/2026 |
| 2.1.1-rc.4 | 100 | 5/11/2026 |
| 2.1.1-rc.3 | 843 | 5/1/2026 |
| 2.1.1-rc.2 | 64 | 5/1/2026 |
| 2.0.1 | 4,886,900 | 3/26/2024 |
| 1.10.0 | 465,111 | 2/14/2024 |
| 1.9.0 | 255,114 | 1/6/2024 |
| 1.8.0 | 2,935 | 1/5/2024 |
| 1.7.0 | 868 | 1/5/2024 |
| 1.6.0 | 42,778 | 1/4/2024 |
| 1.5.0 | 11,656 | 1/2/2024 |
| 1.4.0 | 1,254 | 1/1/2024 |
| 1.3.0 | 1,220,595 | 10/1/2023 |
| 1.2.1 | 1,582,512 | 11/24/2022 |
| 1.2.0 | 11,609 | 11/17/2022 |
| 1.1.0 | 11,508 | 11/14/2022 |
| 1.0.1 | 94,321 | 9/22/2022 |