Mediatr.Patterns.Builder 8.0.0

dotnet add package Mediatr.Patterns.Builder --version 8.0.0
NuGet\Install-Package Mediatr.Patterns.Builder -Version 8.0.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="Mediatr.Patterns.Builder" Version="8.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Mediatr.Patterns.Builder --version 8.0.0
#r "nuget: Mediatr.Patterns.Builder, 8.0.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.
// Install Mediatr.Patterns.Builder as a Cake Addin
#addin nuget:?package=Mediatr.Patterns.Builder&version=8.0.0

// Install Mediatr.Patterns.Builder as a Cake Tool
#tool nuget:?package=Mediatr.Patterns.Builder&version=8.0.0

MediatR.Patterns.Builder

MediatR.Patterns.Builder Sits on top of MediatR and exposes PreProcess, Process and PostProcess methods to handlers instead of only exposing the Handle method allowing to implement handlers using the builder pattern.

It simplifies common usage of Mediatr integrating interfaces to differentiate between commands and queries and also automatically creating a behavior pipeline to apply FluentValidation checks.

It is as fast as the vanilla version and helps reduce the development process by having a defined pattern within handlers.


Usage

Handlers

Inherit from the abstract class BuilderRequestHandler setting what the request and the response are.

In below example, if the cache has a value, it returns from the PreProcess method directly without going to the Process method but if not (and returns null) the Process method and then PostProcess method will execute in sequence.


public class GetAllCountriesHandler : BuilderRequestHandler<GetAllCountries, List<CountryData>>
{
    private readonly ILogger<GetAllCountriesHandler> _logger;
    private readonly ICache _cache;
    private readonly IRepository _repository;

    public GetAllCountriesHandler(ICache cache, ILogger<GetAllCountriesHandler> logger, IRepository repository)
    {
        _logger = logger;
        _cache = cache;
        _repository = repository;
    }

    protected override async Task<List<CountryData>> PreProcess(GetAllCountries request, CancellationToken cancellationToken = default)
    {
        var cacheKey = GetCacheKey();

        var cachedValue = await _cache.GetCacheValueAsync<List<CountryData>>(cacheKey, cancellationToken);
        if (cachedValue == null) return null;
        
        _logger.LogInformation("Cache value found for {CacheKey}", cacheKey);
        return cachedValue;
    }
    
    protected override async Task<List<CountryData>> Process(GetAllCountries request, CancellationToken cancellationToken = default)
    {
        return await GetAllCountries();
    }

    protected override Task PostProcess(GetAllCountries request, List<CountryData> response, CancellationToken cancellationToken = default)
    {
        if (response != null)
        {
            _ = _cache.SetCacheValueAsync(GetCacheKey(), response, cancellationToken);
        }

        return Task.CompletedTask;
    }
}

Differentiate between Query and Command
  • For queries instead of using IRequest use IQuery
  • For commands instead of using IRequest use ICommand

By doing this can further expand your pipeline behaviors and act according to the type of request.


public class GetAllCountries : IQuery<List<CountryData>>
{
    ... some properties
}

public class AddCountry : ICommand<List<CountryData>>
{
    ... some properties
}

Setting FluentValidation

Just create the validations related to the request you will be handling like you normally do:


public class GetAllCountries : IQuery<List<CountryData>>
{
    ... some properties
}

public class GetAllCitiesValidator : AbstractValidator<GetAllCountries>
{
    public GetAllCitiesValidator()
    {
        RuleFor(x => x).NotNull();
        
        ... more fluentValidation rules
    }
}

Configuration

Dependency Injection

Just as Mediatr, you can pass the assemblies to scan for handlers and those assemblies can be also used by FluentValidation if AddFluentValidation is set to true so it internally creates a pipeline behavior to validate before going to the handler.

services.AddMediatrBuilder(options =>
{
    options.RegisterServicesFromAssemblies(Assembly.GetExecutingAssembly(), ... more assemblies)
    options.AddFluentValidation(true);
});

Contributing

It is simple, as all things should be:

  1. Clone it
  2. Improve it
  3. Make pull request

Credits

  • Initial development by Slukad
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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. 
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
8.0.0 218 11/20/2023
7.0.1 155 5/19/2023

Release