Knight.Response.AspNetCore
1.0.1
See the version list below for details.
dotnet add package Knight.Response.AspNetCore --version 1.0.1
NuGet\Install-Package Knight.Response.AspNetCore -Version 1.0.1
<PackageReference Include="Knight.Response.AspNetCore" Version="1.0.1" />
<PackageVersion Include="Knight.Response.AspNetCore" Version="1.0.1" />
<PackageReference Include="Knight.Response.AspNetCore" />
paket add Knight.Response.AspNetCore --version 1.0.1
#r "nuget: Knight.Response.AspNetCore, 1.0.1"
#:package Knight.Response.AspNetCore@1.0.1
#addin nuget:?package=Knight.Response.AspNetCore&version=1.0.1
#tool nuget:?package=Knight.Response.AspNetCore&version=1.0.1
Knight.Response.AspNetCore
ASP.NET Core integration for [Knight.Response]. It converts Result
/ Result<T>
to HTTP responses, supports RFC7807 ProblemDetails (including validation errors), and provides an exception middleware for consistent error payloads.
NuGet packages you’ll typically use:
Knight.Response
– core result types and extensionsKnight.Response.AspNetCore
– this HTTP integration layer
Install
dotnet add package Knight.Response.AspNetCore
Quick start
1) Register in DI
// Program.cs
using Knight.Response.AspNetCore.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Add Knight.Response HTTP integration (optional inline configuration)
builder.Services.AddKnightResponse(options =>
{
// Defaults shown; override as needed
options.IncludeFullResultPayload = true;
options.UseProblemDetails = false;
options.UseValidationProblemDetails = false;
options.IncludeExceptionDetails = false; // keep false in production
// Inline override (not common; prefer the typed overload below)
options.ValidationMapper = new MyValidationErrorMapper();
});
// Option A: register a custom validation mapper separately
builder.Services.AddScoped<IValidationErrorMapper, MyValidationErrorMapper>();
// Option B: use the typed overload
builder.Services.AddKnightResponse<MyValidationErrorMapper>(options =>
{
options.UseValidationProblemDetails = true;
});
2) Add the exception middleware (optional)
var app = builder.Build();
app.UseKnightResponseExceptionMiddleware(); // must be registered before endpoints
app.MapGet("/", () => "OK");
app.Run();
The middleware catches unhandled exceptions and returns a consistent payload (ProblemDetails or JSON), honoring your configured options.
Using results in endpoints and controllers
You can return a Result
/Result<T>
as an ASP.NET Core IResult
via helpers or extensions.
Minimal APIs
using Knight.Response.AspNetCore.Extensions;
using Knight.Response.Factories;
// Example domain service
public interface IUserService
{
Task<Result<UserDto>> GetByIdAsync(int id, CancellationToken ct);
}
public record UserDto(int Id, string Name);
// Minimal API endpoint
app.MapGet("/users/{id:int}", async (int id, HttpContext http, IUserService userService, CancellationToken ct) =>
{
var result = await userService.GetByIdAsync(id, ct);
// Converts Result<UserDto> → IResult (200 if success, 400/ProblemDetails otherwise)
return result.ToIResult(http);
});
MVC Controllers
using Knight.Response.AspNetCore.Factories;
using Knight.Response.Core;
using Microsoft.AspNetCore.Mvc;
// Example DTOs
public record CreateUserRequest(string Name);
public record UserDto(int Id, string Name);
// Example domain service
public interface IUserService
{
Task<Result<UserDto>> CreateAsync(CreateUserRequest request, CancellationToken ct);
Task<Result<UserDto>> GetByIdAsync(int id, CancellationToken ct);
}
[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
private readonly IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
[HttpPost]
public async Task<IResult> Create([FromBody] CreateUserRequest request, CancellationToken ct)
{
var result = await _userService.CreateAsync(request, ct);
// Maps Result<UserDto> → 201 Created or error
return ApiResults.Created(result, HttpContext, location: result.IsSuccess
? $"/api/users/{result.Value.Id}"
: null);
}
[HttpGet("{id:int}")]
public async Task<IResult> Get(int id, CancellationToken ct)
{
var result = await _userService.GetByIdAsync(id, ct);
// Maps Result<UserDto> → 200 OK if found, otherwise 400/ProblemDetails
return ApiResults.Ok(result, HttpContext);
}
}
What gets returned
Behavior depends on KnightResponseOptions
:
Success (2xx):
IncludeFullResultPayload = true
Returns the fullResult
/Result<T>
as JSON (201 Created
uses the body and optionalLocation
header).IncludeFullResultPayload = false
ReturnsValue
(forResult<T>
) or an empty 2xx with the chosen status.
Failure (non-2xx):
UseProblemDetails = true
Returns RFC7807ProblemDetails
. IfUseValidationProblemDetails = true
and the validation mapper produces field errors, returnsValidationProblemDetails
.UseProblemDetails = false
Returns a simple JSON array of messages with the chosen status.
Status codes: Determined by
StatusCodeResolver
(defaults shown below).
Default status code mapping
Knight.Response Status | Default HTTP Status Code |
---|---|
Success |
200 (or requested 2xx, e.g. 201, 204) |
Failed |
400 |
Cancelled |
409 |
Error |
500 |
You can override this mapping via KnightResponseOptions.StatusCodeResolver
.
API surface
Result → IResult conversion
Use either the extensions or the factory:
Extensions (Minimal API friendly)
Result.ToIResult(HttpContext? http = null)
Result<T>.ToIResult(HttpContext? http = null)
Factory methods (works everywhere)
ApiResults.Ok(Result|Result<T>, HttpContext? http = null)
ApiResults.Created(Result|Result<T>, HttpContext? http = null, string? location = null)
ApiResults.Accepted(Result|Result<T>, HttpContext? http = null, string? location = null)
ApiResults.NoContent(Result, HttpContext? http = null)
ApiResults.BadRequest(Result, HttpContext? http = null)
ApiResults.NotFound(Result, HttpContext? http = null)
ApiResults.Conflict(Result, HttpContext? http = null)
ApiResults.Unauthorized()
,ApiResults.Forbidden()
All methods consult DI for KnightResponseOptions
if HttpContext
is provided; otherwise defaults are used.
Options
Options type comes from
public sealed class KnightResponseOptions
: KnightResponseBaseOptions<ProblemDetails, ValidationProblemDetails>
{
// Same core properties:
// - IncludeFullResultPayload
// - UseProblemDetails
// - UseValidationProblemDetails
// - IncludeExceptionDetails
// - StatusCodeResolver
// - ValidationMapper (default: DefaultValidationErrorMapper from Abstractions)
// - ProblemDetailsBuilder, ValidationBuilder
}
Register and customize:
builder.Services.AddKnightResponse(options =>
{
options.IncludeFullResultPayload = true;
options.UseProblemDetails = true;
options.UseValidationProblemDetails = true;
options.StatusCodeResolver = status => status switch
{
Status.Failed => StatusCodes.Status400BadRequest,
Status.Cancelled => StatusCodes.Status409Conflict,
Status.Error => StatusCodes.Status500InternalServerError,
_ => StatusCodes.Status400BadRequest
};
// Optional customization of ProblemDetails payload
options.ProblemDetailsBuilder = (http, result, pd) =>
{
pd.Extensions["svcStatus"] = result.Status.ToString();
};
});
Validation mapping
By default, validation messages are projected to a simple Dictionary<string, string[]>
using DefaultValidationErrorMapper
. Plug in your own:
builder.Services.AddKnightResponse();
builder.Services.AddScoped<IValidationErrorMapper, MyCustomMapper>();
If the mapper returns one or more field errors and UseValidationProblemDetails
is enabled, responses use ValidationProblemDetails
. Otherwise they fall back to standard ProblemDetails
.
Exception middleware
UseKnightResponseExceptionMiddleware()
wraps the pipeline and converts unhandled exceptions to a consistent error response:
- Logs exceptions via
ILogger<KnightResponseExceptionMiddleware>
- Honors
UseProblemDetails
andIncludeExceptionDetails
- Uses
StatusCodeResolver
to select the HTTP status (default 500)
Register early in the pipeline (after logging, before endpoints):
app.UseKnightResponseExceptionMiddleware();
Notes
- Works with both Minimal APIs and MVC controllers.
IResult
is first-class in .NET 8 and can be returned from controllers as well. - If you prefer
IActionResult
, you can wrapIResult
viaResults.Extensions.ToActionResult()
in .NET 8+, but this library focuses onIResult
for modern apps. - For consistent payloads across your app, prefer returning
Result
/Result<T>
and translating via these helpers everywhere.
License
This project is licensed under the MIT License.
Contributing
Contributions are welcome! Please read CONTRIBUTING.md.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | 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. |
-
net8.0
- Knight.Response.Abstractions.Http (>= 1.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
- Internal refactor to depend on Knight.Response.Abstractions.Http for shared options and validation mappers.
- No functional changes; public API surface remains the same.