Routya.ResultKit 2.1.0

dotnet add package Routya.ResultKit --version 2.1.0
                    
NuGet\Install-Package Routya.ResultKit -Version 2.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Routya.ResultKit" Version="2.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Routya.ResultKit" Version="2.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Routya.ResultKit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Routya.ResultKit --version 2.1.0
                    
#r "nuget: Routya.ResultKit, 2.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Routya.ResultKit@2.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Routya.ResultKit&version=2.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Routya.ResultKit&version=2.1.0
                    
Install as a Cake Tool

CI CI NuGet NuGet NuGet AspNetCore NuGet AspNetCore .NET Standard Supports Nested Validation

ðŸ“Ķ 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.AspNetCore package, ToActionResult() and ToHttpResult() 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

  1. 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())
    
  2. 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)
    
  3. 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 ProblemDetails
    
  4. ASP.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

  1. Update package: dotnet add package Routya.ResultKit --version 2.1.0
  2. Replace Result.Success → Result.Ok
  3. Replace Result.Failure → Result.Fail (use ProblemDetailsBuilder)
  4. Replace ValidateObject() → Validate()
  5. For ASP.NET Core, add Routya.ResultKit.AspNetCore package

📖 Full Migration Guide - Complete migration documentation with examples


📚 Documentation & Resources


Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.

Version Downloads Last Updated
2.1.0 461 11/20/2025
2.0.0 403 11/19/2025
1.0.2 228 4/30/2025
1.0.1 168 4/25/2025
1.0.0 185 4/25/2025

v2.1.0: Added NoContent() for 204 responses and Redirect()/RedirectPermanent() for 301/302 redirects. Includes automatic status code handling.