FeatureSlice.FluentServiceBus 1.0.4

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package FeatureSlice.FluentServiceBus --version 1.0.4                
NuGet\Install-Package FeatureSlice.FluentServiceBus -Version 1.0.4                
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="FeatureSlice.FluentServiceBus" Version="1.0.4" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add FeatureSlice.FluentServiceBus --version 1.0.4                
#r "nuget: FeatureSlice.FluentServiceBus, 1.0.4"                
#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 FeatureSlice.FluentServiceBus as a Cake Addin
#addin nuget:?package=FeatureSlice.FluentServiceBus&version=1.0.4

// Install FeatureSlice.FluentServiceBus as a Cake Tool
#tool nuget:?package=FeatureSlice.FluentServiceBus&version=1.0.4                

FeatureSlice

Release Status NuGet Version NuGet Downloads

FeatureSlice is an library aiming to help working with Vertical/Feature Slice Architecture.

FeatureSlices can be Handlers or Consumers, and have an Endpoint and/or FeatureToggle.

  • Handlers are a InMemory Request handlers which produce an Response.
  • Consumers are Message Consumers which take an Request and produce only Success or Error Result, they can be setup to use for example Azure ServiceBus to send Requests.
  • Both of those can also be set to be reachable from API as Endpoints and/or have a FeatureToggle.

Those elements can be setup using two types of API:

FluentGenericBuilder

Endpoint
public sealed class ExampleEndpoint : FeatureSliceBuilder
    .WithEndpoint
    .Build<ExampleEndpoint>
{
    protected override Endpoint Endpoint => Map.Get("test", (int age) => 
    {
        return Results.Ok();
    });
}
Handler
public sealed class ExampleHandler : FeatureSliceBuilder
    .WithHandler<ExampleHandler.Request, ExampleHandler.Response, FromServices<Dependency1, Dependency2>>
    .Build<ExampleHandler>
{
    public record Request();
    public record Response();

    protected override async Task<Result<Response>> Handle(Request request, FromServices<Dependency1, Dependency2> dependencies)
    {
        var (dep1, dep2) = dependencies;

        await Task.CompletedTask;

        return new Response();
    }
}
Consumer
public sealed class ExampleConsumer : FeatureSliceBuilder
    .WithConsumer<ExampleConsumer.Request, FromServices<Dependency1, Dependency2>>
    .Build<ExampleConsumer>
{
    public record Request();

    protected override ConsumerName ConsumerName => new("ExampleConsumer");

    protected override Task<Result> Consume(Request request, FromServices<Dependency1, Dependency2> dependencies)
    {
        var (dep1, dep2) = dependencies;

        return Result.Success;
    }
}
Combination of Consumer with Endpoint, Handler with Endpoint and both with FeatureFlag
public sealed class ExampleConsumerWithEndpoint : FeatureSliceBuilder
    .WithFlag
    .WithEndpoint
    .WithConsumer<ExampleConsumerWithEndpoint.Request, FromServices<Dependency1, Dependency2>>
    .Build<ExampleConsumerWithEndpoint>
{
    public record Request();

    protected override ConsumerName ConsumerName => new("ExampleConsumerWithEndpoint");

    protected override Endpoint Endpoint => Map.Get("test", (int age) => 
    {
        return Results.Ok();
    });

    protected override Task<Result> Consume(Request request, FromServices<Dependency1, Dependency2> dependencies)
    {
        var (dep1, dep2) = dependencies;

        return Result.Success;
    }
}
Handlers and Consumers Expose Dispatch methods which allow them to be called from dependencies
public static void Use(
    IPublisher publisher,
    ExampleConsumer.Dispatch consumer,
    ExampleHandler.Dispatch handler,
    ExampleConsumerWithEndpoint.Dispatch consumerWithEndpoint)
{
    publisher.Dispatch(new ExampleConsumer.Request());
    consumer(new ExampleConsumer.Request());
    handler(new ExampleHandler.Request());
    consumerWithEndpoint(new ExampleConsumerWithEndpoint.Request());
}
Handlers and Consumers Expose Register for DI registration
public static void Register(IServiceCollection services, Messaging.ISetup setup, WebAppExtender hostExtender)
{
    ExampleEndpoint.Register(services, hostExtender);
    ExampleConsumer.Register(services, setup);
    ExampleHandler.Register(services, hostExtender);
    ExampleConsumerWithEndpoint.Register(services, setup, hostExtender);
}

