EasyRequestHandler 1.1.5

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

Easy Request Handler

EasyRequestHandler is a lightweight and extensible .NET library that simplifies request and event handling using patterns like Mediator and Event Dispatcher. It integrates seamlessly with the .NET Dependency Injection (DI) system and supports asynchronous operations, making it ideal for modular applications and event-driven systems.

✨ Features

Core Capabilities

  • 🎯 Mediator Pattern: Centralizes request handling with the ISender interface, promoting loose coupling and separation of concerns
  • πŸ”„ Flexible Request Handling: Support for both input-based (RequestHandler<TRequest, TResponse>) and no-input handlers (RequestHandler<TResponse>)
  • πŸ“‘ Event Dispatching: Publish events to multiple handlers with support for both sequential and parallel execution
  • πŸ”Œ Automatic Registration: Register all handlers with a single fluent API call using IServiceCollection extensions
  • πŸͺ Request Hooks: Execute logic before and/or after request handling with three types of hooks:
    • IRequestHook<TRequest, TResponse> - Pre and post execution
    • IRequestPreHook<TRequest> - Pre-execution only
    • IRequestPostHook<TRequest, TResponse> - Post-execution only
  • πŸ”§ Pipeline Behaviors: Add cross-cutting concerns (logging, validation, caching, etc.) as middleware-style behaviors
  • πŸ“ Built-in Logging: Optional structured logging with contextual information for debugging and monitoring
  • ⚑ Performance Optimized: Singleton pattern for no-input requests, optimized task handling, and minimal allocations
  • πŸ”’ Type-Safe: Fully generic, compile-time type checking for requests, responses, and events
  • πŸ§ͺ Testable: Clean abstractions make unit testing straightforward

Key Benefits

  • βœ… Minimal Boilerplate: Define handlers as simple classesβ€”no complex setup required
  • βœ… DI-First Design: Built on Microsoft.Extensions.DependencyInjection for seamless integration
  • βœ… Async by Default: All operations use Task-based async patterns for scalability
  • βœ… Zero Breaking Changes: Backward compatible design maintains existing functionality
  • βœ… Production Ready: Comprehensive error handling, cancellation support, and security validated

πŸ“¦ Installation

Install from NuGet using the .NET CLI:

dotnet add package EasyRequestHandler

Or using Package Manager Console:

Install-Package EasyRequestHandler

🎯 Why Choose EasyRequestHandler?

Compared to MediatR

  • Simpler API: No need for IRequest<T> marker interfaces on your request types
  • Built-in Hooks: Pre/post execution hooks without additional packages
  • Event Publishing: Native support for event dispatching with parallel execution
  • Lightweight: Minimal dependencies and smaller footprint

Compared to Custom Solutions

  • Battle-Tested: Proven patterns and comprehensive error handling
  • Extensible: Easy to add behaviors, hooks, and custom logic
  • Maintained: Regular updates and security fixes
  • Well-Documented: Clear examples and API documentation

πŸš€ Quick Start

Here's a minimal example to get started in 3 steps:

1. Define Your Request and Handler

// Your request
public class CalculateRequest
{
    public int X { get; set; }
    public int Y { get; set; }
}

// Your response
public class CalculateResponse
{
    public int Sum { get; set; }
}

// Your handler
public class CalculateHandler : RequestHandler<CalculateRequest, CalculateResponse>
{
    public override Task<CalculateResponse> HandleAsync(CalculateRequest request, CancellationToken cancellationToken = default)
    {
        return Task.FromResult(new CalculateResponse { Sum = request.X + request.Y });
    }
}

2. Register in DI Container

// In Program.cs or Startup.cs
services.AddEasyRequestHandlers(typeof(Program))
        .WithMediatorPattern()  // Optional: enable ISender
        .Build();

3. Use in Your Application

public class CalculatorController : ControllerBase
{
    private readonly ISender _sender;

    public CalculatorController(ISender sender) => _sender = sender;

    [HttpGet("calculate")]
    public async Task<IActionResult> Calculate(int x, int y)
    {
        var result = await _sender.SendAsync<CalculateRequest, CalculateResponse>(
            new CalculateRequest { X = x, Y = y });
        return Ok(result);
    }
}

That's it! Your handler is automatically discovered, registered, and ready to use.


πŸš€ Usage

🧭 Request Handling

Basic Request Handlers

Handlers can be used in two ways:

  • Direct Injection: Inject the handler class itself (e.g., MyRequestHandler) into your controller or service and call HandleAsync() directly.
  • Mediator Pattern: Use the ISender interface to decouple request handling and improve testability and separation of concerns.

Here’s how you could invoke a request using the ISender interface:

public class MyApiController : ControllerBase
{
    private readonly ISender _sender;

    public MyApiController(ISender sender)
    {
        _sender = sender;
    }

    [HttpGet("double")]
    public async Task<IActionResult> GetDoubledNumber([FromQuery] int number)
    {
        var response = await _sender.SendAsync<MyRequest, MyResponse>(new MyRequest { Number = number });
        return Ok(response.Result);
    }
}

Define a request and handler:

public class MyRequest
{
    public int Number { get; set; }
}

public class MyResponse
{
    public int Result { get; set; }
}

public class MyRequestHandler : RequestHandler<MyRequest, MyResponse>
{
    public override Task<MyResponse> HandleAsync(MyRequest request, CancellationToken cancellationToken = default)
    {
        return Task.FromResult(new MyResponse { Result = request.Number * 2 });
    }
}

