CleanArch.DevKit.Mediator.Results
1.0.0
See the version list below for details.
dotnet add package CleanArch.DevKit.Mediator.Results --version 1.0.0
NuGet\Install-Package CleanArch.DevKit.Mediator.Results -Version 1.0.0
<PackageReference Include="CleanArch.DevKit.Mediator.Results" Version="1.0.0" />
<PackageVersion Include="CleanArch.DevKit.Mediator.Results" Version="1.0.0" />
<PackageReference Include="CleanArch.DevKit.Mediator.Results" />
paket add CleanArch.DevKit.Mediator.Results --version 1.0.0
#r "nuget: CleanArch.DevKit.Mediator.Results, 1.0.0"
#:package CleanArch.DevKit.Mediator.Results@1.0.0
#addin nuget:?package=CleanArch.DevKit.Mediator.Results&version=1.0.0
#tool nuget:?package=CleanArch.DevKit.Mediator.Results&version=1.0.0
CleanArch.DevKit.Mediator.Results
Type Result à la rust/F#, erreurs typées et behavior qui transforme les ValidationException en Result.Fail(...).
Rôle
Modélise les échecs métier comme des valeurs plutôt que comme des exceptions. Les handlers retournent Result (sans valeur) ou Result<T> (avec valeur), portant soit une réussite, soit une liste d'Error typées. Inclut un IPipelineBehavior<,> qui convertit la ValidationException du package Validation en ValidationError, ce qui évite les try/catch dans les handlers.
Installation
dotnet add package CleanArch.DevKit.Mediator.Results
Dépend de CleanArch.DevKit.Mediator et de CleanArch.DevKit.Mediator.Validation.
Fonctionnalités
- Type
ResultetResult<T>(struct, sans allocation) - Type de base
Error(Code, Message) - Erreurs préfournies :
NotFoundError,ConflictError,ForbiddenError,UnauthorizedError,ValidationError - Conversions implicites depuis
TetError - Extensions de composition :
Map,Bind,Match,MapError,OnSuccess,OnFailure(+ variantes async) ResultBehavior—ValidationException→ValidationError
Result et Result<T>
Result.Ok(); // succès sans valeur
Result.Fail(new NotFoundError(...)); // échec avec une erreur
Result.Fail(errors); // échec avec plusieurs erreurs
Result<User>.Ok(user);
Result<User>.Fail(new ConflictError("user.email_taken", "..."));
Inspection :
if (result.IsSuccess) { /* ... */ }
if (result.IsFailure) { /* ... */ }
foreach (var error in result.Errors) { /* ... */ }
var value = result.Value; // throw si IsFailure — préférer Match
ResultetResult<T>sont desreadonly struct: aucune allocation sur le tas pour le wrapper lui-même.
Type Error et erreurs préfournies
Error est un record abstract :
public abstract record Error(string Code, string Message);
Le package fournit cinq dérivés concrets pour les cas usuels :
| Type | Quand l'utiliser |
|---|---|
NotFoundError |
L'entité demandée n'existe pas |
ConflictError |
Conflit avec l'état courant (doublon, version stale, etc.) |
ForbiddenError |
L'utilisateur est authentifié mais n'a pas l'autorisation |
UnauthorizedError |
L'utilisateur n'est pas authentifié |
ValidationError |
Une ou plusieurs ValidationFailure |
return new NotFoundError("user.not_found", $"Utilisateur '{id}' introuvable.");
// Raccourci pour le cas "entité X avec id Y"
return NotFoundError.ForEntity("User", 42);
// → Code: "user.not_found", Message: "User '42' not found."
Pour des erreurs métier propres, dériver d'Error :
public sealed record InsufficientFundsError(decimal Balance, decimal Requested)
: Error("payment.insufficient_funds",
$"Solde {Balance:C} insuffisant pour un retrait de {Requested:C}.");
Conversions implicites
Une T se convertit en Result<T>.Ok(value), un Error en Result.Fail(error) :
public Result<User> GetUser(int id)
{
var user = repo.Find(id);
if (user is null)
return new NotFoundError("user.not_found", $"Utilisateur {id}.");
return user; // implicit conversion → Result<User>.Ok(user)
}
Composer avec Map, Bind, Match
Result<UserDto> dto = result
.Map(user => mapper.Map<UserDto>(user)); // transforme la valeur
Result<Order> order = userResult
.Bind(user => orderRepo.GetFor(user)); // chaîne une autre op qui peut échouer
IActionResult response = userResult.Match(
onSuccess: user => Ok(user),
onFailure: errors => BadRequest(errors));
Variantes async (MapAsync, BindAsync, MatchAsync) qui acceptent Task<Result<T>> :
var dto = await repo.GetAsync(id)
.MapAsync(user => mapper.Map<UserDto>(user));
Effets de bord et transformation d'erreurs
result
.OnSuccess(user => logger.LogInformation("Found {Id}", user.Id))
.OnFailure(errors => logger.LogWarning("Failed: {Count} errors", errors.Count));
result.MapError(err => err is ValidationError v
? new ConflictError("input.invalid", v.Message)
: err);
ResultBehavior — conversion automatique des exceptions
Quand le ValidationBehavior du package Validation détecte des échecs, il lance une ValidationException. Le ResultBehavior attrape cette exception uniquement pour les requêtes dont la réponse est Result ou Result<T>, et la transforme en Result.Fail(new ValidationError(...)) :
services.AddMediator();
services.AddValidationBehavior();
services.AddResultBehavior(); // s'insère en position 0 (le plus externe)
Avec ça, un handler retourne simplement Result<T> — la validation est gérée hors du handler :
public sealed class CreateUserHandler : IRequestHandler<CreateUser, Result<int>>
{
public Task<Result<int>> Handle(CreateUser cmd, CancellationToken ct)
{
// Si la validation a échoué, on n'arrive jamais ici.
// Si une logique métier échoue :
if (emailDuplicate) return new ConflictError("user.email_taken", "...");
var id = repo.Create(cmd);
return Task.FromResult(Result<int>.Ok(id));
}
}
Côté appelant :
var result = await mediator.Send(new CreateUser(...));
return result.Match(
onSuccess: id => Results.Created($"/users/{id}", new { id }),
onFailure: errors => Results.BadRequest(errors));
AddResultBehavior()insère le behavior en position 0 dans la liste desIPipelineBehavior<,>, ce qui le rend indépendant de l'ordre d'appel des autresAdd...Behavior().
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- CleanArch.DevKit.Mediator (>= 1.0.0)
- CleanArch.DevKit.Mediator.Validation (>= 1.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on CleanArch.DevKit.Mediator.Results:
| Package | Downloads |
|---|---|
|
CleanArch.DevKit.Mediator.Results.Testing
Fluent assertions for CleanArch.DevKit.Mediator.Results — Should().BeSuccess(), HaveError<TError>(), HaveValidationErrorFor(...) and more. Standalone assertion library inspired by AwesomeAssertions, with no external assertion-framework dependency. Part of the CleanArch.DevKit set. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.1.1 | 98 | 5/17/2026 |
| 1.1.0 | 91 | 5/17/2026 |
| 1.0.0 | 112 | 5/15/2026 |
| 0.1.0-preview.1 | 45 | 5/14/2026 |