Skip to content
sano-suguruPublic

About

Feature files for ASP.NET Core Minimal APIs with generated registrations, clients, and portability checks.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

505 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SliceFx

日本語

CI Perf (nightly) Pages .NET License: MIT NuGet

One feature file per endpoint. Generated ASP.NET Core registration, checks, clients, and portability hints.

Website: https://sano-suguru.github.io/slicefx/

SliceFx is an experimental .NET framework built on ASP.NET Core Minimal APIs. A feature is one file: request, response, handler, validation, and filters together. A source generator turns it into standard Minimal API registrations, a route manifest, and typed clients, so nothing needs hand-syncing.

[Feature("POST /users", Summary = "Create a new user")]
public static class CreateUser
{
    public record Request([Required, MinLength(2)] string Name, [Required, EmailAddress] string Email);
    public record Response(Guid Id, string Name, string Email, DateTime CreatedAt);

    public static async Task<Response> Handle(Request req, IUserStore store, CancellationToken ct)
    {
        var user = await store.AddAsync(req.Name, req.Email, ct);
        return new Response(user.Id, user.Name, user.Email, user.CreatedAt);
    }
}

This is the whole feature: route, validation, and handler. The generated AddSlice() / MapSlices() calls wire it up.

Curious about the design choices? See Design decisions FAQ and Production readiness criteria.

Why use SliceFx?

Need SliceFx provides
Endpoint code that is easy to review One feature file per endpoint: request, response, handler, validation, and filters stay together.
Less hand-synced API glue AddSlice() / MapSlices(), route metadata, and typed clients are generated from the same feature definitions.
Standard ASP.NET Core behavior Minimal API binding, DI, endpoint filters, DataAnnotations, OpenAPI compatibility, and IResult remain available.
Native AOT-friendly startup Generated MapMethods calls avoid startup route scanning; SliceFx.Core has no PackageReference entries and only uses the Microsoft.AspNetCore.App framework reference. Add [assembly: SliceAspNetAot] to switch to reflection-free generated dispatch and publish a native binary with zero IL2026/IL3050 diagnostics.
Early portability feedback slicefx routes classifies each endpoint as portable, partial, or aspnet-only; Lambda and wasi:http adapters are optional.
Low lock-in Generated code compiles down to standard MapMethods calls. Remove the source generator reference and expand the output in place for a low-residue exit path.

What SliceFx is not: a replacement for ASP.NET Core, or a mediator/pipeline framework like MediatR. Auth, rate limiting, CORS, and IEndpointFilter all still work as-is (see What you keep). SliceFx is a generated layer around Minimal APIs that compiles down to plain WebApplication.MapMethods calls, so dropping the source generator reference leaves the generated code working as your exit path. You don't need to rewrite anything: add it to one endpoint in an existing app and keep the rest on controllers or handwritten Minimal APIs (migrating from Minimal APIs, migrating from controllers).

Latest benchmark results

Latest source generator benchmark results

dotnet run --project samples/SliceFx.Sample
curl http://localhost:5099/health

Project status

SliceFx is pre-1.0 experimental software. Preview packages use 0.x versions until the API is intentionally stabilized. A subset of SliceFx.Core — [Feature], [Filter<T>], ISliceValidator<T>, SliceValidationResult, SliceResult<T>/SliceResult — already carries an explicit stability commitment; see docs/api-stability-policy.md for scope and terms.

The latest preview is published on NuGet — see the NuGet badge above. Install from NuGet:

dotnet add package SliceFx.Core --prerelease
dotnet add package SliceFx.SourceGenerator --prerelease

See the package table for satellite packages. NuGet package pages: SliceFx.Core, SliceFx.SourceGenerator, SliceFx.Cli.

SDK and analyzer policy: the repository targets .NET 10 with SDK 10.0.300 pinned in global.json and rollForward: latestFeature. Warnings and code-analysis diagnostics are treated as errors, but the analyzer recommendation set is pinned to 10.0-recommended so normal PR/main builds do not unexpectedly break when a newer SDK promotes analyzer rules. A separate analyzer canary workflow checks the latest .NET 10 analyzer behavior and reports drift for dedicated maintenance PRs.

