CleanArch.DevKit.Mediator.Results 1.1.0

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

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 Result et Result<T> (struct, sans allocation)
  • Type de base Error(Code, Message)
  • Erreurs préfournies : NotFoundError, ConflictError, ForbiddenError, UnauthorizedError, ValidationError
  • Conversions implicites depuis T et Error
  • Extensions de composition : Map, Bind, Match, MapError, OnSuccess, OnFailure (+ variantes async)
  • ResultBehaviorValidationExceptionValidationError

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

Result et Result<T> sont des readonly 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 des IPipelineBehavior<,>, ce qui le rend indépendant de l'ordre d'appel des autres Add...Behavior().

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

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