ResultR 1.0.2

dotnet add package ResultR --version 1.0.2
                    
NuGet\Install-Package ResultR -Version 1.0.2
                    
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="ResultR" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ResultR" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="ResultR" />
                    
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 ResultR --version 1.0.2
                    
#r "nuget: ResultR, 1.0.2"
                    
#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 ResultR@1.0.2
                    
#: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=ResultR&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=ResultR&version=1.0.2
                    
Install as a Cake Tool

ResultR

GitHub Actions Workflow Status NuGet Version NuGet Downloads GitHub License

📖 Overview

ResultR is a lightweight request/response dispatcher for .NET applications. It routes requests to handlers and wraps all responses in a Result<T> type for consistent success/failure handling.

What it does:

  • Decouples your application logic by routing requests to dedicated handler classes
  • Provides a predictable pipeline: Validate → BeforeHandle → Handle → AfterHandle
  • Catches exceptions automatically and returns them as failure results
  • Eliminates the need for try/catch blocks scattered throughout your codebase

What it doesn't do:

  • No notifications or pub/sub messaging
  • No pipeline behaviors or middleware chains
  • No stream handling
  • No distributed messaging

This focused scope keeps the library small, fast, and easy to understand.

📋 Requirements

  • .NET 10.0 or later
  • C# 14.0 or later

📥 Installation

dotnet add package ResultR

🚀 Quick Start

1. Define a Request

public record CreateUserRequest(string Email, string Name, int Age) : IRequest<User>;

2. Create a Handler

public class CreateUserHandler : IRequestHandler<CreateUserRequest, User>
{
    private readonly IUserRepository _repository;
    private readonly ILogger<CreateUserHandler> _logger;

    public CreateUserHandler(IUserRepository repository, ILogger<CreateUserHandler> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    // Optional: Validate the request (override virtual method)
    public ValueTask<Result> ValidateAsync(CreateUserRequest request)
    {
        if (string.IsNullOrWhiteSpace(request.Email))
            return new(Result.Failure("Email is required"));
        
        if (!request.Email.Contains("@"))
            return new(Result.Failure("Invalid email format"));
        
        return new(Result.Success());
    }

    // Optional: Before handle hook (override virtual method)
    public ValueTask BeforeHandleAsync(CreateUserRequest request)
    {
        _logger.LogInformation("Creating user with email: {Email}", request.Email);
        return default;
    }

    // Required: Core handler logic
    public async ValueTask<Result<User>> HandleAsync(CreateUserRequest request, CancellationToken cancellationToken)
    {
        // Exceptions are automatically caught and converted to Result.Failure
        var user = new User(request.Email, request.Name, request.Age);
        await _repository.AddAsync(user, cancellationToken);
        return Result<User>.Success(user);
    }

    // Optional: After handle hook (override virtual method)
    public ValueTask AfterHandleAsync(CreateUserRequest request, Result<User> result)
    {
        if (result.IsSuccess)
            _logger.LogInformation("User created successfully: {UserId}", result.Value.Id);
        else
            _logger.LogError("User creation failed: {Error}", result.Error);
        return default;
    }
}

3. Register with DI

// Simple: auto-scans entry assembly
services.AddResultR();

// Or explicit: scan specific assemblies (for multi-project solutions)
services.AddResultR(
    typeof(Program).Assembly,
    typeof(MyHandlers).Assembly);

4. Dispatch Requests

public class UserController : ControllerBase
{
    private readonly IDispatcher _dispatcher;

    public UserController(IDispatcher dispatcher)
    {
        _dispatcher = dispatcher;
    }

    [HttpPost]
    public async Task<IActionResult> CreateUser(CreateUserRequest request)
    {
        var result = await _dispatcher.Dispatch(request);
        
        return result.IsSuccess 
            ? Ok(result.Value) 
            : BadRequest(result.Error);
    }
}

📦 Result Type

The Result<T> type provides a clean way to handle success and failure states:

// Success
var success = Result<User>.Success(user);

// Failure with message
var failure = Result<User>.Failure("User not found");

// Failure with exception
var error = Result<User>.Failure("Database error", exception);

// Checking results
if (result.IsSuccess)
{
    var value = result.Value;
}
else
{
    var error = result.Error;
    var exception = result.Exception;
}

For void operations, use the non-generic Result with IRequest:

public record DeleteUserRequest(Guid UserId) : IRequest;

public class DeleteUserHandler : IRequestHandler<DeleteUserRequest>
{
    public async ValueTask<Result> HandleAsync(DeleteUserRequest request, CancellationToken cancellationToken)
    {
        await _repository.DeleteAsync(request.UserId);
        return Result.Success();
    }
}

❓ Why ResultR?

ResultR prioritizes simplicity and explicitness over flexibility, giving you a focused request/handler pattern without the complexity of pipelines, behaviors, or middleware chains that you may never need. Every operation returns a unified Result or Result<T> type, making error handling consistent and predictable across your entire codebase. The optional inline hooks (ValidateAsync, BeforeHandleAsync, AfterHandleAsync) let you add cross-cutting concerns directly in your handlers without separate classes or DI registrations, keeping related logic together and reducing ceremony.

💬 Support

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

ISC License - see the LICENSE file for details.


Built with ❤️ for the C# / DotNet community.

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 ResultR:

Package Downloads
ResultR.Validation

Lightweight inline validation framework for ResultR. Define validation rules directly in ValidateAsync() using a fluent API, with seamless integration into ResultR's pipeline hooks.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 108 1/28/2026
1.0.1 116 1/2/2026
1.0.0 136 12/28/2025
1.0.0-beta.6 254 12/18/2025
1.0.0-beta.5 636 12/2/2025
1.0.0-beta.4 80 11/29/2025
1.0.0-beta.3 79 11/29/2025
1.0.0-beta.2 155 11/26/2025
1.0.0-beta.1 155 11/26/2025