Routya.ResultKit.AspNetCore 2.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Routya.ResultKit.AspNetCore --version 2.0.0
                    
NuGet\Install-Package Routya.ResultKit.AspNetCore -Version 2.0.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.AspNetCore" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Routya.ResultKit.AspNetCore" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Routya.ResultKit.AspNetCore" />
                    
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.AspNetCore --version 2.0.0
                    
#r "nuget: Routya.ResultKit.AspNetCore, 2.0.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.AspNetCore@2.0.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.AspNetCore&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Routya.ResultKit.AspNetCore&version=2.0.0
                    
Install as a Cake Tool

Routya.ResultKit.AspNetCore

ASP.NET Core integration for Routya.ResultKit providing seamless integration with Microsoft's ProblemDetails, automatic exception handling middleware, and IResult/IActionResult extensions for Minimal APIs and MVC controllers.

Features

Automatic Exception Handling - Global middleware that converts exceptions to RFC 7807 ProblemDetails
Microsoft ProblemDetails Integration - Bidirectional conversion with Microsoft.AspNetCore.Http.ProblemDetails
Minimal API Support - ToHttpResult() extension for seamless IResult conversion
MVC Controller Support - ToActionResult() extension for IActionResult conversion
Custom Exception Mappers - Register custom exception-to-ProblemDetails mappers
Configurable Options - Control trace IDs, exception details, naming policies, and more
RFC 7807 Compliant - Automatic application/problem+json content type

Requirements

  • .NET 7, .NET 8, or .NET 9
  • Routya.ResultKit v2.0.0+

Installation

dotnet add package Routya.ResultKit.AspNetCore

Quick Start

1. Register Services

using Routya.ResultKit.AspNetCore.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Add ResultKit services
builder.Services.AddResultKitProblemDetails(options =>
{
    options.ProblemTypeBaseUri = "https://api.example.com/problems/";
    options.IncludeExceptionDetails = builder.Environment.IsDevelopment();
    options.IncludeTraceId = true;
});

var app = builder.Build();

// Add exception handler middleware (early in pipeline)
app.UseResultKitExceptionHandler();

app.MapControllers();
app.Run();

2. Use in Minimal APIs

app.MapPost("/users", (CreateUserRequest request, HttpContext context) =>
{
    var result = request.Validate();
    return result.ToHttpResult(context);
});

Success Response (200 OK):

{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com"
}

Validation Error Response (400 Bad Request):

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json

{
  "type": "urn:problem-type:validation-error",
  "title": "Validation Failed",
  "status": 400,
  "detail": "One or more validation errors occurred.",
  "instance": "/users",
  "errors": {
    "email": ["The Email field is required."],
    "name": ["The Name field is required."]
  },
  "traceId": "00-abc123..."
}

3. Use in MVC Controllers

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult GetUser(int id)
    {
        var user = _repository.FindById(id);
        
        if (user == null)
            return Result<User>.NotFound($"User with ID {id} not found")
                .ToActionResult(HttpContext);
        
        return Result<User>.Ok(user).ToActionResult();
    }
    
    [HttpPost]
    public IActionResult CreateUser(CreateUserRequest request)
    {
        var validationResult = request.Validate();
        if (!validationResult.Success)
            return validationResult.ToActionResult(HttpContext);
        
        var user = _repository.Create(request);
        
        // Result.Created() automatically sets 201 status code
        return Result<User>.Created(user).ToActionResult(HttpContext);
    }
    
    [HttpPost("{id}/process")]
    public IActionResult ProcessUser(int id)
    {
        _processor.QueueForProcessing(id);
        
        // Result.Accepted() automatically sets 202 status code
        return Result<object>.Accepted(new { id, status = "queued" })
            .ToActionResult(HttpContext);
    }
}

Exception Handling

The middleware automatically converts unhandled exceptions to RFC 7807 ProblemDetails:

app.MapGet("/users/{id}", (int id) =>
{
    if (id <= 0)
        throw new ArgumentException("ID must be positive");
    
    // Automatically becomes 400 Bad Request with ProblemDetails
    return Results.Ok(GetUser(id));
});

Custom Exceptions

using Routya.ResultKit.AspNetCore.Exceptions;
using Routya.ResultKit.ProblemTypes;

public class InsufficientFundsException : ProblemDetailsException
{
    public InsufficientFundsException(decimal available, decimal requested)
        : base(
            type: StandardProblemTypes.Custom("insufficient-funds"),
            title: "Insufficient Funds",
            status: 400,
            detail: $"Balance ${available} is less than requested ${requested}")
    {
        Extensions["availableBalance"] = available;
        Extensions["requestedAmount"] = requested;
    }
}