WASI support (SliceFx.Wasi) is experimental and depends on an unstable upstream toolchain: componentize-dotnet, NativeAOT-LLVM preview packages, WASI Preview 2 / wasi:http@0.2, and Cloudflare's JS transpile/shim path when targeting Workers. Native WASI publish requires Linux x64 or Windows x64; macOS requires a Linux x64 Docker cross-build. "Experimental" means SliceFx.Wasi's own 0.x API may change; "unstable upstream toolchain" means those external build and deployment tools may break independently of SliceFx runtime code.

All adapters are opt-in. Reference only the packages you need; the source generator emits code only for the surfaces you reference. An ASP.NET-only app uses just SliceFx.Core and SliceFx.SourceGenerator.

Package Purpose
SliceFx.Core Core runtime: [Feature], [Filter<T>], validation, and endpoint filters.
SliceFx.SourceGenerator AOT-friendly generated registrations and route metadata.
SliceFx.Lambda ASP.NET-hosted AWS Lambda adapter.
SliceFx.Lambda.FunctionPerFeature Experimental HTTP API v2 function-per-feature Lambda handlers.
SliceFx.TestHost In-process test host helpers.
SliceFx.Wasi ASP.NET-independent wasi:http dispatch.
SliceFx.Wasi.KeyValue IKeyValueStore abstraction and in-memory test double for WASI features.
SliceFx.Wasi.HttpClient IWasiHttpClient abstraction and in-memory test double for outgoing HTTP in WASI features.
SliceFx.Wasi.Spin ISpinCronHandler abstraction, SpinCronDispatcher, and recording test double for Spin cron trigger integration in WASI features.
SliceFx.Cli Scaffolding, route inspection, AWS SAM manifest/package helpers, and typed client generation.

Add SliceFx.Core and SliceFx.SourceGenerator at the same preview version:

dotnet add package SliceFx.Core --prerelease
dotnet add package SliceFx.SourceGenerator --prerelease

Hello, SliceFx

Program.cs:

var builder = WebApplication.CreateSlimBuilder(args);

builder.Services.AddSlice();
builder.Services.AddSingleton<IUserStore, InMemoryUserStore>();

var app = builder.Build();

app.MapSlices();
app.Run();

Features/Users/CreateUser.cs:

namespace SliceFx.Sample.Features.Users;

[Feature("POST /users", Summary = "Create a new user")]
public static class CreateUser
{
    public record Request(
        [Required, MinLength(2)] string Name,
        [Required, EmailAddress] string Email);

    public record Response(Guid Id, string Name, string Email, DateTime CreatedAt);

    public static async Task<Response> Handle(Request req, IUserStore store, CancellationToken ct)
    {
        var user = await store.AddAsync(req.Name, req.Email, ct);
        return new Response(user.Id, user.Name, user.Email, user.CreatedAt);
    }
}

The generator discovers [Feature] classes, emits AddSlice() / MapSlices(), wires Minimal API binding, and attaches validation. Prefer plain response records for portable endpoints. Use IResult when the feature intentionally needs ASP.NET-specific response helpers such as Results.NotFound() or Results.NoContent().

DI binding note: On the ASP.NET path binding is plain Minimal API — any registered service (concrete or interface) resolves from DI automatically, identical to raw Minimal API. Annotate concrete service params with [FromServices] (keyed services with [FromKeyedServices(key)]) only if you want the handler portable across ASP.NET, WASI, and Lambda — the portable-dispatch generator cannot probe the DI container at compile time. See docs/guides/parameter-binding.md and samples/SliceFx.Sample/Features/Users/PromoteUser.cs.

Filters and validation

Feature filters are standard ASP.NET Core IEndpointFilter types:

[Feature("DELETE /users/{id:guid}", Summary = "Delete a user")]
[Filter<RequestLoggingFilter>]
[Filter<RequireApiKeyFilter>]
public static class DeleteUser
{
    public static async Task<IResult> Handle(Guid id, IUserStore store, CancellationToken ct)
    {
        var user = await store.GetAsync(id, ct);
        if (user is null) return Results.NotFound();
        await store.RemoveAsync(id, ct);
        return Results.NoContent();
    }
}

