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

// Install FeatureSlice as a Cake Tool
#tool nuget:?package=FeatureSlice&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 (1)

Showing the top 1 NuGet packages that depend on FeatureSlice:

Package Downloads
FeatureSlice.FluentServiceBus

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.7 41 8/1/2024
1.0.6 71 7/30/2024
1.0.5 71 7/30/2024
1.0.4 74 7/22/2024
1.0.3 104 4/6/2024
1.0.2 98 3/6/2024
1.0.1 110 2/23/2024
1.0.0 143 2/14/2024