For handlers with no input request:

public class WeatherForecastHandler : RequestHandler<List<WeatherForecast>>
{
    public override Task<List<WeatherForecast>> HandleAsync(CancellationToken cancellationToken = default)
    {
        return Task.FromResult(GetForecasts());
    }
}
Mediator Pattern

Use the ISender interface to decouple request invocation:

public async Task<IActionResult> GetForecast(string city, ISender sender)
{
    var forecast = await sender.SendAsync<string, WeatherForecast>(city);
    return Ok(forecast);
}
Request Behaviors

Behaviors are middleware for requests:

public class LoggingBehaviour<TRequest, TResponse> : IPipelineBehaviour<TRequest, TResponse>
{
    private readonly ILogger<LoggingBehaviour<TRequest, TResponse>> _logger;

    public LoggingBehaviour(ILogger<LoggingBehaviour<TRequest, TResponse>> logger)
    {
        _logger = logger;
    }

    public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        _logger.LogInformation("Handling {RequestType}", typeof(TRequest).Name);
        var response = await next();
        _logger.LogInformation("Handled {RequestType}", typeof(TRequest).Name);
        return response;
    }
}
Request Hooks

The library now supports three different types of hooks to provide more flexibility in your request processing pipeline:

// Complete hook (both pre and post execution)
public class MyRequestHook : IRequestHook<MyRequest, MyResponse>
{
    public Task OnExecutingAsync(MyRequest request, CancellationToken cancellationToken)
    {
        Console.WriteLine("Before handling request");
        return Task.CompletedTask;
    }

    public Task OnExecutedAsync(MyRequest request, MyResponse response, CancellationToken cancellationToken)
    {
        Console.WriteLine("After handling request");
        return Task.CompletedTask;
    }
}

// Pre-execution only hook
public class MyRequestPreHook : IRequestPreHook<MyRequest>
{
    public Task OnExecutingAsync(MyRequest request, CancellationToken cancellationToken)
    {
        Console.WriteLine("Pre-hook executing");
        // You can modify request properties here
        return Task.CompletedTask;
    }
}

// Post-execution only hook
public class MyRequestPostHook : IRequestPostHook<MyRequest, MyResponse>
{
    public Task OnExecutedAsync(MyRequest request, MyResponse response, CancellationToken cancellationToken)
    {
        Console.WriteLine("Post-hook executed");
        // You can work with both request and response here
        return Task.CompletedTask;
    }
}
Registration and Configuration
services.AddEasyRequestHandlers(typeof(Program))
        .WithMediatorPattern()
        .WithBehaviours(typeof(LoggingBehaviour<,>), typeof(ValidationBehaviour<,>))
        .WithRequestHooks()
        .Build();

Minimal API example:

//Using direct handler injection.
app.MapGet("/weather-forecast", async (WeatherRequest request, WeatherForecastHandler handler) =>
{
    return await handler.HandleAsync(request);
});

//Using Mediator Pattern
app.MapGet("/weather-forecast", async (WeatherRequest request, ISender sender) =>
{
    return await sender.SendAsync<WeatherRequest, WeatherForecast?>(request, cancellationToken: cancellationToken);
});

πŸ“£ Event Handling

A single event can have multiple handlers. All handlers registered for an event will be invoked, and they can run either sequentially or in parallel depending on the event publisher's implementation.

Basic Event Handler
public class MyEvent
{
    public string Message { get; set; }
}

public class MyEventHandler : IEventHandler<MyEvent>
{
    public Task HandleAsync(MyEvent @event, CancellationToken cancellationToken)
    {
        Console.WriteLine(@event.Message);
        return Task.CompletedTask;
    }
}
Publishing Events
public class MyController
{
    private readonly IEventPublisher _publisher;

    public MyController(IEventPublisher publisher)
    {
        _publisher = publisher;
    }

    public async Task SendNotification(string message)
    {
        await _publisher.PublishAsync(new MyEvent { Message = message });
    }
}

βœ… Summary

EasyRequestHandler provides a clean, extensible way to manage requests and events in .NET, with support for modern patterns like mediator, behaviors, and hooksβ€”all without unnecessary boilerplate.

Perfect For

  • βœ… CQRS Applications: Separate command and query handling with clear boundaries
  • βœ… Clean Architecture: Enforce separation of concerns and dependency inversion
  • βœ… Event-Driven Systems: Publish domain events and handle them asynchronously
  • βœ… Microservices: Standardize request/event handling across services
  • βœ… API Development: Build maintainable REST APIs with consistent patterns

Getting Help

  • πŸ“– Documentation - Full API reference and examples
  • πŸ› Issues - Report bugs or request features
  • πŸ’¬ Discussions - Ask questions and share ideas

Contributing

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


πŸ“„ License

Licensed under MIT License.


Made with ❀️ by Juan Carlos Torres Cuervo

Product 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 netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 359 3/14/2026
1.1.5 138 2/16/2026
1.1.3 1,096 7/23/2025
1.1.2 249 7/16/2025
1.1.1 222 7/8/2025
1.1.0 220 7/7/2025
1.0.9 218 7/7/2025
1.0.8 179 7/5/2025
1.0.7 453 4/10/2025
1.0.6 238 4/10/2025
1.0.4 1,574 9/2/2024
1.0.3 200 8/30/2024
1.0.2 192 8/30/2024
1.0.1 186 8/30/2024
1.0.0 212 8/30/2024