AddSlice() registers referenced filters and matching validators as scoped services, and [Filter<T>] applies filters in declaration order. Supported DataAnnotations rules are generated and run first; closed ISliceValidator<TRequest> implementations are discovered when TRequest is a Slice request parameter and run automatically before feature filters for rules that need code. A request type can have one Slice validator; orphan validators fail the build so validation is never skipped silently.

For production authorization policies, prefer ASP.NET Core Authorization. Slice filters are best for explicit per-feature endpoint filter behavior.

Read more:

What you keep

SliceFx generated code is pure Minimal API expansion — the full ASP.NET surface stays available.

Features you keep on every endpoint:

  • ASP.NET Core Authorization — [Authorize], policies, fallback policy, RequireAuthorization()
  • Output caching — CacheOutput() via route group
  • Rate limiting — RequireRateLimiting() via route group
  • CORS — RequireCors() via route group
  • Exception handling middleware and IProblemDetailsService
  • [Filter<T>] endpoint filters with full IEndpointFilter access
  • OpenAPI integration — builder.Services.AddOpenApi() / app.MapOpenApi()
  • Standard Minimal API binding — [FromRoute], [FromQuery], [FromHeader], [FromForm], [FromServices], [FromKeyedServices]

Escape hatches for common needs:

Need Default path Escape hatch
Validation DataAnnotations attributes on the request record Implement ISliceValidator<T> for the request type
Authorization ASP.NET Core Authorization ([Authorize], policies) Group-level RequireAuthorization(...) or fallback policy
Rate limiting / caching / CORS Route group: app.MapGroup("/api").RequireRateLimiting(...).MapSlices() Per-group or per-endpoint policy
Cross-cutting behavior [Filter<T>] endpoint filter Standard ASP.NET Core middleware

For more detail see ASP.NET features and escape hatches.

What works today

Feature Status
[Feature("METHOD /path")] declarative routing Implemented
Source-generated AddSlice() / MapSlices() Implemented
Static handlers with body / route / query / DI / CancellationToken binding Implemented
Source-generated DataAnnotations validation for supported property/positional-record attributes Implemented
ISliceValidator<T> custom validation Implemented
[Filter<T>] endpoint filters Implemented
Route metadata manifest Experimental
slicefx routes portability classification Experimental
slicefx client csharp typed client generation Experimental
slicefx client typescript typed fetch client generation Experimental
AWS SAM manifest generation Experimental
ASP.NET-hosted Lambda adapter Experimental
Function-per-feature Lambda handlers Experimental HTTP API v2 NativeAOT binary-per-feature packaging
TestHost helper Experimental
WASI adapter Experimental single-component in-process wasi:http dispatch; per-feature WASM packaging is not implemented
SliceResult<T> / SliceResult typed WASI results Implemented — host-neutral result structs in SliceFx.Core; source generator + CLI client generator unwrap to the payload type
Plain NativeAOT ASP.NET host Experimental — [assembly: SliceAspNetAot] opts into generated AOT-safe dispatch; linux-x64 publish + smoke test CI-gated

The C# typed client reuses C# request/response types rather than generating DTO copies. Use nested feature DTOs when the client can reference the feature assembly; use non-nested DTOs in a shared contracts project when Blazor or another .NET client should reference contracts without referencing server features. The TypeScript client emits interfaces from built metadata. Routes returning SliceResult<T> generate Task<T> methods; routes returning the non-generic SliceResult generate Task (void) methods.

Adoption evidence

Maintainer dogfooding is live: slicefx-inbox has been running on Fermyon Cloud (Spin WASI, wasi:http/incoming-handler) since preview.5. All 11 handlers return SliceResult<T> / SliceResult (preview.7+), with SliceApiClient.g.cs fully generated.

Portability

Most projects use all three portability classes in the same codebase — the classification tells tooling where a feature can run, not whether it is well-written.

The source generator classifies each feature endpoint at build time. slicefx routes reports the result; the same data drives typed-client generation, WASI route tables, and Lambda function-per-feature eligibility.

