# Pipeline & Behaviors

Miru uses MediatR for the Pipeline and Behaviors.

Consider this code when a Feature is sent to the Mediator:

public class AccountLogin 
{
    public class Command : IRequest<Result>
    {
        public string Email { get; set; }
        public string Password { get; set; }  
    }

    public class Handler : IRequestHandler<Command, Result>
    {
        public async Task<Result> Handle(Command command, CancellationToken ct)
        {
            return new Result();
        }
    }

    public class AccountsController : MiruController
    {
        [HttpPost]
        public async Task<Result> Login(Command command) => await SendAsync(command);
    }
}

When await SendAsync(command) is called, the object AccountLogin.Command will pass through a chain of responsability. It means that AccountLogin.Command will pass through a chain of Behaviors, for example Logging, Database Transaction, Authorization, Validation, etc.

# Pipeline

The Pipeline is the chain of Behaviors. It is configured in /src/{AppName}/Startup.cs:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMiru<Startup>()
            // pipeline
            .AddDefaultPipeline<Startup>()
    }
}

The .AddDefaultPipeline() adds these behaviors:

services.AddPipeline<TAssemblyOfType>(_ =>
{
    _.UseBehavior(typeof(LogBehavior<,>));
    _.UseBehavior(typeof(DumpRequestBehavior<,>));
    _.UseBehavior(typeof(SetUserBehavior<,>));
    _.UseBehavior(typeof(TransactionBehavior<,>));
    _.UseBehavior(typeof(AuthorizationBehavior<,>));
    _.UseBehavior(typeof(ValidationBehavior<,>));
});

LogBehavior will be called first, then DumpRequestBehavior until call all of them ending in ValidationBehavior. After that, the Feature Handler is called.

It's possible to customize the Pipeline by replacing AddDefaultPipeline with your own chain of behaviors:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMiru<Startup>()
            // pipeline
            .AddPipeline<Startup>(_ =>
            {
                _.UseBehavior(typeof(YourBehavior<,>));
                _.UseBehavior(typeof(LogBehavior<,>));
                _.UseBehavior(typeof(YourOtherBehavior<,>));
                _.UseBehavior(typeof(TransactionBehavior<,>));
                _.UseBehavior(typeof(AuthorizationBehavior<,>));
                _.UseBehavior(typeof(ValidationBehavior<,>));
            });
    }
}

# Behaviors

Behavior is a class that can perform some task before and after the next behavior is called.

This is the structure of a Behavior:

public class ExampleBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
    public async Task<TResponse> Handle(
        TRequest request, 
        CancellationToken cancellationToken, 
        RequestHandlerDelegate<TResponse> next)
    {
        // call the next behavior in the pipeline
        var response = await next();

        // return response to the behavior that called this ExampleBehavior
        return response;
    }
}

For example, this is the DumpRequestBehavior from Miru:

public class DumpRequestBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
    public async Task<TResponse> Handle(
        TRequest request, 
        CancellationToken cancellationToken, 
        RequestHandlerDelegate<TResponse> next)
    {
        request.LogIt();
        var response = await next();
        return response;
    }
}