Knight.Response
2.0.0-preview04
See the version list below for details.
dotnet add package Knight.Response --version 2.0.0-preview04
NuGet\Install-Package Knight.Response -Version 2.0.0-preview04
<PackageReference Include="Knight.Response" Version="2.0.0-preview04" />
<PackageVersion Include="Knight.Response" Version="2.0.0-preview04" />
<PackageReference Include="Knight.Response" />
paket add Knight.Response --version 2.0.0-preview04
#r "nuget: Knight.Response, 2.0.0-preview04"
#:package Knight.Response@2.0.0-preview04
#addin nuget:?package=Knight.Response&version=2.0.0-preview04&prerelease
#tool nuget:?package=Knight.Response&version=2.0.0-preview04&prerelease
Knight.Response
Knight.Response is a lightweight, immutable, fluent result library for C# services, APIs, and applications. It provides a clean and consistent way to handle outcomes, success/failure states, codes, messages, and functional chaining — making your code simpler, safer, and more expressive.
Features
- Immutable
Result
andResult<T>
types - Statuses:
Completed
,Cancelled
,Failed
,Error
- Optional
ResultCode
for domain/system-defined reasons - Built-in
ResultCodes
(ValidationFailed, NotFound, AlreadyExists, NoContent, Created, Updated, Deleted, etc.) - Rich
Message
withMessageType
+ optional structuredMetadata
- Factory methods:
Success
,Failure
,Error
,Cancel
,NotFound
,NoContent
,FromCondition
,Aggregate
,Error(Exception)
- Functional extensions:
OnSuccess
,OnFailure
,Map
,Bind
- Advanced extensions:
Ensure
,Tap
,Recover
,WithCode
,WithoutCode
,WithMessage
,WithMessages
,WithDetail
- Branching:
Match
,MatchValue
for expressive success/failure/null handling - Predicates:
IsSuccess
,IsFailure
,IsError
,IsCancelled
,IsUnsuccessful
,IsUnsuccessfulOrNull
,ValueIsNull
- Validation helpers:
TryGetValidationResults
,GetValidationResults
- Pattern matching via deconstruction
- Zero runtime dependencies
Installation
dotnet add package Knight.Response --version 2.0.0-preview04
Quick Start
using Knight.Response;
using Knight.Response.Models;
var userResult = Results.Success(new User("Knight"), code: ResultCodes.Created)
.Ensure(u => u!.IsActive, "User is not active")
.Tap(u => _audit.LogLogin(u!));
if (userResult.IsSuccess())
{
Console.WriteLine(userResult.Value!.Name);
}
else if (userResult.HasCode(ResultCodes.ValidationFailed))
{
Console.WriteLine("Validation failed");
}
Core Concepts
public class Result
{
public Status Status { get; }
public ResultCode? Code { get; } // optional reason, e.g. "NotFound"
public IReadOnlyList<Message> Messages { get; }
}
public class Result<T> : Result
{
public T? Value { get; }
}
Status
Completed
Cancelled
Failed
Error
ResultCode
Optional, transport-agnostic reason for the result.
Use built-in ResultCodes
or define your own.
MessageType
Information
Warning
Error
Metadata
Message
supports optional Metadata
as a read-only dictionary for structured context, e.g.:
var msg = new Message(
MessageType.Warning,
"Rate limit exceeded",
new Dictionary<string, object?> { ["retryAfter"] = 30 }
);
Factory Methods
Method | Description |
---|---|
Results.Success() |
Create a success result |
Results.Success<T>(T value) |
Success result with data |
Results.Success<T>(T value, IReadOnlyList<Message> messages) |
Success with value and messages |
Results.Failure(string reason, ResultCode? code = null) |
Failure result with message + optional code |
Results.Failure(IReadOnlyList<Message> messages) |
Failure from messages |
Results.Error(string reason, ResultCode? code = null) |
Error result |
Results.Error(Exception ex) |
Error result from exception |
Results.Cancel(string reason) |
Cancelled result (defaults to Warning ) |
Results.Cancel(IReadOnlyList<Message> messages) |
Cancelled from messages |
Results.NotFound() |
"Not found" (defaults to Completed + Warning ) |
Results.NoContent() |
"No content" (defaults to Completed ) |
Results.FromCondition(bool condition, string failMessage) |
Success if true, Failure if false |
Results.Aggregate(IEnumerable<Result> results) |
Combine multiple results |
Core Extensions
result.OnSuccess(() => Console.WriteLine("All good"))
.OnFailure(msgs => Console.WriteLine($"Failed: {string.Join(", ", msgs.Select(m => m.Content))}"));
var mapped = Results.Success(2).Map(x => x * 5); // Success(10)
var bound = Results.Success("abc").Bind(v => Results.Success(v.ToUpper()));
- IsSuccess / IsFailure / IsError / IsCancelled / IsUnsuccessful / IsUnsuccessfulOrNull
- OnSuccess – Runs an action if result is success
- OnFailure – Runs an action if result is not success
- Map – Transforms the value if success
- Bind – Chains another
Result
operation if success
Advanced Extensions
- Ensure – Ensures a predicate holds for success; otherwise returns failure
- Tap – Executes an action for side effects, preserving the result
- Recover – Transforms a failure into a success with fallback value
- WithCode / WithoutCode – Adds, replaces, or clears a
ResultCode
- WithMessage – Adds a single message to a result
- WithMessages – Adds multiple messages to a result
- WithDetail – Attaches structured metadata to the last message
- ValueIsNull – Checks if
Result<T>.Value
is null
var ensured = Results.Success(5).Ensure(x => x > 0, "Must be positive");
var tapped = ensured.Tap(v => Console.WriteLine($"Value: {v}"));
var recovered = Results.Failure<int>("bad", code: ResultCodes.ValidationFailed).Recover(_ => 42);
var withMsg = recovered.WithMessage(new Message(MessageType.Information, "Recovered with default"));
if (recovered.ValueIsNull())
Console.WriteLine("No value present.");
Branching with Match
var result = Results.Failure<int>("Not valid", code: ResultCodes.ValidationFailed);
result.Match(
onUnsuccessful: msgs => Console.WriteLine($"Failed: {string.Join(", ", msgs.Select(m => m.Content))}"),
onSuccess: () => Console.WriteLine("All good!")
);
Producing results with MatchValue
var processed = result.MatchValue(
onUnsuccessful: msgs => Results.Failure<int>("Could not process further"),
onNoValue: () => Results.NoContent<int>(),
onValue: v => Results.Success(v * 10)
);
These let you return directly from a method, eliminating repeated if/else
checks.
Validation Support
Validation errors can be converted into results and later retrieved:
using System.ComponentModel.DataAnnotations;
var errors = new List<ValidationResult>
{
new("Name is required", new[] { "Name" }),
new("Amount must be greater than 0", new[] { "Amount" })
};
var result = Results.Validation(errors);
if (result.TryGetValidationResults(out var vr))
{
foreach (var v in vr)
Console.WriteLine($"Validation: {v.ErrorMessage}");
}
Pattern Matching
You can deconstruct results directly:
var (status, code, messages) = Results.Failure("fail!", code: ResultCodes.ValidationFailed);
var (status, code, messages, value) = Results.Success(42, code: ResultCodes.Created);
Or use C# pattern matching:
switch (result)
{
case { Status: Status.Completed }:
Console.WriteLine("Success!");
break;
case { Status: Status.Failed, Messages: var msgs }:
Console.WriteLine($"Failed: {msgs[0].Content}");
break;
}
Important: Result<T>.Value
and default values
When T
is a non-nullable value type, failed results will contain the default value of that type (0
for int
, false
for bool
, etc.). This is a limitation of .NET generics.
var r1 = Results.Failure<int>("bad");
Console.WriteLine(r1.Value); // 0
var r2 = Results.Failure<int?>("bad");
Console.WriteLine(r2.Value); // null
Guidance
- Use nullable value types (e.g.
int?
,bool?
) if you wantnull
to represent "no value". - Use non-nullable value types if a default like
0
orfalse
makes sense in your domain. - Reference types (e.g.
string
,User
) will correctly returnnull
when notCompleted
.
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 | 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. |
-
.NETStandard 2.0
- System.ComponentModel.Annotations (>= 5.0.0)
- System.Text.Json (>= 9.0.8)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Knight.Response:
Package | Downloads |
---|---|
Knight.Response.Abstractions.Http
Framework-agnostic HTTP abstractions for Knight.Response (shared options and validation mapping). |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
2.0.0-preview05 | 259 | 9/26/2025 |
2.0.0-preview04 | 298 | 9/25/2025 |
2.0.0-preview03 | 467 | 9/22/2025 |
2.0.0-preview02 | 171 | 9/22/2025 |
2.0.0-preview01 | 175 | 9/22/2025 |
1.1.0 | 570 | 9/1/2025 |
1.0.2 | 400 | 8/26/2025 |
1.0.1 | 272 | 8/15/2025 |
1.0.0 | 145 | 8/14/2025 |
- Added: `IsUnsuccessfulOrNull`, `HasCode` overloads, `WithCode`/`WithoutCode` helpers, `NoContent` factory, extended `ResultCodes`.
- Improved: XML docs, test coverage to reduce mutants.
- Fixed: Minor issues in extensions and message metadata handling.