Class Meaning
portable Returns a plain record or void. Eligible for typed-client generation, WASI dispatch, and function-per-feature Lambda.
partial Portable handler shape, but attached endpoint filters are ASP.NET-only today.
aspnet-only Returns IResult or uses ASP.NET-specific behavior. The full Minimal API feature set is available.

aspnet-only features are standard Minimal API endpoints with the complete ASP.NET ecosystem available — they are not penalized or degraded.

Native AOT — optional, first-class

Add [assembly: SliceAspNetAot] to any assembly to switch from the default RequestDelegateFactory registration path to generated AOT-safe handlers. The generator emits new RequestDelegate(…) methods that bind parameters, run validation, and serialize responses using JsonTypeInfo<T> — no per-request reflection. Publishing with PublishAot=true and TreatWarningsAsErrors=true then fails on any residual IL2026/IL3050 diagnostic.

// AotSetup.cs
[assembly: SliceAspNetAot]
// AotJsonContext.cs — covers every request/response type the generator will serialize
[SliceJsonContext(SliceJsonTarget.AspNet)]
[JsonSerializable(typeof(CreateTodo.Request))]
[JsonSerializable(typeof(Todo))]
internal sealed partial class AotJsonContext : JsonSerializerContext { }

The default non-AOT path is unchanged for assemblies that do not carry the attribute, preserving full backwards compatibility. See docs/aot.md and the AotSample README.

WASI and edge are optional

You do not need WASI or edge hosting to use SliceFx. The default path is still a normal ASP.NET Core app.

Edge usually means running code closer to users on platforms such as Cloudflare Workers or Fermyon Spin instead of only in one central server region. WASI is a standards-based way to package server-side code as a WebAssembly component that those hosts can run. In SliceFx, WASI support proves the portability story: if a feature returns plain request/response records and avoids ASP.NET-only response helpers, the same feature shape can be dispatched outside ASP.NET through a generated route table and SliceFx.Wasi.

That path is intentionally experimental. SliceFx.Wasi depends on preview tooling, has stricter JSON and validation rules, and does not run arbitrary ASP.NET endpoint filters. The practical deployment target today is one wasi:http component with generated in-process route dispatch, not one WASM component per feature. The practical benefit today is visibility: slicefx routes tells you which endpoints are portable, which are partially portable, and which intentionally stay ASP.NET-only.

OpenAPI

Slice endpoints work with ASP.NET Core's standard OpenAPI support out of the box. Add Microsoft.AspNetCore.OpenApi, call builder.Services.AddOpenApi(), and map app.MapOpenApi() in the ASP.NET host:

builder.Services.AddSlice();
builder.Services.AddOpenApi();

var app = builder.Build();
app.MapSlices();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

The Slice route manifest is a separate build-time artifact for portability classification, client generation, and slicefx openapi manifest projections. It complements rather than replaces the ASP.NET Core OpenAPI document. See docs/guides/openapi.md.

Tooling and adapters

Topic Details
Source generator and route manifest docs/source-generator.md
CLI commands docs/cli.md
Blazor WASM + generated typed client sample samples/SliceFx.BlazorSample/
OpenAPI integration docs/guides/openapi.md
Native AOT deployment docs/aot.md
Native AOT sample samples/SliceFx.AotSample/README.md
Lambda hosting and function-per-feature Lambda docs/lambda.md
Lambda function-per-feature sample samples/SliceFx.LambdaFunctionPerFeatureSample/
WASI deploy path samples/SliceFx.WasiSample/README.md
Migration guides Minimal API, controllers
Platform abstraction and DI swap patterns docs/patterns/platform-abstraction.md
ASP.NET features and escape hatches docs/guides/aspnet-features.md
Design decisions FAQ docs/design-decisions.md
Product direction docs/product-direction.md
Production readiness docs/production-readiness.md

Build & run

dotnet build
dotnet run --project samples/SliceFx.Sample

Then:

curl http://localhost:5099/health
curl -X POST http://localhost:5099/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice","email":"alice@example.com"}'
curl -X DELETE http://localhost:5099/users/{id} -H "X-API-Key: secret"

License

MIT. See LICENSE.

About

Feature files for ASP.NET Core Minimal APIs with generated registrations, clients, and portability checks.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages