Skip to content

Latest commit

 

History

History
128 lines (94 loc) · 3.52 KB

quick_start.md

File metadata and controls

128 lines (94 loc) · 3.52 KB

🚀 Quick Start

In this section of the documentation, you'll learn how to build first Pipeline.


1️⃣ Define your own types

1.1 Input

The "Input" acts as the initial parameter for Handler and Dispatcher methods, guiding the search for the relevant Handler.

public interface IInput<TResult> where TResult: class{ } 

1.2 Handler

Handlers house the application logic and can generate both synchronous and asynchronous results.

public interface IHandler<in TInput, TResult> where TInput : IInput<TResult> where TResult: class
{
    public Task<TResult> HandleAsync(TInput input, CancellationToken token);
}

1.3 Dispatcher

Serving as a bridge between inputs and their respective handlers, the Dispatcher ensures the appropriate Handler is triggered for a given Input.

public interface IDispatcher
{
    public Task<TResult> SendAsync<TResult>(IInput<TResult> input, CancellationToken token) where TResult : class;
}

2️⃣ Implement first decorator (optional step)

Analogous to Middlewares in .NET. Think of them as layers of logic that execute before or after the handler.

public class LoggingDecorator<TInput, TResult> : IHandler<TInput, TResult> where TInput : IInput<TResult> where TResult : class
{
    private readonly IHandler<TInput, TResult> _handler;
    private readonly ILogger _logger;
    
    public LoggingDecorator(IHandler<TInput, TResult> handler, ILogger logger)
    {
        _handler = handler;
        _logger = logger;
    }

    public async Task<TResult> HandleAsync(TInput request, CancellationToken token)
    {
        _logger.Log(LogLevel.Information,"Executing handler for input {0}", typeof(TInput));
        var result = await _handler.HandleAsync(request, token);
        _logger.Log(LogLevel.Information,"Executed handler for input {0}", typeof(TInput));

        return result;
    }
}

3️⃣ Register pipeline

In your application's initialization, such as Startup.cs:

IMPORTANT! All provided types must be specified using the typeof() method!

var handlersAssembly = //Assembly where handlers assembly are implemented
var dispatcherAssembly = //Assembly where AddPipeline gets invoked

_services
    .AddPipeline()
        .AddInput(typeof(IInput<>))
        .AddHandler(typeof(IHandler<,>), handlersAssembly)
        .AddDispatcher<IDispatcher>(dispatcherAssembly)
        .WithDecorator(typeof(LoggingDecorator<,>))
        .Build();

4️⃣ Implement first handler

4.1 Input and Result

public record ExampleInput(string Value) : IInput<ExampleCommandResult>;
public record ExampleCommandResult(string Value);

4.2 Handler

public class ExampleHandler : IHandler<ExampleInput, ExampleCommandResult>
{
    public Task<ExampleCommandResult> HandleAsync(ExampleInput input, CancellationToken token)
    {
        return Task.FromResult(new ExampleCommandResult(input.Value));
    }
}

5️⃣ Example Usage (Fluent API .NET)

public static void CreateExampleEndpoint(this WebApplication app)
    {
        app.MapPost("/example", async (ExampleInput request, IDispatcher dispatcher, CancellationToken token) =>
        {
            var result = await dispatcher.SendAsync(input,token);
            return Results.Ok();
        });
    }

6️⃣ Next steps

Advanced examples: