Routya.ResultKit
2.1.0
dotnet add package Routya.ResultKit --version 2.1.0
NuGet\Install-Package Routya.ResultKit -Version 2.1.0
<PackageReference Include="Routya.ResultKit" Version="2.1.0" />
<PackageVersion Include="Routya.ResultKit" Version="2.1.0" />
<PackageReference Include="Routya.ResultKit" />
paket add Routya.ResultKit --version 2.1.0
#r "nuget: Routya.ResultKit, 2.1.0"
#:package Routya.ResultKit@2.1.0
#addin nuget:?package=Routya.ResultKit&version=2.1.0
#tool nuget:?package=Routya.ResultKit&version=2.1.0
ðĶ Routya.ResultKit
**Lightweight result wrapper, validation and transformation toolkit for C# **
Brings clean Result<T> handling and extensible validation with custom attributes.
âĻ Features
- â
Consistent
Result<T>response pattern - â
One-line
.Validate()extension for request models - â
.Transform()extension for clean and safe object/result projection - â Rich built-in and custom validation attributes
- â Works great with System.ComponentModel.Annotations
- â Validation for nested objects
ðĨ Installation
dotnet add package Routya.ResultKit --version 2.1.0
Upgrading from v1.x? See the Migration Guide below.
ð Quick Start
1. Define Your Request Model (with Custom Validation)
using Routya.ResultKit.Attributes;
using System.ComponentModel.DataAnnotations;
private enum UserRole { Admin, User, Guest }
private class TestModel
{
[Required]
public string Name { get; set; }
[EmailAddress]
public string Email { get; set; }
[Range(18, 120)]
public int Age { get; set; }
[StringEnum(typeof(UserRole))]
public string Role { get; set; }
[Required]
public string Password { get; set; }
[Compare("Password")]
public string ConfirmPassword { get; set; }
public decimal MinPurchase { get; set; }
[GreaterThan("MinPurchase")]
public decimal MaxPurchase { get; set; }
}
2. Validate and Return
using Routya.ResultKit;
using Routya.ResultKit.Validation;
app.MapPost("/users", (CreateUserRequest request) =>
{
var validationResult = request.Validate();
if (!validationResult.Success)
return Results.BadRequest(validationResult.Error); // Returns ProblemDetails
var user = new User { Id = 1, Name = request.Name, Email = request.Email };
return Results.Ok(user);
});
â Successful Response Example (200 OK)
{
"id": 1,
"name": "Henry",
"email": "henry@example.com"
}
â Validation Error Response Example (422 Unprocessable Entity)
{
"type": "urn:problem-type:validation-error",
"title": "Validation Failed",
"status": 422,
"detail": "One or more validation errors occurred.",
"errors": {
"name": ["The Name field is required."],
"email": ["The Email field is not a valid e-mail address."],
"age": ["The field Age must be between 18 and 120."],
"role": ["Role must be one of: Admin, User, Guest"],
"confirmPassword": ["'ConfirmPassword' and 'Password' do not match."],
"maxPurchase": ["MaxPurchase must be greater than MinPurchase"]
}
}
Note: v2.0 uses RFC 7807 compliant ProblemDetails for all errors.
ð ïļ Built-in Validation Attributes
Routya.ResultKit includes powerful validation attributes ready to use:
| Attribute | Purpose |
|---|---|
[GreaterThan("OtherProp")] |
Ensure a property is greater than another |
[LessThan("OtherProp")] |
Ensure a property is less than another |
[RequiredIf("OtherProp", "Value")] |
Conditionally require a property |
[RequiredIfEmpty("OtherProp")] |
Require a property if another is empty |
[StringEnum(typeof(EnumType))] |
Ensure a string matches an Enum name |
[MatchRegex("pattern")] |
Validate a string against a regex |
[MinItems(count)] |
Validate minimum items in a collection |
[MaxItems(count)] |
Validate maximum items in a collection |
[ValidStartEndDateRange("Start", "End")] |
Validate that StartDate is before EndDate (This is a class level attribute) |
[ValidDateTimeOffsetRange("End")] |
Validate DateTimeOffset ranges |
[ValidDateTimeRange("End")] |
Validate DateTime ranges |
ð Transforming Models
Use .Transform(...) to reshape validated models or result data into domain entities or response objects â cleanly and safely.
â Example 1: Basic Object Transformation
var request = "Hello";
var greeting = request.Transform(str => new Greeting
{
Message = str,
Length = str.Length
});
public class Greeting
{
public string Message { get; set; }
public int Length { get; set; }
}
â Example 2: Full Validate â Transform â Result Flow
var result = request.Validate()
.Transform(req => new CreateUserCommand
{
Name = req.Name,
Email = req.Email,
Role = Enum.Parse<UserRole>(req.Role, ignoreCase: true)
});
â Example 3: Transforming Result<T> Output
var result = Result.Ok(user)
.Transform(u => new UserResponse
{
Id = u.Id,
Name = u.Name
});
ð§ Why Use Transform(...)?
| Benefit | Description |
|---|---|
| â Fluent | Clean chaining after .Validate() |
| â Safe | When using Result<T> it only transforms data if result is successful |
| â Expressive | Encourages intentional mapping logic |
| â Lightweight | Zero dependencies, pure functional mapping |
ð Bonus: Works with Both Objects and Result<T>
TOut Transform<TIn, TOut>(this TIn input, Func<TIn, TOut> selector)
Result<TOut> Transform<TIn, TOut>(this Result<TIn> result, Func<TIn, TOut> selector)
ð HTTP Status Code Support
Result<T> carries semantic HTTP intent with automatic status code handling:
// Success status codes
Result<User>.Ok(user); // 200 OK
Result<User>.Created(user); // 201 Created
Result<User>.Accepted(user); // 202 Accepted
Result<User>.NoContent(); // 204 No Content
// Redirect status codes
Result<string>.Redirect(location); // 302 Found (temporary)
Result<string>.RedirectPermanent(location); // 301 Moved Permanently
// Error status codes (automatic from factory methods)
Result<User>.NotFound("User not found"); // 404 Not Found
Result<User>.BadRequest("Invalid data"); // 400 Bad Request
Result<User>.Unauthorized("Not authenticated"); // 401 Unauthorized
NoContent Example - DELETE Operations
[HttpDelete("users/{id}")]
public IActionResult DeleteUser(int id)
{
var user = _repository.FindById(id);
if (user == null)
return Result<User>.NotFound($"User {id} not found").ToActionResult(HttpContext);
_repository.Delete(user);
return Result<User>.NoContent().ToActionResult(HttpContext); // Returns 204
}
Redirect Examples
// Temporary redirect (302) - for moved resources
[HttpGet("docs")]
public IActionResult RedirectToDocs()
{
return Result<string>.Redirect("https://routya.github.io/").ToActionResult(HttpContext);
}
// Permanent redirect (301) - for permanently moved endpoints
[HttpGet("old-users")]
public IActionResult OldEndpoint()
{
var newLocation = $"{Request.Scheme}://{Request.Host}/api/users";
return Result<string>.RedirectPermanent(newLocation).ToActionResult(HttpContext);
}
// HEAD request with NoContent
[HttpHead("users/check-email")]
public IActionResult CheckEmailExists([FromQuery] string email)
{
var exists = _repository.EmailExists(email);
return exists
? Result<User>.NoContent().ToActionResult(HttpContext)
: Result<User>.NotFound("Email not found").ToActionResult(HttpContext);
}
Note: When using the
Routya.ResultKit.AspNetCorepackage,ToActionResult()andToHttpResult()automatically use the appropriate status code from the Result. See ASP.NET Core Integration for details.
ð Migrating from v1.x to v2.0
v2.0 introduces RFC 7807 ProblemDetails and a cleaner API. Here's what changed:
Key Changes
ProblemDetails replaces old error format
// â v1.x - Simple error dictionary Result.Fail("Validation Failed", 400, errors) // â v2.0 - RFC 7807 ProblemDetails Result.Fail(ProblemDetailsBuilder.ValidationError("Validation Failed") .WithErrors(errors) .Build())Result factory methods renamed
// â v1.x Result.Success(data) Result.Failure("Error", 400) // â v2.0 Result.Ok(data) Result.Created(data) // New: Sets 201 status Result.Accepted(data) // New: Sets 202 status Result.NoContent() // New in v2.1: Sets 204 status Result.Redirect(location) // New in v2.1: Sets 302 status Result.RedirectPermanent(location) // New in v2.1: Sets 301 status Result.Fail(problemDetails)Validation returns ProblemDetails
// â v1.x var result = request.ValidateObject(); if (!result.Success) return result; // Returned Result<T> // â v2.0 var result = request.Validate(); if (!result.Success) return result.Error; // Returns ProblemDetailsASP.NET Core Integration (New Package)
dotnet add package Routya.ResultKit.AspNetCore// Automatic conversion to IResult/IActionResult return result.ToActionResult(HttpContext); // Automatic exception handling builder.Services.AddResultKitProblemDetails(); app.UseResultKitExceptionHandler();
Quick Migration Steps
- Update package:
dotnet add package Routya.ResultKit --version 2.1.0 - Replace
Result.SuccessâResult.Ok - Replace
Result.FailureâResult.Fail(use ProblemDetailsBuilder) - Replace
ValidateObject()âValidate() - For ASP.NET Core, add
Routya.ResultKit.AspNetCorepackage
ð Full Migration Guide - Complete migration documentation with examples
ð Documentation & Resources
- Official Website - Routya project homepage
- Migration Guide to v2.0 - Complete guide for upgrading from v1.x
- ASP.NET Core Integration - ProblemDetails, middleware, IResult/IActionResult extensions
- Demo API - Comprehensive examples of all features
| 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 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.ComponentModel.Annotations (>= 5.0.0)
- System.Text.Json (>= 8.0.5)
-
.NETStandard 2.1
- System.ComponentModel.Annotations (>= 5.0.0)
- System.Text.Json (>= 8.0.5)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Routya.ResultKit:
| Package | Downloads |
|---|---|
|
Routya.ResultKit.AspNetCore
ASP.NET Core integration for Routya.ResultKit with Microsoft ProblemDetails support, exception handling middleware, and IResult/IActionResult extensions. |
|
|
EffinitiveFramework.Core
Ultra-high-performance HTTP/1.1 and HTTP/2 web framework for .NET 8+. Built from scratch for maximum speed with zero-allocation routing, custom HTTP/2 implementation with HPACK compression, and sub-50Ξs response times. 6-10x faster than ASP.NET Core for API workloads. |
GitHub repositories
This package is not used by any popular GitHub repositories.
v2.1.0: Added NoContent() for 204 responses and Redirect()/RedirectPermanent() for 301/302 redirects. Includes automatic status code handling.