REslava.Result.SourceGenerators
1.15.0
Prefix Reserved
See the version list below for details.
dotnet add package REslava.Result.SourceGenerators --version 1.15.0
NuGet\Install-Package REslava.Result.SourceGenerators -Version 1.15.0
<PackageReference Include="REslava.Result.SourceGenerators" Version="1.15.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="REslava.Result.SourceGenerators" Version="1.15.0" />
<PackageReference Include="REslava.Result.SourceGenerators"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add REslava.Result.SourceGenerators --version 1.15.0
#r "nuget: REslava.Result.SourceGenerators, 1.15.0"
#:package REslava.Result.SourceGenerators@1.15.0
#addin nuget:?package=REslava.Result.SourceGenerators&version=1.15.0
#tool nuget:?package=REslava.Result.SourceGenerators&version=1.15.0
REslava.Result - Railway-Oriented Programming for .NET
<div align="center">
๐ Complete Functional Programming Framework + ASP.NET Integration + OneOf Extensions
</div>
Why REslava.Result?
The only .NET library that combines functional error handling with compile-time ASP.NET API generation.
| REslava.Result | FluentResults | ErrorOr | LanguageExt | |
|---|---|---|---|---|
| Result<T> pattern | โ | โ | โ | โ |
| OneOf discriminated unions | โ (2-4 types) | โ | โ | โ |
| Maybe<T> | โ | โ | โ | โ |
| ASP.NET source generators | โ | โ | โ | โ |
| SmartEndpoints (zero-boilerplate APIs) | โ | โ | โ | โ |
| OpenAPI metadata auto-generation | โ | โ | โ | โ |
| Authorization & Policy support | โ | โ | โ | โ |
| Roslyn safety analyzers | โ | โ | โ | โ |
| Validation framework | โ | Basic | โ | โ |
| Zero dependencies | โ | โ | โ | โ |
Unique advantage: SmartEndpoints auto-generates complete Minimal API endpoints from your business logic โ including routing, DI, HTTP status mapping, error handling, full OpenAPI metadata (.Produces<T>(), .WithSummary(), .WithTags()), and authorization (.RequireAuthorization(), .AllowAnonymous()). No other .NET library does this.
๐ Table of Contents
| ๐ฏ Section | ๐ Description |
|---|---|
| ๐ Quick Start | Installation and complete generator showcase |
| ๐ Choose Your Path | Find exactly what you need |
| ๐ฏ The Transformation: 70-90% Less Code | See how boilerplate disappears |
| ๐ REslava.Result Core Library | Functional programming foundation |
| ๐ ASP.NET Integration | ResultToIResult and HTTP mapping |
| ๐ง Advanced Patterns | Maybe, LINQ, functional composition |
| ๐ Complete Architecture | How generators work internally |
| ๐ฆ Package Structure | What you get with each package |
| ๐ฏ Quick Examples | Real-world code samples |
| ๐ Production Benefits | Enterprise-ready advantages |
| ๐งช Testing & Quality Assurance | 2,004+ tests passing |
| ๐ข Real-World Impact | Success stories and use cases |
| ๐ Why Choose REslava.Result? | Unique advantages |
| ๐ Deep Dive Documentation | Comprehensive guides |
| ๐งช Quick Start Scenarios | Hands-on tutorials |
| ๐ฏ Roadmap | Future development plans |
| ๐ค Contributing | How to contribute |
| ๐ License | MIT License details |
| ๐ Acknowledgments | Community credits |
| ๐ Version History | Release notes and changes |
๐ Quick Start
Installation
dotnet add package REslava.Result # Core library
dotnet add package REslava.Result.SourceGenerators # ASP.NET source generators
dotnet add package REslava.Result.Analyzers # Roslyn safety analyzers
Complete Generator Showcase
โก SmartEndpoints - Zero-Boilerplate Fast APIs
Generate complete Minimal APIs from controllers with automatic HTTP mapping!
[AutoGenerateEndpoints(RoutePrefix = "/api/users")]
public class UserController {
private readonly UserService _service;
public UserController(UserService service) => _service = service;
// ๐ DI + async โ Automatic REST API with dependency injection!
public async Task<OneOf<ValidationError, NotFoundError, User>>
GetUser(int id) => await _service.GetUserByIdAsync(id);
public async Task<OneOf<ValidationError, ConflictError, User>>
CreateUser(CreateUserRequest request) => await _service.CreateAsync(request);
public async Task<Result<List<User>>> GetUsers()
=> await _service.GetAllAsync();
}
๐ Generated Minimal API (Zero Manual Code!)
- โ
POST /api/usersโ 201/400/404/409 (OneOf4 auto-mapping!) - โ
GET /api/users/{id}โ 200/404 (OneOf2 auto-mapping!) - โ
Full OpenAPI metadata โ
.Produces<T>(200),.Produces(404),.WithSummary(),.WithTags()auto-generated from return types - โ Error handling automatically configured
- โ HTTP status mapping automatically applied
- โ
Route grouping via
MapGroupwith automatic tag generation
๐ฅ Development Speed: 10x Faster
- No manual route setup - automatic from method names
- No manual error handling - automatic from return types
- No manual status codes - automatic from error types
- No manual API docs - OpenAPI + Scalar UI automatically generated
- Self-explanatory code - business logic only
๐ OneOf Extensions - Intelligent HTTP Mapping
Automatic error detection and HTTP status mapping for OneOf types:
// Error Types โ HTTP Status Codes
ValidationError โ 400 Bad Request
UserNotFoundError โ 404 Not Found
ConflictError โ 409 Conflict
UnauthorizedError โ 401 Unauthorized
ForbiddenError โ 403 Forbidden
ServerError โ 500 Internal Server Error
Supported Patterns:
- OneOf2ToIResult<T1,T2> - Two-type error handling
- OneOf3ToIResult<T1,T2,T3> - Three-type error handling
- ๐ OneOf4ToIResult<T1,T2,T3,T4> - Four-type error handling (NEW v1.12.0!)
- SmartEndpoints Integration - Uses extensions automatically in generated APIs
๐ Enhanced SmartEndpoints + OpenAPI Metadata (NEW!)
Feature: Full OpenAPI metadata auto-generated at compile time from return types Benefits: Scalar/Swagger UI shows typed responses, status codes, summaries, and tags โ zero manual configuration Use Case: Production-ready APIs with complete documentation from day one
๐ฅ What Makes SmartEndpoints Revolutionary:
// โ
YOU WRITE: Pure business logic (5 lines)
[AutoGenerateEndpoints(RoutePrefix = "/api/orders")]
public class SmartOrderController {
public async Task<OneOf<UserNotFoundError, InsufficientStockError, ValidationError, OrderResponse>>
CreateOrder(CreateOrderRequest request) => await _service.CreateOrderAsync(request);
}
// ๐ GENERATOR PRODUCES: Complete endpoint with full OpenAPI metadata
var smartOrderGroup = endpoints.MapGroup("/api/orders")
.WithTags("Smart Order");
smartOrderGroup.MapPost("/", async (CreateOrderRequest request, SmartOrderController service) =>
{
var result = await service.CreateOrder(request);
return result.ToIResult();
})
.WithName("SmartOrder_CreateOrder")
.WithSummary("Create order")
.Produces<OrderResponse>(200)
.Produces(400) // โ ValidationError
.Produces(404) // โ UserNotFoundError
.Produces(409); // โ InsufficientStockError
๐ฏ Everything Auto-Generated from Return Types:
- Method name โ HTTP method +
.WithName()(CreateOrderโPOST+SmartOrder_CreateOrder) - Class name โ
.WithTags()+MapGroup()(SmartOrderControllerโ"Smart Order") - PascalCase โ
.WithSummary()(CreateOrderโ"Create order") - Success type โ
.Produces<T>(200)(OrderResponseโ typed 200 response) - Error types โ
.Produces(statusCode)(UserNotFoundErrorโ 404,InsufficientStockErrorโ 409) - Parameters โ Route/body binding (
int idโ/{id},requestโ JSON body)
โก Zero Boilerplate Benefits:
- No manual route configuration - inferred from class/method names
- No manual error handling - automatic from OneOf types
- No manual status codes - automatic from error type names
- No manual OpenAPI metadata -
.Produces(),.WithSummary(),.WithTags()all auto-generated - No manual endpoint names - globally unique names from controller + method
- No manual ProblemDetails - automatic RFC 7807 compliance
๐ฏ ResultToIResult Extensions
Convert Result<T> types to proper HTTP responses:
public Result<User> GetUser(int id) { /* ... */ }
return GetUser(id).ToIResult(); // Automatic HTTP mapping
app.MapGet("/users/{id}", async (int id, IUserService service) =>
{
return await service.GetUserAsync(id); // Auto-converts to HTTP response!
});
// ๐ v1.10.0: OneOf extensions also work!
app.MapGet("/users/oneof/{id}", async (int id) =>
{
return GetOneOfUser(id); // Auto-converts OneOf<T1,T2,T3> too!
});
๐ก๏ธ Safety Analyzers โ Compile-Time Diagnostics
Catch common Result<T> and OneOf mistakes at compile time with 4 diagnostics and 2 code fixes:
// RESL1001 โ Unsafe .Value access without guard [Warning + Code Fix]
var result = GetUser(id);
var name = result.Value; // โ ๏ธ Warning: Access to '.Value' without checking 'IsSuccess'
// ๐ก Fix A: Wrap in if (result.IsSuccess) { ... }
// ๐ก Fix B: Replace with result.Match(v => v, e => default)
// โ
Safe alternatives:
if (result.IsSuccess)
var name = result.Value; // No warning โ guarded by IsSuccess
var name = result.Match( // No warning โ pattern matching
onSuccess: u => u.Name,
onFailure: _ => "Unknown");
// RESL1002 โ Discarded Result<T> return value [Warning]
Save(); // โ ๏ธ Warning: Return value of type 'Result<T>' is discarded
await SaveAsync(); // โ ๏ธ Warning: errors silently swallowed
// โ
Safe alternatives:
var result = Save(); // No warning โ assigned
return Save(); // No warning โ returned
// RESL1003 โ Prefer Match() over if-check [Info suggestion]
if (result.IsSuccess) // โน๏ธ Suggestion: Consider using Match() instead
{
var x = result.Value;
}
else
{
var e = result.Errors;
}
// โ
Cleaner with Match():
var x = result.Match(v => v, e => HandleErrors(e));
// RESL2001 โ Unsafe OneOf.AsT* access without IsT* check [Warning + Code Fix]
var oneOf = GetResult(); // OneOf<User, NotFound, ValidationError>
var user = oneOf.AsT1; // โ ๏ธ Warning: Access to '.AsT1' without checking '.IsT1'
// ๐ก Fix: Replace with oneOf.Match(t1 => t1, t2 => throw ..., t3 => throw ...)
// โ
Safe alternatives:
if (oneOf.IsT1)
var user = oneOf.AsT1; // No warning โ guarded
var user = oneOf.Match( // No warning โ exhaustive
user => user,
notFound => throw ...,
error => throw ...);
dotnet add package REslava.Result.Analyzers
๐ Choose Your Path
Find exactly what you need based on your goals:
| ๐ฏ I'm building a... | ๐ Start Here | ๐ What You'll Learn |
|---|---|---|
| Web API | ๐ ASP.NET Integration | Auto-conversion, error mapping, OneOf extensions |
| Library/Service | ๐ Core Library | Result pattern, validation, functional programming |
| Custom Generator | ๐ Custom Generator Guide | Build your own source generators |
| Advanced App | ๐ง Advanced Patterns | Maybe, OneOf, validation rules |
| Testing | ๐งช Testing & Quality | 2,004+ tests, CI/CD, test strategies |
| Curious About Magic | ๐ Complete Architecture | How generators work, SOLID design |
๐ฏ The Transformation: 70-90% Less Code
See how REslava.Result eliminates boilerplate in real .NET 10 applications:
โ BEFORE: Traditional Minimal API
// Manual error handling, validation, and HTTP responses
app.MapPost("/users", async (CreateUserRequest request, IUserService service) =>
{
// Manual validation
if (string.IsNullOrWhiteSpace(request.Email))
return Results.BadRequest(new { error = "Email required" });
if (!IsValidEmail(request.Email))
return Results.BadRequest(new { error = "Invalid email" });
// Manual duplicate checking
if (await EmailExistsAsync(request.Email))
return Results.Conflict(new { error = "Email already exists" });
try
{
var user = await service.CreateUserAsync(request);
return Results.Created($"/users/{user.Id}", user);
}
catch (ValidationException ex)
{
return Results.BadRequest(new { errors = ex.Errors });
}
catch (Exception ex)
{
return Results.Problem("Internal server error");
}
});
โ AFTER: REslava.Result Magic
// Clean, declarative, type-safe - 3 lines instead of 25+
app.MapPost("/users", async (CreateUserRequest request) =>
await CreateUser(request));
// Service layer handles everything elegantly
public async Task<Result<User>> CreateUser(CreateUserRequest request) =>
await Result<CreateUserRequest>.Ok(request)
.Ensure(r => !string.IsNullOrWhiteSpace(r.Email), "Email required")
.Ensure(r => IsValidEmail(r.Email), "Invalid email format")
.EnsureAsync(async r => !await EmailExistsAsync(r.Email), "Email already exists")
.BindAsync(async r => await _userService.CreateUserAsync(r))
.WithSuccess("User created successfully");
๐ Result: 70-90% less code, 100% type-safe, automatic HTTP responses, rich error context!
๐ REslava.Result Core Library
๐ง Functional Programming Foundation
Railway-Oriented Programming (ROP)
- Immutable Results: Thread-safe functional data structures
- Error Composition: Chain operations without exception handling
- Success/Failure Pipelines: Clean separation of happy and error paths
- Type Safety: Compile-time guarantees for error handling
๐ง Complete Method Catalog
Core Operations
// Factory Methods
Result<T>.Ok(value) // Success result
Result<T>.Fail("error") // Failure result
Result.Fail("error") // Non-generic failure
// Pattern Matching
result.Match(
onSuccess: value => DoSomething(value),
onFailure: errors => HandleErrors(errors)
);
// Value Access
result.Value // Throws if failed
result.GetValueOrDefault(defaultValue) // Safe access
Functional Composition
// Bind (Chain operations)
var result = Result<int>.Ok(5)
.Bind(x => Result<string>.Ok(x.ToString()))
.Bind(s => ValidateEmail(s));
// Map (Transform success values)
var result = Result<int>.Ok(5)
.Map(x => x * 2)
.Map(x => x.ToString());
// Tap (Side effects without changing result)
var result = Result<User>.Ok(user)
.Tap(u => LogUserAccess(u))
.Tap(u => SendNotification(u));
// Ensure (Validation)
var result = Result<string>.Ok(email)
.Ensure(e => IsValidEmail(e), "Invalid email format")
.EnsureAsync(async e => !await EmailExistsAsync(e), "Email already registered");
Async Operations
// All methods have async variants
var result = await Result<int>.Ok(id)
.BindAsync(async i => await GetUserAsync(i))
.MapAsync(async user => await ToDtoAsync(user))
.TapAsync(async dto => await LogAccessAsync(dto))
.EnsureAsync(async dto => await ValidateDtoAsync(dto), "Invalid DTO");
๐ LINQ Integration
Functional Query Comprehensions
// LINQ-like syntax for Result operations
var result = from user in GetUser(id)
from validation in ValidateUser(user)
from saved in SaveUser(validation)
from notification in SendNotification(saved)
select saved;
// Complex queries
var results = from id in userIds
from user in GetUserAsync(id)
from updated in UpdateUserAsync(user)
select updated;
// Equivalent to method chaining
var result = GetUser(id)
.Bind(ValidateUser)
.Bind(SaveUser)
.Bind(SendNotification);
๐ฏ Advanced Patterns
Maybe<T> - Null-Safe Optionals
// Instead of null references
Maybe<User> user = GetUserFromCache(id);
var email = user
.Select(u => u.Email)
.Filter(email => email.Contains("@"))
.ValueOrDefault("no-reply@example.com");
// Safe operations
var result = user
.Map(u => u.Name)
.Bind(name => ValidateName(name))
.ToResult(() => new UserNotFoundError(id));
OneOf - Discriminated Unions
// Internal OneOf implementation
OneOf<ValidationError, User> result = ValidateAndCreateUser(request);
return result.Match(
case1: error => BadRequest(error),
case2: user => Ok(user)
);
// Three-type OneOf
OneOf<ValidationError, NotFoundError, User> GetUser(int id) { /* logic */ }
// Conversion to Result
var result = oneOf.ToResult(); // Convert OneOf to Result
Validation Rules Framework
// Built-in validation
var validator = Validator.Create<User>()
.Rule(u => u.Email, email => email.Contains("@"))
.Rule(u => u.Name, name => !string.IsNullOrWhiteSpace(name))
.Rule(u => u.Age, age => age >= 18, "Must be 18 or older");
var result = validator.Validate(user);
๐ง CRTP Pattern & Method Chaining
Curiously Recurring Template Pattern
// Fluent method chaining with CRTP
var result = Result<User>.Ok(user)
.Ensure(ValidateEmail)
.Map(ToDto)
.Tap(SendWelcomeEmail)
.Bind(SaveToDatabase)
.WithSuccess("User created successfully")
.WithTag("UserId", user.Id);
๐ Advanced Extensions
Functional Composition
// Function composition
var createUser = Compose(
ValidateRequest,
MapToUser,
SaveUser,
SendNotification
);
// Higher-order functions
var results = users
.Where(u => u.IsActive)
.Select(u => ProcessUser(u))
.Sequence(); // Turns IEnumerable<Result<T>> into Result<IEnumerable<T>>
// Traverse operations
var results = userIds
.Traverse(id => GetUserAsync(id)); // Async version of Sequence
๐ ASP.NET Integration
๐ ResultToIResult Extensions
Complete HTTP Method Support
// GET requests
return GetUser(id).ToIResult(); // 200 OK or 404/400
// POST requests
return CreateUser(request).ToPostResult(); // 201 Created or 400
// PUT requests
return UpdateUser(id, request).ToPutResult(); // 200 OK or 404
// DELETE requests
return DeleteUser(id).ToDeleteResult(); // 204 No Content or 404
// PATCH requests
return PatchUser(id, request).ToPatchResult(); // 200 OK or 404
๐ง Smart HTTP Mapping
Intelligent Status Code Detection
- "not found" โ 404 Not Found
- "validation" โ 400 Bad Request
- "unauthorized" โ 401 Unauthorized
- "forbidden" โ 403 Forbidden
- "conflict" โ 409 Conflict
- Default โ 500 Internal Server Error
๐ Problem Details Integration
RFC 7807 Compliance
[MapToProblemDetails(StatusCode = 404, Title = "User Not Found")]
public class UserNotFoundError : Error
{
public int UserId { get; }
public UserNotFoundError(int userId) : base($"User {userId} not found")
{
UserId = userId;
this.WithTag("UserId", userId);
}
}
// Automatically generates:
{
"type": "https://httpstatuses.com/404",
"title": "User Not Found",
"status": 404,
"userId": 123
}
๐ง Advanced Patterns
Take your functional programming skills to the next level with these powerful patterns:
๐ฒ Maybe<T> - Safe Null Handling
Eliminate null reference exceptions permanently:
// โ Traditional null checking
string email = user?.Email?.ToLower();
if (string.IsNullOrEmpty(email))
{
email = "no-reply@example.com";
}
// โ
Maybe<T> functional approach
Maybe<User> maybeUser = GetUserFromCache(id);
string email = maybeUser
.Select(u => u.Email)
.Filter(e => !string.IsNullOrWhiteSpace(e))
.Map(e => e.ToLower())
.ValueOrDefault("no-reply@example.com");
// Chaining operations safely
var result = maybeUser
.Filter(u => u.IsActive)
.Select(u => u.Profile)
.Select(p => p.Settings)
.Select(s => s.Theme)
.ValueOrDefault("default-theme");
๐ OneOf - Discriminated Unions
Express multiple possible outcomes with type safety:
// Internal OneOf implementation
OneOf<ValidationError, NotFoundError, User> result = ValidateAndCreateUser(request);
// Pattern matching with exhaustive checking
return result.Match(
case1: validationError => BadRequest(new { errors = validationError.Errors }),
case2: notFoundError => NotFound(new { message = notFoundError.Message }),
case3: user => CreatedAtAction(nameof(GetUser), new { id = user.Id }, user)
);
// ๐ v1.12.0: OneOf4 for complex scenarios
OneOf<ValidationError, NotFoundError, ConflictError, User> complexResult =
ValidateCreateUserWithConflictCheck(request);
return complexResult.Match(
case1: validationError => BadRequest(new { errors = validationError.Errors }),
case2: notFoundError => NotFound(new { message = notFoundError.Message }),
case3: conflictError => Conflict(new { error = conflictError.Message }),
case4: user => CreatedAtAction(nameof(GetUser), new { id = user.Id }, user)
);
// Conversion to Result for chaining
var userResult = result.ToResult(); // Convert OneOf to Result
// REslava.Result internal OneOf support (v1.12.0)
using REslava.Result.AdvancedPatterns.OneOf;
OneOf<ValidationError, User> internalResult = ValidateUser(request);
return internalResult.ToIResult(); // Auto-converts to HTTP response!
โ Validation Framework
Declarative validation with rich error context:
// Built-in validation rules
var validator = Validator.Create<User>()
.Rule(u => u.Email, email => email.Contains("@"), "Invalid email format")
.Rule(u => u.Name, name => !string.IsNullOrWhiteSpace(name), "Name is required")
.Rule(u => u.Age, age => age >= 18, "Must be 18 or older")
.Rule(u => u.Email, async email => !await EmailExistsAsync(email), "Email already exists");
// Execute validation
var validationResult = await validator.ValidateAsync(user);
// Chain with Result operations
var result = validationResult
.Bind(validUser => CreateUserAsync(validUser))
.WithSuccess("User created successfully");
// Custom validation rules
public class UniqueEmailRule : IValidationRule<User>
{
public ValidationResult Validate(User user)
{
return EmailExistsAsync(user.Email).GetAwaiter().GetResult()
? ValidationResult.Fail("Email already exists")
: ValidationResult.Success();
}
}
๐ Functional Composition
Build complex operations from simple functions:
// Function composition
Func<CreateUserRequest, Result<User>> createUserPipeline = Compose(
ValidateRequest,
MapToUser,
ValidateUser,
SaveUser,
SendWelcomeEmail
);
// Use the composed function
var result = createUserPipeline(request);
// Higher-order functions with Result
var results = users
.Where(u => u.IsActive)
.Select(u => ProcessUser(u))
.Sequence(); // Turns IEnumerable<Result<T>> into Result<IEnumerable<T>>
// Async traverse operations
var results = await userIds
.Traverse(id => GetUserAsync(id)); // Async version of Sequence
// Error aggregation
var aggregatedResult = results
.Map(users => users.ToList())
.Tap(users => LogInfo($"Processed {users.Count} users"));
๐ท๏ธ Rich Error Context
Add structured metadata for debugging and monitoring:
// Error with tags and metadata
var error = new UserNotFoundError(userId)
.WithTag("UserId", userId)
.WithTag("RequestId", requestId)
.WithTag("Timestamp", DateTime.UtcNow)
.WithMetadata("Endpoint", "/api/users/{id}")
.WithMetadata("HttpMethod", "GET");
// Result with rich context
var result = Result<User>.Fail(error);
// Extract context for logging
if (result.IsFailed)
{
var error = result.Errors.First();
var userId = error.GetTag<string>("UserId");
var requestId = error.GetTag<string>("RequestId");
logger.LogWarning("User {UserId} not found for request {RequestId}", userId, requestId);
}
๐ Performance Patterns
Optimize for high-performance scenarios:
// Value objects for reduced allocations
public readonly record struct UserEmail(string Value)
{
public static Result<UserEmail> Create(string email) =>
string.IsNullOrWhiteSpace(email)
? Result<UserEmail>.Fail("Email required")
: email.Contains("@")
? Result<UserEmail>.Ok(new UserEmail(email))
: Result<UserEmail>.Fail("Invalid email format");
}
// Array pooling for high-throughput scenarios
using System.Buffers;
var result = Result<string[]>.Ok(ArrayPool<string>.Shared.Rent(1000))
.Ensure(arr => arr.Length >= 1000, "Array too small")
.Tap(arr => ArrayPool<string>.Shared.Return(arr));
// Memory-efficient validation
public ref struct ValidationSpan(ReadOnlySpan<char> input)
{
public bool IsValid => !input.IsEmpty && input.Contains('@');
public Result<ReadOnlySpan<char>> AsResult() =>
IsValid ? Result<ReadOnlySpan<char>>.Ok(input)
: Result<ReadOnlySpan<char>>.Fail("Invalid email");
}
๐ Complete Architecture
REslava.Result is a comprehensive ecosystem with two main components that work together seamlessly:
๐ฆ Base Library: REslava.Result
Core Functional Programming Foundation
src/
โโโ Result.cs # ๐ฏ Core Result<T> implementation
โโโ Result.NonGeneric.cs # ๐ Non-generic Result for void operations
โโโ AdvancedPatterns/
โ โโโ Maybe.cs # ๐ฒ Safe null handling
โ โโโ OneOf.cs # ๐ Discriminated unions (2, 3, 4+ types)
โ โโโ OneOfResultExtensions.cs # ๏ฟฝ OneOf โ Result conversions
โ โโโ Validation/
โ โโโ Validator.cs # โ
Validation framework
โ โโโ IValidationRule.cs # ๐ Validation rule interface
โ โโโ ValidationResult.cs # ๐ Validation results
โโโ Extensions/
โ โโโ ResultExtensions.cs # ๐ LINQ and async extensions
โ โโโ ResultMapExtensions.cs # ๐บ๏ธ Mapping and transformation
โ โโโ ResultFunctionalExtensions.cs # ๐ง Functional composition
โโโ Utilities/
โโโ Compose.cs # ๐ Function composition utilities
โโโ Error.cs # โ Error base classes
๐ Source Generators: REslava.Result.SourceGenerators
Zero-Boilerplate Code Generation
SourceGenerator/
โโโ Core/ # ๐ Generator Infrastructure
โ โโโ CodeGeneration/ # ๐ CodeBuilder utilities
โ โโโ Utilities/ # ๐ HttpStatusCodeMapper, AttributeParser
โ โโโ Configuration/ # โ๏ธ Configuration base classes
โ โโโ Interfaces/ # ๏ฟฝ SOLID interfaces
โโโ Generators/ # ๐ฆ Individual Generators
โ โโโ ResultToIResult/ # ๐ฏ Result โ HTTP response conversion
โ โ โโโ Attributes/ # ๐ท๏ธ Auto-generated attributes
โ โ โโโ CodeGeneration/ # ๐ป Extension method generation
โ โ โโโ Orchestration/ # ๐ผ Pipeline coordination
โ โโโ OneOfToIResult/ # ๐ OneOf<T1,...,TN> โ HTTP (consolidated v1.14.1)
โ โ โโโ OneOf2ToIResultGenerator.cs # ๐ฏ Thin wrapper (arity=2)
โ โ โโโ OneOf3ToIResultGenerator.cs # ๐ฏ Thin wrapper (arity=3)
โ โ โโโ OneOf4ToIResultGenerator.cs # ๐ฏ Thin wrapper (arity=4)
โ โ โโโ Attributes/ # ๐ท๏ธ Shared attribute generators
โ โ โโโ CodeGeneration/ # ๐ป Arity-parameterized extensions
โ โ โโโ Orchestration/ # ๐ผ Single shared orchestrator
โ โโโ SmartEndpoints/ # โก Auto-generate Minimal APIs (v1.11.0+)
โ โโโ Attributes/ # ๐ท๏ธ AutoGenerateEndpoints attribute
โ โโโ CodeGeneration/ # ๐ป SmartEndpointExtensionGenerator
โ โโโ Models/ # ๐ EndpointMetadata
โ โโโ Orchestration/ # ๐ผ SmartEndpointsOrchestrator
โโโ Tests/ # ๐งช Comprehensive Test Suite (1,976+ tests)
โโโ OneOfToIResult/ # โ
12/12 tests (unified, covers arity 2/3/4)
โโโ SmartEndpoints/ # โ
4/4 tests passing
โโโ ResultToIResult/ # โ
6/6 tests passing
โโโ CoreLibrary/ # ๐ Base library tests
โโโ GeneratorTest/ # ๏ฟฝ Integration tests
๐ Visual Architecture: See Core Type Hierarchy and Source Generator Pipeline for detailed Mermaid diagrams.
๐ฏ SOLID Principles in Action
| Principle | Implementation | Benefit |
|---|---|---|
| Single Responsibility | Separate classes for attributes, code generation, orchestration | Zero duplicate generation, clear concerns |
| Open/Closed | Interface-based design (IAttributeGenerator, ICodeGenerator, IOrchestrator) | Easy to add new generators without modifying existing code |
| Liskov Substitution | All generators implement common interfaces | Interchangeable components, consistent behavior |
| Interface Segregation | Focused interfaces for specific responsibilities | Minimal contracts, easier testing |
| Dependency Inversion | Constructor injection with abstractions | Testable, maintainable, loosely coupled |
๐ How Components Work Together
graph TB
A[Your Code] --> B[REslava.Result Base Library]
B --> C[Result T / Maybe T / OneOf T]
C --> D[Source Generators]
D --> E[Generated Extensions]
E --> F[ASP.NET Core IResult]
G[REslava.Result OneOf] --> H[OneOf2ToIResult Generator]
G --> I[OneOf3ToIResult Generator]
G --> J[OneOf4ToIResult Generator]
H --> F
I --> F
J --> F
K[SmartEndpoints Generator] --> L[MapSmartEndpoints]
L --> F
๐ Smart Auto-Detection (v1.10.0)
Zero Configuration Required
- Setup Detection: Automatically detects your REslava.Result OneOf setup
- Conflict Prevention: Generators only run when appropriate types are found
- Perfect Coexistence: OneOf generators work seamlessly together
- Zero Compilation Errors: Clean developer experience guaranteed
๐ฆ Package Structure
Three NuGet packages for a complete development experience:
| Package | Purpose |
|---|---|
REslava.Result |
Core library โ Result<T>, Maybe<T>, OneOf, LINQ, validation |
REslava.Result.SourceGenerators |
ASP.NET source generators โ SmartEndpoints, ToIResult, OneOf extensions |
REslava.Result.Analyzers |
Roslyn safety analyzers โ RESL1001, RESL1002, RESL1003, RESL2001 diagnostics + code fixes |
๐ NuGet Package Contents
REslava.Result.SourceGenerators.1.10.0.nupkg/
โโโ analyzers/dotnet/cs/
โ โโโ REslava.Result.SourceGenerators.dll # Main source generators
โ โโโ REslava.Result.SourceGenerators.Core.dll # Generator infrastructure
โโโ content/
โ โโโ MapToProblemDetailsAttribute.cs # Runtime attribute
โโโ build/
โ โโโ REslava.Result.SourceGenerators.props # MSBuild integration
โโโ lib/
โ โโโ netstandard2.0/
โ โโโ REslava.Result.SourceGenerators.dll # Reference assembly
โโโ README.md # Package documentation
๐ฏ Generated Output Structure
When your project builds:
YourProject/
โโโ obj/
โ โโโ GeneratedFiles/
โ โโโ net10.0/
โ โโโ REslava.Result.SourceGenerators/
โ โโโ REslava.Result.SourceGenerators.Generators.ResultToIResult.ResultToIResultRefactoredGenerator/
โ โ โโโ GenerateResultExtensionsAttribute.g.cs # Auto-generated attribute
โ โ โโโ MapToProblemDetailsAttribute.g.cs # Auto-generated attribute
โ โ โโโ ResultToIResultExtensions.g.cs # HTTP extension methods
โ โโโ REslava.Result.SourceGenerators.Generators.OneOf2ToIResult.OneOf2ToIResultGenerator/
โ โ โโโ GenerateOneOf2ExtensionsAttribute.g.cs # OneOf2 attribute
โ โ โโโ MapToProblemDetailsAttribute.g.cs # OneOf2 mapping attribute
โ โ โโโ OneOf2ToIResultExtensions.g.cs # OneOf2 HTTP extensions
โ โโโ REslava.Result.SourceGenerators.Generators.OneOf3ToIResult.OneOf3ToIResultGenerator/
โ โโโ GenerateOneOf3ExtensionsAttribute.g.cs # OneOf3 attribute
โ โโโ MapToProblemDetailsAttribute.g.cs # OneOf3 mapping attribute
โ โโโ OneOf3ToIResultExtensions.g.cs # OneOf3 HTTP extensions
โโโ bin/
โโโ Your compiled application with auto-generated extensions
๐ Build Integration
Automatic MSBuild Integration:
<Import Project="..\packages\REslava.Result.SourceGenerators.1.10.0\build\REslava.Result.SourceGenerators.props" />
What happens during build:
- Analysis Phase: Generators scan your code for Result<T>, OneOf<T1,T2>, OneOf<T1,T2,T3> usage
- Generation Phase: Creates appropriate extension methods and attributes
- Compilation Phase: Generated code is compiled into your assembly
- Runtime Phase: Extensions available for automatic HTTP conversion
๐ฏ Quick Examples
๐ฆ Core Library - Type-Safe Error Handling
// Fluent, chainable operations
var result = await Result<string>.Ok(email)
.Ensure(e => IsValidEmail(e), "Invalid email format")
.EnsureAsync(async e => !await EmailExistsAsync(e), "Email already registered")
.BindAsync(async e => await CreateUserAsync(e))
.WithSuccess("User created successfully");
// Pattern matching
return result.Match(
onSuccess: user => CreatedAtAction(nameof(GetUser), new { id = user.Id }, user),
onFailure: errors => BadRequest(new { errors })
);
๐ Source Generator - Zero Boilerplate
// Your service returns Result<T>
public async Task<Result<User>> GetUserAsync(int id)
{
return await Result<int>.Ok(id)
.Ensure(i => i > 0, "Invalid user ID")
.BindAsync(async i => await _repository.FindAsync(i))
.Ensure(u => u != null, new NotFoundError("User", id));
}
// Your controller just returns the Result - auto-converted!
app.MapGet("/users/{id}", async (int id) =>
await _userService.GetUserAsync(id));
// ๐ v1.10.0: OneOf extensions also work!
public OneOf<ValidationError, NotFoundError, User> GetOneOfUser(int id) { /* logic */ }
app.MapGet("/users/oneof/{id}", async (int id) =>
GetOneOfUser(id)); // Auto-converts OneOf too!
// HTTP responses are automatically generated:
// 200 OK with User data
// 404 Not Found with ProblemDetails
// 400 Bad Request with validation errors
๐ง Advanced Patterns - Functional Programming
// Maybe<T> for safe null handling
Maybe<User> user = GetUserFromCache(id);
var email = user
.Select(u => u.Email)
.Filter(email => email.Contains("@"))
.ValueOrDefault("no-reply@example.com");
// ๐ v1.10.0: Enhanced OneOf support
OneOf<ValidationError, NotFoundError, User> result = ValidateAndCreateUser(request);
return result.Match(
case1: error => BadRequest(error),
case2: user => Ok(user)
);
// ๐ v1.10.0: OneOf with auto-detection
public OneOf<ValidationError, NotFoundError, User> GetUser(int id) { /* logic */ }
return GetUser(id).ToIResult(); // ๐ Automatic HTTP mapping!
๐ Production Benefits
| ๐ฏ Challenge | ๐ REslava.Result Solution |
|---|---|
| Hidden exceptions | Explicit error contracts in method signatures |
| Complex error handling | Fluent, chainable operations |
| Hard to debug failures | Rich error context with tags |
| Inconsistent error responses | Automatic RFC 7807 compliance |
| Slow development | 70-90% less boilerplate code |
| ๐ OneOf integration pain | Smart auto-detection, zero configuration |
| ๐ Multiple library conflicts | Perfect coexistence, no compilation errors |
๐งช Testing & Quality Assurance
๐ Comprehensive Test Suite
1,928+ Tests Passing ๐
- Source Generator Tests: 17 tests for all generators
- Core Library Tests: 1,902 tests for REslava.Result functionality (1,902 core + 26 generator = 1,928 total)
- Integration Tests: 9 endpoint tests for complete ASP.NET integration
- Performance Tests: Memory and speed benchmarks
๐ Source Generator Test Architecture
Complete Test Coverage for v1.12.0
tests/REslava.Result.SourceGenerators.Tests/
โโโ OneOf2ToIResult/ # โ
5/5 tests passing
โโโ OneOf3ToIResult/ # โ
4/4 tests passing
โโโ OneOf4ToIResult/ # โ
5/5 tests passing (NEW!)
โโโ ResultToIResult/ # โ
6/6 tests passing
โโโ SmartEndpoints/ # โ
4/4 tests passing
โโโ CoreLibrary/ # Core utilities tests
โโโ GeneratorTest/ # Console validation tests
โโโ Legacy/ # Historical tests (disabled)
๐ฏ Generator Test Coverage
OneOf4ToIResult Generator (NEW v1.12.0)
- โ Extension method generation for OneOf<T1,T2,T3,T4>
- โ Intelligent HTTP status mapping
- โ Error type detection and handling
- โ Attribute generation
- โ Type combinations (ValidationError, NotFoundError, ConflictError, ServerError)
- โ Conditional generation (no false positives)
- โ HTTP mapping validation (T1โ400, T2โ200)
OneOf3ToIResult Generator
- โ
Extension method generation (
OneOf3Extensions) - โ Attribute generation
- โ Type combinations (3-way scenarios)
- โ Conditional generation
- โ HTTP mapping validation (T1โ400, T2โ400, T3โ200)
ResultToIResult Generator
- โ Extension method generation
- โ Attribute generation
- โ Syntax tree detection
- โ Conditional generation (zero false positives)
๐ CI/CD Pipeline
Automated Testing
# .github/workflows/ci.yml
- Build Solution: dotnet build --configuration Release
- Run Tests: dotnet test --configuration Release --no-build
- Total Tests: 1,928+ passing
- Coverage: 95%+ code coverage
๐งช Test Categories
Source Generator Tests
- Unit Tests: Individual generator behavior
- Integration Tests: Generator compilation scenarios
- Regression Tests: Prevent breaking changes
- Performance Tests: Generation speed and memory
Core Library Tests
- Functional Tests: Result pattern operations
- Async Tests: Task-based operations
- Validation Tests: Error handling scenarios
- Extension Tests: Method chaining and composition
๐ Sample Projects & Integration Tests
Real-World Validation
- OneOfTest.Api: Live API testing with OneOf2ToIResult & OneOf3ToIResult
- Integration Tests: End-to-end HTTP mapping validation
- Performance Benchmarks: Memory allocation and speed tests
- Production Samples: Enterprise-grade implementations
๐ Test Quality Metrics
High Standards
- โ 1,928/1,928 tests passing (100% success rate)
- โ 95%+ code coverage (comprehensive coverage)
- โ Zero flaky tests (reliable CI/CD)
- โ Fast execution (complete suite < 10 seconds)
- โ Clean architecture (SOLID test organization)
๐โโ๏ธ Running Tests Locally
Quick Test Commands
# Run all tests (2,004+ tests)
dotnet test --configuration Release
# Run only Source Generator tests (16 tests)
dotnet test tests/REslava.Result.SourceGenerators.Tests/
# Run specific generator tests
dotnet test --filter "OneOf2ToIResult" # 5 tests
dotnet test --filter "OneOf3ToIResult" # 4 tests
dotnet test --filter "ResultToIResult" # 6 tests
# Clean environment before testing
./scripts/clean-before-test.ps1
Test Output Example
Test summary: total: 1928, failed: 0, succeeded: 1928, skipped: 0, duration: 7.8s
Build succeeded in 8.3s
๏ฟฝ Real-World Impact
๐ข For Enterprise Teams
Explicit failure tracking replaces hidden exception flows
- Rich error context with tags for debugging and monitoring
- Better observability with structured error information
- Consistent error handling across all services and APIs
- Audit trails with detailed error metadata for compliance
๐งช For Test-Driven Development
Predictable patterns make unit tests simple and reliable
- No complex exception setups - just assert on Result values
- Faster test writing with deterministic results
- Clear test scenarios - success, failure, and edge cases are explicit
- Better test coverage - error paths are first-class citizens
๐ฅ For Team Collaboration
Clear contracts between services and components
- Consistent patterns across the entire codebase
- Improved onboarding for new team members
- Self-documenting code with explicit error types
- Reduced cognitive load - one way to handle errors everywhere
๐ For Performance & Scalability
Optimized for modern applications
- Zero allocation failures - immutable design prevents memory leaks
- Compile-time guarantees - no runtime reflection or magic
- AOT & NativeAOT compatible - works with trimming and native compilation
- Minimal overhead - lightweight Result objects with smart optimizations
๏ฟฝ๐ Why Choose REslava.Result?
โ Zero Dependencies
- No external packages - Reduces security vulnerabilities
- Small footprint - Only ~50KB compiled
- Fast compilation - No complex dependency chains
โ Production-Ready
- 95%+ code coverage - Reliable in production
- Comprehensive testing - Unit, integration, and performance tests
- Memory efficient - Immutable design, predictable allocations
โ Developer Experience
- Rich IntelliSense - Extensive XML documentation
- Modern C# - Supports .NET 8, 9, and 10
- AOT compatible - Works with NativeAOT and trimming
- ๐ Smart Auto-Detection - Zero configuration for v1.10.0
๐ Deep Dive Documentation
๐ฏ Navigate by Goal
| I'm building a... | ๐ Start Here | ๐ฏ What You'll Learn |
|---|---|---|
| Web API | ๐ ASP.NET Integration | Auto-conversion, OneOf extensions, error mapping |
| Library/Service | ๐ Core Library | Result pattern, validation, error handling |
| Custom Generator | ๐ Custom Generator Guide | Build your own source generators |
| Advanced App | ๐ง Advanced Patterns | Maybe, OneOf, validation rules |
| Testing | ๐งช Testing & Quality | 2,004+ tests, CI/CD, test strategies |
| Curious About Magic | ๐ Complete Architecture | How generators work, SOLID design |
๐ Complete Reference
- ๐ Getting Started Guide - Learn the basics
- ๐ ASP.NET Integration - HTTP mapping details
- ๐ OneOf Extensions - ๐ External library support
- โก Source Generator - Smart auto-detection magic
- ๐ง Functional Programming - Complete ROP methodology
- ๐ Custom Generator Guide - ๐ Build your own generators
- ๐ API Reference - Complete technical documentation
๐ฏ Hands-On Samples
๐ FastMinimalAPI Demo - Production-ready .NET 10 Minimal API showcase
- SmartEndpoints vs Manual - Side-by-side comparison (~85% less code)
- OpenAPI 3.0 + Scalar UI - Modern API documentation
- REslava.Result patterns - Result<T> and OneOf<T1,T2,T3,T4> discriminated unions
- Real-world scenarios - Users, Products, Orders with full CRUD operations
- Zero exception-based control flow - Type-safe error handling
๐ Console Samples - 13 progressive examples from basic to advanced
- Level 1: Core Result<T> patterns, validation pipelines, error handling
- Level 2: Async operations, LINQ syntax, custom errors
- Level 3: Maybe<T>, OneOf patterns, ResultโOneOf conversions
๐ ASP.NET Integration Samples - Compare pure .NET 10 vs REslava.Result with source generators
- MinimalApi.Net10.Reference - Pure .NET 10 implementation (baseline)
- MinimalApi.Net10.REslava.Result.v1.7.3 - REslava.Result + source generators (70-90% less code)
๐งช Quick Start Scenarios
Installation
# Core functional programming library
dotnet add package REslava.Result
# ASP.NET integration + OneOf extensions
dotnet add package REslava.Result.SourceGenerators
# Roslyn safety analyzers (compile-time diagnostics)
dotnet add package REslava.Result.Analyzers
Scenario 1: Functional Programming Foundation
using REslava.Result;
using static REslava.Result.Functions;
// Core Result pattern usage
public Result<User> GetUser(int id)
{
if (id <= 0)
return Result<User>.Fail("Invalid user ID");
var user = FindUser(id);
return user ?? Result<User>.Fail($"User {id} not found");
}
// Functional composition
public Result<UserDto> GetUserDto(int id) =>
GetUser(id)
.Map(ToDto)
.Tap(LogAccess)
.Ensure(dto => dto.IsActive, "User is inactive");
// LINQ integration
public Result<UserDto> GetUserDtoLinq(int id) =>
from user in GetUser(id)
from validation in ValidateUser(user)
from dto in ToDto(user)
select dto;
Scenario 2: ASP.NET Integration
[ApiController]
public class UsersController : ControllerBase
{
// Automatic HTTP mapping
[HttpGet("{id}")]
public IResult GetUser(int id) =>
GetUser(id).ToIResult(); // 200 OK or 404/400
// POST with created response
[HttpPost]
public IResult CreateUser([FromBody] CreateUserRequest request) =>
CreateUser(request).ToPostResult(); // 201 Created or 400
}
Scenario 3: OneOf Extensions (NEW!)
using REslava.Result.AdvancedPatterns.OneOf;
using Generated.OneOfExtensions;
// REslava.Result internal OneOf with automatic mapping
public OneOf<ValidationError, NotFoundError, User> GetUser(int id)
{
if (id <= 0)
return new ValidationError("Invalid ID");
var user = FindUser(id);
return user ?? new NotFoundError($"User {id} not found");
}
[HttpGet("{id}")]
public IResult GetUser(int id) =>
GetUser(id).ToIResult(); // 400, 404, or 200
๐ฏ Roadmap
v1.15.0 (Current) โ
- Repository cleanup: removed unused Node.js toolchain, stale samples, incomplete templates
- Emoji standardization:
๐for all architecture/design references across documentation - Documentation refresh and consolidated release notes
v1.14.x โ
- REslava.Result.Analyzers โ 4 diagnostics + 2 code fixes
- RESL1001: Warns on unsafe
.Valueaccess + 2 code fixes (if-guard, Match) - RESL1002: Warns when
Result<T>return value is discarded - RESL1003: Suggests
Match()over if-check with.Value/.Errors - RESL2001: Warns on unsafe
OneOf.AsT*access + code fix (Match)
- RESL1001: Warns on unsafe
- OneOf generator consolidation (15 files โ 7)
- Shared
GuardDetectionHelperfor reusable guard-detection - 46 analyzer tests, 2,004+ total tests
v1.13.0 โ
- SmartEndpoints: Authorization & Policy Support โ
RequiresAuth,Roles,Policies,[SmartAllowAnonymous] - LINQ query comprehension syntax for Result<T> โ
Select,SelectMany,Where+ async variants - SmartEndpoints: OpenAPI Metadata Auto-Generation
๐ค Contributing
We welcome contributions! Please see our Contributing Guide for details.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Functional Programming Community - For the ROP methodology and patterns
- OneOf library - Excellent discriminated union implementation
- Roslyn team - Powerful source generator framework
- .NET community - Valuable feedback and contributions
๐ Ready to Transform Your Error Handling?
๐ Start with Getting Started Guide
<div align="center">
โญ Star this REslava.Result repository if you find it useful!
Made with โค๏ธ by Rafa Eslava for developers community
Report Bug โข Request Feature โข Discussions </div>
Contributors
See the full list of contributors in CONTRIBUTORS.md.
๐ Version History
- v1.15.0 - Repository cleanup: removed Node.js toolchain, stale samples, templates; emoji standardization (๐ for architecture)
- v1.14.2 - Analyzers Phase 2+3: RESL1003 (prefer Match), RESL2001 (unsafe OneOf.AsT*), code fixes for RESL1001 & RESL2001, shared GuardDetectionHelper
- v1.14.1 - Internal refactor: consolidated OneOf2/3/4ToIResult generators into single arity-parameterized OneOfToIResult (15 files โ 7)
- v1.14.0 - NEW: REslava.Result.Analyzers package (RESL1001 unsafe .Value access, RESL1002 discarded Result), package icons for all NuGet packages
- v1.13.0 - SmartEndpoints Authorization & Policy Support (RequireAuthorization, AllowAnonymous, Roles, Policies, Produces(401))
- v1.12.2 - SmartEndpoints OpenAPI metadata auto-generation (Produces, WithSummary, WithTags, MapGroup)
- v1.12.1 - SmartEndpoints DI + async support, FastMinimalAPI demo, Console samples
- v1.12.0 - OneOf4ToIResult generator, enhanced SmartEndpoints, 1,928 tests passing
- v1.11.0 - SmartEndpoints generator for zero-boilerplate API generation
- v1.10.3 - OneOf2ToIResult & OneOf3ToIResult generators
- v1.10.2 - Initial ResultToIResult generator
- v1.10.1 - Core Result types and error handling
- v1.10.0 - Framework foundation with ROP patterns
| 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 was computed. 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 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. |
This package has 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.32.0 | 161 | 2/28/2026 | |
| 1.31.0 | 120 | 2/27/2026 | |
| 1.30.0 | 125 | 2/27/2026 | |
| 1.29.0 | 120 | 2/25/2026 | |
| 1.28.0 | 118 | 2/25/2026 | |
| 1.27.0 | 113 | 2/25/2026 | |
| 1.26.0 | 136 | 2/24/2026 | |
| 1.25.0 | 130 | 2/23/2026 | |
| 1.24.0 | 129 | 2/23/2026 | |
| 1.23.0 | 126 | 2/23/2026 | |
| 1.22.0 | 136 | 2/18/2026 | |
| 1.21.0 | 126 | 2/17/2026 | |
| 1.20.0 | 128 | 2/17/2026 | |
| 1.19.0 | 124 | 2/16/2026 | |
| 1.18.0 | 124 | 2/16/2026 | |
| 1.17.0 | 131 | 2/16/2026 | |
| 1.16.0 | 124 | 2/16/2026 | |
| 1.15.0 | 130 | 2/16/2026 |