Functional which needs more manual setup

Endpoint
public static class ExampleEndpoint
{
    public static void Register(IServiceCollection services, IHostExtender<WebApplication> extender)
    {
        services.FeatureSlice()
            .WithEndpoint(
                extender,
                Endpoint);
    }

    private static Endpoint Endpoint => Map.Get("test", (int age) => 
    {
        return Results.Ok();
    });
}
Handler
public sealed class ExampleHandler : Dispatchable<ExampleHandler, ExampleHandler.Request, Result<ExampleHandler.Response, Disabled>>
{
    public record Request();
    public record Response();

    public static void Register(IServiceCollection services, IHostExtender<WebApplication> extender)
    {
        services.FeatureSlice()
            .WithHandler<Dispatch, Request, Response, FromServices<Dependency1, Dependency2>>(
                Handle,
                handler => handler.Invoke);
    }

    private static async Task<Result<Response>> Handle(Request request, FromServices<Dependency1, Dependency2> dependencies)
    {
        var (dep1, dep2) = dependencies;

        await Task.CompletedTask;

        return new Response();
    }
}
Consumer
public static class ExampleConsumer
{
    public delegate Task<Result> Dispatch(Request request);

    public record Request();

    public static void Register(IServiceCollection services, Messaging.ISetup setup)
    {
        services.FeatureSlice()
            .WithConsumer<Dispatch, Request, FromServices<Dependency1, Dependency2>>(
                setup,
                new ("ExampleConsumer"),
                Consume,
                handler => handler.Invoke);
    }

    private static async Task<Result> Consume(Request request, FromServices<Dependency1, Dependency2> dependencies)
    {
        var (dep1, dep2) = dependencies;

        await Task.CompletedTask;

        return Result.Success;
    }
}
Combination of Consumer with Endpoint, Handler with Endpoint and both with FeatureFlag
public static class ExampleConsumerWithEndpoint
{
    public delegate Task<Result.Or<Disabled>> Dispatch(Request request);

    public record Request();

    public static void Register(IServiceCollection services, Messaging.ISetup setup, IHostExtender<WebApplication> extender)
    {
        services.FeatureSlice()
            .WithFlag("ExampleConsumerWithEndpoint")
            .WithEndpoint(
                extender,
                Endpoint)
            .WithConsumer<Dispatch, Request, FromServices<Dependency1, Dependency2>>(
                setup,
                new ("ExampleConsumerWithEndpoint"),
                Consume,
                handler => handler.Invoke);
    }

    private static Endpoint Endpoint => Map.Get("test", (int age) => 
    {
        return Results.Ok();
    });

    private static async Task<Result> Consume(Request request, FromServices<Dependency1, Dependency2> dependencies)
    {
        var (dep1, dep2) = dependencies;

        await Task.CompletedTask;

        return Result.Success;
    }
}
Handlers and Consumers need to have manually added Dispatch methods which allow them to be called from dependencies
public static void Use(
    IPublisher publisher,
    ExampleConsumer.Dispatch consumer,
    ExampleHandler.Dispatch handler,
    ExampleConsumerWithEndpoint.Dispatch consumerWithEndpoint)
{
    publisher.Dispatch(new ExampleConsumer.Request());
    consumer(new ExampleConsumer.Request());
    handler(new ExampleHandler.Request());
    consumerWithEndpoint(new ExampleConsumerWithEndpoint.Request());
}
Handlers and Consumers need to have manually added Register for DI registration
public static void Register(IServiceCollection services, Messaging.ISetup setup, WebAppExtender hostExtender)
{
    ExampleEndpoint.Register(services, hostExtender);
    ExampleConsumer.Register(services, setup);
    ExampleHandler.Register(services, hostExtender);
    ExampleConsumerWithEndpoint.Register(services, setup, hostExtender);
}

Samples

src/Samples

License

The code in this repo is licensed under the MIT license.

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
1.0.7 70 8/1/2024
1.0.6 77 7/30/2024
1.0.5 77 7/30/2024
1.0.4 87 7/22/2024
1.0.3 123 4/6/2024
1.0.2 123 3/6/2024
1.0.1 113 2/23/2024