Voyager.Common.Results
1.10.0
See the version list below for details.
dotnet add package Voyager.Common.Results --version 1.10.0
NuGet\Install-Package Voyager.Common.Results -Version 1.10.0
<PackageReference Include="Voyager.Common.Results" Version="1.10.0" />
<PackageVersion Include="Voyager.Common.Results" Version="1.10.0" />
<PackageReference Include="Voyager.Common.Results" />
paket add Voyager.Common.Results --version 1.10.0
#r "nuget: Voyager.Common.Results, 1.10.0"
#:package Voyager.Common.Results@1.10.0
#addin nuget:?package=Voyager.Common.Results&version=1.10.0
#tool nuget:?package=Voyager.Common.Results&version=1.10.0
Voyager.Common.Results
A lightweight, functional Result Pattern implementation for .NET that enables Railway Oriented Programming. Replace exceptions with explicit error handling, making your code more predictable and easier to test.
Supports .NET Framework 4.8 and .NET 8 ๐
โจ Features
- ๐ฏ Type-safe error handling without exceptions
- ๐ Railway Oriented Programming with method chaining
- โก Async/await support with extension methods and instance proxies
- ๐งฉ Contextual errors with Ensure/EnsureAsync error factories
- ๐งต Deadlock-safe async - library uses ConfigureAwait(false) internally
- ๐ฆ Zero dependencies (except polyfills for .NET Framework)
- ๐ Source Link enabled for debugging
- ๐ Comprehensive XML documentation
- ๐งช Fully tested with high code coverage
- ๐จ Implicit conversions for ergonomic API
- ๐ฌ Built-in Roslyn analyzer warns when Result is not consumed
- ๐ค Automated publishing via GitHub Actions
๐ฆ Installation
# Core Result pattern library
dotnet add package Voyager.Common.Results
# Advanced resilience patterns (Circuit Breaker)
dotnet add package Voyager.Common.Resilience
๐ Quick Start
using Voyager.Common.Results;
// Define operations that can fail (assumes repository doesn't throw exceptions)
public Result<User> GetUser(int id)
{
var user = _repository.Find(id);
return user is not null
? user // Implicit conversion: User โ Result<User>
: Error.NotFoundError($"User {id} not found");
}
public Result<Order> GetLatestOrder(User user)
{
var order = _repository.GetLatestOrder(user.Id);
return order is not null
? order
: Error.NotFoundError("No orders found");
}
// Chain operations with Railway Oriented Programming
var result = GetUser(123)
.Bind(user => GetLatestOrder(user))
.Map(order => order.TotalAmount)
.Tap(total => _logger.LogInfo($"Total: {total}"));
// Handle the result
var message = result.Match(
onSuccess: total => $"Order total: {total:C}",
onFailure: error => $"Error: {error.Message}"
);
๐งช Testing
The library includes a comprehensive test suite ensuring correctness across multiple dimensions:
- Monad Laws - Verifies mathematical properties of Result<T> (identity, composition)
- Invariants - XOR property, null safety, immutability guarantees
- Error Propagation - Correct error flow through all operators and chains
- Composition - Operator chaining and combination behavior in complex scenarios
- Unit Tests - Core functionality, extension methods, edge cases, and cancellation
All tests validate behavior on both .NET 8.0 and .NET Framework 4.8 to ensure cross-platform compatibility.
๐ Documentation
Core Types
Result<T>- Represents an operation that returns a value or an errorResult- Represents an operation that returns success or an error (void operations)Error- Represents an error with type and message
Error Types
Error.ValidationError("Invalid email format")
Error.NotFoundError("User not found")
Error.UnauthorizedError("User not logged in")
Error.PermissionError("Access denied")
Error.ConflictError("Email already exists")
Error.DatabaseError("Connection failed")
Error.BusinessError("Cannot cancel paid order")
Error.UnavailableError("Service temporarily unavailable")
Error.TimeoutError("Request timed out")
Error.CancelledError("Operation was cancelled")
Error.TooManyRequestsError("Rate limit exceeded") // HTTP 429
Error.CircuitBreakerOpenError(lastError) // Circuit breaker open
Error.UnexpectedError("Something went wrong")
Error.FromException(exception) // Auto-maps exception type to ErrorType
Error Classification (ADR-005)
Use extension methods to classify errors for resilience patterns:
using Voyager.Common.Results.Extensions;
error.Type.IsTransient() // Timeout, Unavailable, TooManyRequests, CircuitBreakerOpen
error.Type.IsBusinessError() // Validation, NotFound, Permission, etc.
error.Type.ShouldRetry() // Same as IsTransient
error.Type.ToHttpStatusCode() // Maps to HTTP status code
Error Chaining (ADR-006)
Track error origin across distributed service calls:
// Chain errors (like InnerException)
var error = Error.UnavailableError("Order failed")
.WithInner(productServiceError);
// Find root cause
var rootCause = error.GetRootCause();
// Check chain for specific error type
if (error.HasInChain(e => e.Type == ErrorType.NotFound)) { }
// Add context when calling external services
var result = await _productService.GetAsync(id)
.AddErrorContextAsync("ProductService", "GetProduct");
Enhanced FromException (ADR-007)
FromException now preserves full diagnostic info and auto-maps exception types:
var error = Error.FromException(exception);
// Auto-maps: TimeoutException โ Timeout, ArgumentException โ Validation, etc.
// Preserves: StackTrace, ExceptionType, Source, InnerException chain
// Override auto-mapping
var error = Error.FromException(exception, ErrorType.Database);
// Detailed logging output
_logger.LogError(error.ToDetailedString());
// [Database] Exception.SqlException: Connection failed
// Stack Trace: at Repository.Query() in Repository.cs:line 42
// Caused by: [Unavailable] Exception.SocketException: Network unreachable
Railway Oriented Programming
GetUser(id)
.Map(user => user.Email) // Transform success value
.Bind(email => SendEmail(email)) // Chain another Result operation
.Ensure(sent => sent, Error.BusinessError("Email not sent"))
.Tap(() => _logger.LogInfo("Email sent")) // Side effect
.OrElse(() => GetDefaultUser()) // Fallback if failed
.Match(
onSuccess: () => "Success",
onFailure: error => error.Message
);
Finally - Resource Cleanup
Executes an action regardless of success or failure (like finally block):
// Chain with other operations
var result = GetUser(id)
.Map(user => user.Email)
.Tap(email => _logger.LogInfo(email))
.Finally(() => _metrics.RecordOperation());
When to use Finally:
- โ Resource cleanup (close connections, dispose streams)
- โ Logging/metrics regardless of outcome
- โ Releasing locks or semaphores
- โ Any cleanup that must happen in both success and failure paths
Try - Exception Handling
Safely convert exception-throwing code into Result pattern:
// Basic: wraps exceptions with Error.FromException
var result = Result<int>.Try(() => int.Parse(userInput));
// Custom error mapping
var result = Result<int>.Try(
() => int.Parse(userInput),
ex => ex is FormatException
? Error.ValidationError("Invalid number format")
: Error.FromException(ex));
// Void operations
var result = Result.Try(() => File.Delete(path));
// With custom error handling
var result = Result.Try(
() => File.Delete(path),
ex => ex is UnauthorizedAccessException
? Error.PermissionError("Access denied")
: Error.FromException(ex));
// Chain with other operations
var userData = Result<string>.Try(() => File.ReadAllText(path))
.Bind(json => ParseJson(json))
.Map(data => data.UserId);
// Robust database operations (handles both exceptions and null)
public Result<User> GetUser(int id)
{
return Result<User>.Try(() => _repository.Find(id))
.Ensure(user => user is not null, Error.NotFoundError($"User {id} not found"));
}
When to use Try:
- โ Wrapping third-party APIs that throw exceptions
- โ File I/O, parsing, network calls
- โ Converting legacy exception-based code to Result pattern
- โ Custom exception-to-error mapping
TryAsync - Async Exception Handling
Safely convert async exception-throwing code into Result pattern. Automatically maps OperationCanceledException to ErrorType.Cancelled when using CancellationToken:
// Preferred: Use Result<T>.TryAsync proxy for cleaner syntax
var result = await Result<Config>.TryAsync(async () =>
await JsonSerializer.DeserializeAsync<Config>(stream));
// With CancellationToken support (auto-maps OperationCanceledException โ ErrorType.Cancelled)
var result = await Result<string>.TryAsync(
async ct => await httpClient.GetStringAsync(url, ct),
cancellationToken);
// Custom error mapping
var result = await Result<Config>.TryAsync(
async () => await JsonSerializer.DeserializeAsync<Config>(stream),
ex => ex is JsonException
? Error.ValidationError("Invalid JSON")
: Error.UnexpectedError(ex.Message));
// With CancellationToken and custom error mapping
var result = await Result<string>.TryAsync(
async ct => await httpClient.GetStringAsync(url, ct),
cancellationToken,
ex => ex is HttpRequestException
? Error.UnavailableError("Service unavailable")
: Error.UnexpectedError(ex.Message));
// Chain with other async operations
var userData = await Result<string>.TryAsync(async () =>
await File.ReadAllTextAsync(path))
.BindAsync(json => ParseJsonAsync(json))
.MapAsync(data => data.UserId);
When to use TryAsync:
- โ Async file I/O, database operations
- โ HTTP/API calls with cancellation support
- โ Async parsing and serialization
- โ Converting async exception-based code to Result pattern
- โ Operations that need proper cancellation handling
Retry - Transient Failure Handling
Handle temporary failures (network issues, service unavailability) with automatic retry logic:
using Voyager.Common.Results.Extensions;
// Basic retry with default policy (3 attempts, exponential backoff)
var result = await GetDatabaseConnection()
.BindWithRetryAsync(
conn => ExecuteQuery(conn),
RetryPolicies.TransientErrors()
);
// Custom retry configuration
var result = await FetchDataAsync()
.BindWithRetryAsync(
data => ProcessData(data),
RetryPolicies.TransientErrors(maxAttempts: 5, baseDelayMs: 500)
);
// Custom retry policy for specific errors
var policy = RetryPolicies.Custom(
maxAttempts: 10,
shouldRetry: e => e.Type == ErrorType.Unavailable || e.Code == "RATE_LIMIT",
delayStrategy: attempt => 500 // Fixed 500ms delay
);
var result = await apiCall.BindWithRetryAsync(ProcessResponse, policy);
// Retry automatically handles:
// โ
ErrorType.Unavailable - Service down, network issues, deadlocks
// โ
ErrorType.Timeout - Operation exceeded time limit
// โ Permanent errors (Validation, NotFound, etc.) - NOT retried
Key features:
- ๐ Exponential backoff by default (1s โ 2s โ 4s โ ...)
- ๐ฏ Only retries transient errors (
Unavailable,Timeout) - ๐ Always preserves original error - never generic "max retries exceeded"
- โก Zero external dependencies
- ๐ง Fully customizable via
RetryPolicies.Custom() - ๐ Retry attempt callbacks for logging and metrics
Retry Attempt Callbacks:
var result = await operation.BindWithRetryAsync(
async value => await _httpClient.GetAsync(value),
RetryPolicies.TransientErrors(maxAttempts: 3),
onRetryAttempt: (attempt, error, delayMs) =>
{
_logger.LogWarning(
"Attempt {Attempt} failed: {Error}. Retrying in {Delay}ms",
attempt, error.Message, delayMs);
_metrics.IncrementRetryCounter(error.Type.ToString());
});
When to use Retry:
- โ Network calls with temporary failures
- โ Database operations during brief unavailability
- โ API calls that may be rate-limited or temporarily down
- โ NOT for permanent errors (Validation, NotFound)
- ๐ก For cascading failure prevention, use Circuit Breaker from Voyager.Common.Resilience
Circuit Breaker - Cascading Failure Prevention
(Requires Voyager.Common.Resilience package)
Prevent cascading failures by temporarily blocking calls to failing services:
using Voyager.Common.Resilience;
// Create a circuit breaker policy
var policy = new CircuitBreakerPolicy(
failureThreshold: 5, // Open after 5 consecutive failures
openTimeout: TimeSpan.FromSeconds(30), // Stay open for 30s
halfOpenMaxAttempts: 3 // Allow 3 test attempts when half-open
);
// Execute operations through the circuit breaker
var result = await GetUser(userId)
.BindWithCircuitBreakerAsync(
user => CallExternalServiceAsync(user),
policy
);
// Circuit breaker states:
// ๐ข Closed - Normal operation, requests flow through
// ๐ด Open - Too many failures, requests immediately fail with CircuitBreakerOpenError
// ๐ก HalfOpen - Testing if service recovered, limited attempts allowed
// Check circuit state
if (policy.State == CircuitBreakerState.Open)
{
_logger.LogWarning("Circuit breaker is open, service unavailable");
}
// Manual reset if needed
policy.Reset();
Key features:
- ๐ก๏ธ Prevents cascading failures across distributed systems
- โก Fast-fail when service is down (no wasted retries)
- ๐ Automatic recovery testing via half-open state
- ๐งต Thread-safe with SemaphoreSlim for async operations
- ๐ Preserves last error context via
CircuitBreakerOpenError(lastError) - ๐ฏ Returns
ErrorType.CircuitBreakerOpenwhen circuit is open - ๐ Only counts infrastructure errors (Unavailable, Timeout, Database, Unexpected)
- โ Ignores business errors (Validation, NotFound, Permission, Business, Conflict)
- ๐ State change callbacks for logging, alerting, and metrics
State Change Callbacks:
var policy = new CircuitBreakerPolicy(failureThreshold: 5);
// Subscribe to state changes
policy.OnStateChanged = (oldState, newState, failureCount, lastError) =>
{
_logger.LogWarning(
"Circuit breaker: {OldState} โ {NewState}, failures: {Count}",
oldState, newState, failureCount);
if (newState == CircuitState.Open)
{
_alertService.SendAlert($"Circuit OPEN: {lastError?.Message}");
_metrics.IncrementCounter("circuit_breaker_opened");
}
};
When to use Circuit Breaker:
- โ External API/service calls that may fail
- โ Database operations during outages
- โ Microservice communication
- โ Any operation where cascading failures must be prevented
- ๐ก Combine with Retry for comprehensive resilience
When to use Retry:
- โ Network calls with temporary failures
- โ Database operations during brief unavailability
- โ API calls that may be rate-limited or temporarily down
- โ NOT for permanent errors (Validation, NotFound)
- ๐ก For cascading failure prevention, use Circuit Breaker from Voyager.Common.Resilience
Map - Value Transformations
Transform success values or convert void operations to value operations:
// Transform Result<T> values
var emailResult = GetUser(id)
.Map(user => user.Email); // Result<User> โ Result<string>
// Convert Result (void) to Result<T> (value)
var numberResult = ValidateInput()
.Map(() => 42); // Result โ Result<int>
// Chain transformations
var result = GetUser(id)
.Map(user => user.Email)
.Map(email => email.ToLower())
.Map(email => email.Trim());
When to use Map:
- โ Transform success value to another type
- โ Convert void success to value success
- โ Simple, non-failing transformations
- โ Don't use for operations that return Result (use
Bindinstead)
MapError - Error Transformation
Transform errors without affecting success:
// Add context to errors
var result = Operation()
.MapError(error => Error.DatabaseError("DB_" + error.Code, error.Message));
// Convert error types
var result = ValidateUser()
.MapError(error => Error.BusinessError("USER_" + error.Code, error.Message));
// Chain transformations
var result = GetData()
.MapError(e => Error.UnavailableError("Service unavailable: " + e.Message))
.TapError(e => _logger.LogError(e.Message));
When to use MapError:
- โ Add prefixes or context to error codes/messages
- โ Convert error types for different layers (API โ Domain โ Infrastructure)
- โ Enrich errors with additional information
- โ Standardize error formats
Bind - Chaining Operations
The Bind method is available on both Result and Result<T> for seamless operation chaining:
// Chain void operations (Result โ Result)
var result = ValidateInput()
.Bind(() => AuthorizeUser())
.Bind(() => SaveToDatabase())
.Bind(() => SendNotification());
// Transform void operation to value operation (Result โ Result<T>)
var userResult = ValidateRequest()
.Bind(() => GetUser(userId))
.Map(user => user.Email);
// Mix void and value operations
var orderResult = AuthenticateUser() // Result
.Bind(() => GetShoppingCart(userId)) // Result โ Result<Cart>
.Bind(cart => ProcessOrder(cart)) // Result<Cart> โ Result<Order>
.Map(order => order.Id); // Result<Order> โ Result<int>
When to use Bind:
- โ
Chain operations that return
Result<T> - โ
Transform
Result(void) toResult<T>(value) - โ Maintain railway oriented flow
- โ Don't use for simple value transformations (use
Mapinstead)
OrElse - Fallback Pattern
// Try multiple data sources - returns first success
var user = GetUserFromCache(userId)
.OrElse(() => GetUserFromDatabase(userId))
.OrElse(() => GetDefaultUser());
// Async version
var config = await LoadConfigFromFileAsync()
.OrElseAsync(() => LoadConfigFromDatabaseAsync())
.OrElseAsync(() => GetDefaultConfigAsync());
// Real-world example: Multi-tier data retrieval
var data = await GetFromPrimaryCacheAsync(key)
.OrElseAsync(() => GetFromDatabaseAsync(key))
.OrElseAsync(() => GetFromApiAsync(key))
.OrElseAsync(Result<Data>.Success(defaultValue));
Common use cases:
- Cache โ Database โ Default value
- Primary API โ Fallback API โ Cached data
- User preferences โ Team defaults โ System defaults
Ensure - Contextual Validation
Validate with error messages that include the actual value:
// Static error (old way)
var result = GetUser(id)
.Ensure(
user => user.Age >= 18,
Error.ValidationError("Must be 18 or older"));
// Contextual error (recommended - provides better error messages)
var result = GetUser(id)
.Ensure(
user => user.Age >= 18,
user => Error.ValidationError($"User {user.Name} is {user.Age} years old, must be 18+"));
EnsureAsync - Async Contextual Validation
Validate with async predicates and contextual errors:
// With sync predicate
var result = await GetUserAsync(id)
.EnsureAsync(
user => user.Age >= 18,
user => Error.ValidationError($"User {user.Name} is {user.Age}, must be 18+"));
// With async predicate
var result = await GetUserAsync(id)
.EnsureAsync(
async user => await _repo.IsActiveAsync(user.Id),
user => Error.ValidationError($"User {user.Name} is inactive"));
Instance Method Proxies
No need to import Extensions namespace - common async methods are available directly on Result<T>:
var result = await GetUser(id) // Result<User>
.EnsureAsync(
async u => await _repo.IsActiveAsync(u.Id),
u => Error.ValidationError($"User {u.Name} inactive"))
.TapAsync(async u => await _audit.LogAsync($"Access: {u.Id}"))
.OrElseAsync(() => GetDefaultUserAsync());
Available instance proxies:
EnsureAsync(asyncPredicate, error)- async validationEnsureAsync(asyncPredicate, errorFactory)- async validation with contextual errorTapAsync(asyncAction)- async side effectsOrElseAsync(asyncAlternativeFunc)- async fallback
Async Operations
await GetUserAsync(id)
.MapAsync(user => user.Email)
.BindAsync(email => SendEmailAsync(email))
.TapAsync(() => _logger.LogInfoAsync("Email sent"));
Collection Operations
var results = new Result<int>[] {
1, // Implicit conversion: int โ Result<int>
2,
3
};
// Combine all results into one
Result<List<int>> combined = results.Combine();
// Partition into successes and failures
var (successes, failures) = results.Partition();
// Get only successful values
List<int> values = results.GetSuccessValues();
// Combine two Results into a tuple
var name = Result<string>.Success("Alice");
var age = Result<int>.Success(30);
Result<(string, int)> pair = name.Combine(age);
Async Collection Operations (v1.9.0)
// TraverseAsync โ sequential async, fail-fast
var result = await operations.TraverseAsync(
x => OperationUpdateResultAsync(ctx, x.op, x.data));
// TraverseAllAsync โ sequential async, collect ALL errors
var result = await items.TraverseAllAsync(
x => ValidateAndProcessAsync(x));
// CombineAsync โ await all tasks, then combine
var tasks = items.Select(x => ProcessAsync(x));
var result = await tasks.CombineAsync();
// PartitionAsync โ await all tasks, then partition
var (successes, failures) = await tasks.PartitionAsync();
See Collection Operations for detailed documentation.
Analyzer - Result Must Be Consumed (VCR0010)
The package includes a built-in Roslyn analyzer that warns when a Result or Result<T> return value is silently discarded. This prevents a common mistake where errors are lost because nobody checked the result:
GetUser(id); // โ ๏ธ VCR0010: Result of 'GetUser' must be checked
await SendEmailAsync(email); // โ ๏ธ VCR0010: Result of 'SendEmailAsync' must be checked
Result.Success(); // โ ๏ธ VCR0010: Result of 'Success' must be checked
// โ
All of these are fine - result is consumed:
var result = GetUser(id); // Assigned to variable
_ = GetUser(id); // Explicitly discarded
if (GetUser(id).IsSuccess) { } // Used in condition
return GetUser(id); // Returned
Log(GetUser(id)); // Passed as argument
GetUser(id).Match(...); // Used in method chain
The analyzer is bundled in the NuGet package - no extra installation needed. Two quick-fixes are available:
- Discard result (
_ = ...) - when you intentionally want to ignore the result - Assign to variable (
var result = ...) - when you want to handle it later
Additional Analyzers
The package includes a full suite of Roslyn analyzers that catch common Result pattern mistakes:
| ID | Severity | Description |
|---|---|---|
| VCR0010 | Warning | Result must be consumed โ unconsumed Result / Result<T> return values |
| VCR0020 | Warning | Value accessed without success check โ result.Value without IsSuccess guard |
| VCR0030 | Warning | Nested Result<Result<T>> โ use Bind instead of Map |
| VCR0040 | Info | GetValueOrThrow defeats Result pattern โ prefer Match/Bind/Map |
| VCR0050 | Error | Failure(Error.None) โ failure without error is always a bug |
| VCR0060 | Disabled | Prefer Match/Switch over if (IsSuccess) branching (opt-in style rule) |
| VCR0070 | Warning | Success(null) โ successful result must carry a value, not null |
| VCR0071 | Disabled | Result<T?> โ nullable type parameter suggests missing Failure modeling (opt-in) |
var result = GetUser(id);
result.Value.Name; // โ ๏ธ VCR0020: Access 'Value' without checking 'IsSuccess'
result.Map(x => GetOrder(x.Id)); // โ ๏ธ VCR0030: Nested Result<Result<Order>>, use Bind
GetUser(id).GetValueOrThrow(); // โน๏ธ VCR0040: Consider Match/Bind instead
Result.Failure(Error.None); // โ VCR0050: Failure with Error.None is a bug
Result<Order?>.Success(null); // โ ๏ธ VCR0070: Success(null) defeats Result pattern
All analyzers are configurable via .editorconfig:
dotnet_diagnostic.VCR0040.severity = none # Disable
dotnet_diagnostic.VCR0060.severity = warning # Enable opt-in rule
๐ More Examples
See the full documentation for detailed examples and best practices.
๐๏ธ Building and Publishing
See BUILD.md for comprehensive instructions on:
- ๐ค Automatic publishing with GitHub Actions (recommended)
- ๐จ Manual building and local testing
- ๐ฆ Publishing to GitHub Packages and NuGet.org
- ๐งช Running tests with code coverage
New to versioning? See Quick Start - Versioning for a 3-step guide to create your first release.
Quick Build
# Restore dependencies
dotnet restore
# Build the solution
dotnet build -c Release
# Run tests
dotnet test -c Release
# Pack the package
dotnet pack src/Voyager.Common.Results/Voyager.Common.Results.csproj -c Release
Automatic Publishing
Simply push to main branch - GitHub Actions will:
- โ Automatically bump version
- โ Build for both .NET 8.0 and .NET Framework 4.8
- โ Run all tests
- โ Publish to GitHub Packages
- โ Publish to NuGet.org (if configured)
git add .
git commit -m "Add new feature"
git push origin main
๐งช Running Tests
# Run all tests
dotnet test
# Run with code coverage
dotnet test --collect:"XPlat Code Coverage"
# Generate coverage report (requires reportgenerator)
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator -reports:**/coverage.cobertura.xml -targetdir:coverage-report -reporttypes:Html
Development Workflow
- Push to
maintriggers automatic version bump and publishing - All tests must pass before merging
- Follow existing code style and conventions
- Add tests for new features
- Update documentation as needed
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
Inspired by:
- Railway Oriented Programming by Scott Wlaschin
- Result type in Rust
- Either type in functional programming
๐ Changelog
See CHANGELOG.md for a list of changes.
๐ Additional Resources
- GitHub Actions Setup Guide - Detailed GitHub Actions configuration
- Build Guide - Building and publishing instructions
- API Documentation - Complete API reference
Made with โค๏ธ by Voyager Poland
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. 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 was computed. 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 Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- No dependencies.
-
net6.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (5)
Showing the top 5 NuGet packages that depend on Voyager.Common.Results:
| Package | Downloads |
|---|---|
|
Voyager.DBConnection
Modern, testable database access library using DbProviderFactory with Result monad pattern for explicit error handling. Features IDbCommandExecutor interface for easy mocking, command factory pattern for separation of concerns, and fluent parameter API. Supports SQL Server, PostgreSQL, MySQL, Oracle, SQLite, and ODBC for universal database connectivity. |
|
|
Voyager.Common.Proxy.Abstractions
Abstractions and attributes for Voyager.Common.Proxy - HTTP service proxy generation |
|
|
Voyager.Common.Resilience
Resilience patterns (Circuit Breaker) for Railway Oriented Programming - extends Voyager.Common.Results with stateful fault tolerance patterns |
|
|
Voyager.Common.Proxy.Server.Core
Core logic for Voyager.Common.Proxy.Server - service scanning, endpoint metadata building, and request dispatching. |
|
|
Voyager.Common.Proxy.Client
HTTP client proxy generation for C# interfaces with Result<T> support |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.11.0-preview.1 | 38 | 3/9/2026 |
| 1.10.0 | 393 | 2/26/2026 |
| 1.10.0-preview.1.4 | 51 | 2/26/2026 |
| 1.10.0-preview.1 | 45 | 2/26/2026 |
| 1.9.1-preview.1 | 49 | 2/25/2026 |
| 1.9.0 | 933 | 2/19/2026 |
| 1.9.0-preview.1.2 | 46 | 2/19/2026 |
| 1.9.0-preview.1 | 49 | 2/18/2026 |
| 1.8.0 | 438 | 2/16/2026 |
| 1.8.0-preview.1.1 | 50 | 2/16/2026 |
| 1.8.0-preview.1 | 47 | 2/16/2026 |
| 1.7.3-preview.2 | 50 | 2/16/2026 |
| 1.7.2 | 112 | 2/14/2026 |
| 1.7.2-preview.6.3 | 52 | 2/14/2026 |
| 1.7.2-preview.6 | 51 | 2/13/2026 |
| 1.7.2-preview.5 | 54 | 2/13/2026 |
| 1.7.2-preview.4 | 52 | 2/13/2026 |
| 1.7.2-preview.3 | 51 | 2/13/2026 |
| 1.7.2-preview.2 | 47 | 2/13/2026 |
| 1.7.2-preview | 86 | 2/13/2026 |
See CHANGELOG.md for release history