Custom Exception Mappers

public class UserNotFoundExceptionMapper : IExceptionMapper
{
    public bool CanHandle(Exception exception) 
        => exception is UserNotFoundException;
    
    public ProblemDetails Map(Exception exception, HttpContext context)
    {
        var ex = (UserNotFoundException)exception;
        return ProblemDetailsBuilder.NotFound(ex.Message)
            .WithInstance(context.Request.Path)
            .WithExtension("userId", ex.UserId)
            .Build();
    }
}

// Register
builder.Services.AddExceptionMapper(new UserNotFoundExceptionMapper());

Configuration Options

builder.Services.AddResultKitProblemDetails(options =>
{
    // Base URI for domain-specific problem types
    options.ProblemTypeBaseUri = "https://api.example.com/problems/";
    
    // Include exception details (stacktrace, etc.) - should be false in production
    options.IncludeExceptionDetails = builder.Environment.IsDevelopment();
    
    // Automatically add trace ID to all problem responses
    options.IncludeTraceId = true;
    
    // Name of the trace ID extension member
    options.TraceIdExtensionName = "traceId";
    
    // JSON naming policy (default: camelCase)
    options.NamingPolicy = JsonNamingPolicy.CamelCase;
});

Built-in Exception Mappings

The following exceptions are automatically mapped:

Exception Type HTTP Status Problem Type
ProblemDetailsException Custom Custom
ArgumentException 400 Bad Request
ArgumentNullException 400 Bad Request
ArgumentOutOfRangeException 400 Bad Request
UnauthorizedAccessException 403 Forbidden
InvalidOperationException 409 Conflict
NotImplementedException 501 Not Implemented
Other exceptions 500 Internal Server Error

Result Status Codes

Result<T> carries a StatusCode property that determines the HTTP status code:

Result<User>.Ok(user)        // StatusCode = 200
Result<User>.Created(user)   // StatusCode = 201
Result<User>.Accepted(data)  // StatusCode = 202
Result<User>.NotFound()      // StatusCode = 404 (from ProblemDetails)
Result<User>.BadRequest()    // StatusCode = 400 (from ProblemDetails)
// etc.

When calling ToHttpResult() or ToActionResult(), the appropriate HTTP response is automatically generated:

Result Method Status Code HTTP Response
Ok(data) 200 OkObjectResult / Results.Ok()
Created(data) 201 CreatedResult / Results.Created()
Accepted(data) 202 AcceptedResult / Results.Accepted()
Fail(problem) From ProblemDetails ObjectResult with ProblemDetails

No need to manually specify status codes - the semantic intent is carried by the Result itself.

API Reference

Extension Methods

ToHttpResult<T>()

Converts Result<T> to IResult for Minimal APIs. Automatically uses the status code from result.StatusCode.

public static IResult ToHttpResult<T>(this Result<T> result, HttpContext? context = null)

Parameters:

  • result - The Result to convert
  • context - Optional HttpContext for setting the instance property from the request path

Returns: Appropriate IResult based on result.StatusCode (200→Ok, 201→Created, 202→Accepted, etc.)

ToActionResult<T>()

Converts Result<T> to IActionResult for MVC controllers. Automatically uses the status code from result.StatusCode.

public static IActionResult ToActionResult<T>(this Result<T> result, HttpContext? context = null)

Parameters:

  • result - The Result to convert
  • context - Optional HttpContext for setting the instance property from the request path

Returns: Appropriate IActionResult based on result.StatusCode (200→OkObjectResult, 201→CreatedResult, 202→AcceptedResult, etc.)

ToProblemResult()

Converts ProblemDetails to IResult.

public static IResult ToProblemResult(this ProblemDetails problemDetails)
ToProblemActionResult()

Converts ProblemDetails to IActionResult.

public static IActionResult ToProblemActionResult(this ProblemDetails problemDetails)

Converters

ProblemDetailsConverter.ToMicrosoft()

Converts Routya.ResultKit.ProblemDetails to Microsoft.AspNetCore.Http.ProblemDetails.

public static Microsoft.AspNetCore.Http.ProblemDetails ToMicrosoft(
    Routya.ResultKit.ProblemDetails source)
ProblemDetailsConverter.FromMicrosoft()

Converts Microsoft.AspNetCore.Http.ProblemDetails to Routya.ResultKit.ProblemDetails.

public static Routya.ResultKit.ProblemDetails FromMicrosoft(
    Microsoft.AspNetCore.Http.ProblemDetails source)

Examples

See the Migration Guide for complete examples.

License

MIT License - see LICENSE

Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
2.1.0 386 11/20/2025
2.0.0 388 11/19/2025