{"id":50457370,"url":"https://github.com/sano-suguru/slicefx","last_synced_at":"2026-06-01T03:04:54.505Z","repository":{"id":359262984,"uuid":"1244757100","full_name":"sano-suguru/slicefx","owner":"sano-suguru","description":"Feature files for ASP.NET Core Minimal APIs with generated registrations, clients, and portability checks.","archived":false,"fork":false,"pushed_at":"2026-05-26T03:19:00.000Z","size":1592,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T03:21:45.508Z","etag":null,"topics":["aot","aspnet-core","dotnet","minimal-api","native-aot","serverless","source-generator","vertical-slice-architecture","wasi"],"latest_commit_sha":null,"homepage":"https://sano-suguru.github.io/slicefx/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sano-suguru.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-20T15:09:06.000Z","updated_at":"2026-05-26T03:19:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sano-suguru/slicefx","commit_stats":null,"previous_names":["sano-suguru/slice","sano-suguru/slicefx"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/sano-suguru/slicefx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sano-suguru%2Fslicefx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sano-suguru%2Fslicefx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sano-suguru%2Fslicefx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sano-suguru%2Fslicefx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sano-suguru","download_url":"https://codeload.github.com/sano-suguru/slicefx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sano-suguru%2Fslicefx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33634615,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aot","aspnet-core","dotnet","minimal-api","native-aot","serverless","source-generator","vertical-slice-architecture","wasi"],"created_at":"2026-06-01T03:04:42.138Z","updated_at":"2026-06-01T03:04:54.499Z","avatar_url":"https://github.com/sano-suguru.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SliceFx\n\n[![CI](https://github.com/sano-suguru/slicefx/actions/workflows/ci.yml/badge.svg)](https://github.com/sano-suguru/slicefx/actions/workflows/ci.yml)\n[![Perf (nightly)](https://github.com/sano-suguru/slicefx/actions/workflows/perf.yml/badge.svg)](https://github.com/sano-suguru/slicefx/actions/workflows/perf.yml)\n[![Pages](https://github.com/sano-suguru/slicefx/actions/workflows/pages.yml/badge.svg)](https://github.com/sano-suguru/slicefx/actions/workflows/pages.yml)\n[![.NET](https://img.shields.io/badge/.NET-10.0-512BD4?logo=dotnet)](https://dotnet.microsoft.com/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\n\u003e One feature file per endpoint. Generated ASP.NET Core registration, checks, clients, and portability hints.\n\nWebsite: \u003chttps://sano-suguru.github.io/slicefx/\u003e\n\n**SliceFx** is an experimental .NET framework for teams that like ASP.NET Core Minimal APIs but do not want route strings, DTOs, validation, filters, clients, and deployment checks to drift apart. A feature is one static class with its request, response, handler, validation, and filters in one place. The generator emits standard Minimal API registrations plus a route manifest for tooling, AOT-friendly startup, Lambda experiments, and WASI/WebAssembly dispatch.\n\nCurious about the design choices? See **[Design decisions FAQ](docs/design-decisions.md)** and **[Production readiness criteria](docs/production-readiness.md)**.\n\n## Why use SliceFx?\n\n| Need | SliceFx provides |\n| --- | --- |\n| Endpoint code that is easy to review | One feature file per endpoint: request, response, handler, validation, and filters stay together. |\n| Less hand-synced API glue | `AddSlice()` / `MapSlices()`, route metadata, and typed clients are generated from the same feature definitions. |\n| Standard ASP.NET Core behavior | Minimal API binding, DI, endpoint filters, DataAnnotations, OpenAPI compatibility, and `IResult` remain available. |\n| 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. |\n| Early portability feedback | `slicefx routes` classifies each endpoint as `portable`, `partial`, or `aspnet-only`; Lambda and wasi:http adapters are optional. |\n| 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. |\n\nSliceFx doesn't restrict any ASP.NET feature. For authorization, rate limiting, caching, CORS, and custom validation patterns see [What you keep](#what-you-keep).\n\nSliceFx is not a replacement for ASP.NET Core. It is a generated vertical-slice layer around Minimal APIs for teams that want explicit feature files, generated contracts, and portability checks without adopting a mediator stack or custom endpoint pipeline.\n\nSliceFx compiles down to standard `WebApplication.MapMethods` calls — removing the source generator reference and expanding the generated output in place is the full exit path. For teams already on FastEndpoints or similar, SliceFx fills a different niche: compile-time portability classification across ASP.NET, Lambda, and wasi:http, not a richer filter and pipeline ecosystem.\n\nExisting ASP.NET Core apps do not need a rewrite. Start with one endpoint, keep the rest of the app on controllers or handwritten Minimal APIs, and use the migration audit plus contract checks to evaluate the shape. See [migrating from Minimal APIs](docs/migrations/from-minimal-api.md) and [migrating from controllers](docs/migrations/from-controllers.md).\n\n### Latest benchmark results\n\n![Latest source generator benchmark results](https://raw.githubusercontent.com/sano-suguru/slicefx/main/docs/perf/latest.svg)\n\nEach endpoint is a static feature file: request, response, validation, filters, and handler stay together. The source generator turns those features into ASP.NET registrations, route metadata for tooling, Lambda handlers, or wasi:http dispatch where the handler shape is portable.\n\n```bash\ndotnet run --project samples/SliceFx.Sample\ncurl http://localhost:5099/health\n```\n\n## Project status\n\nSliceFx is pre-1.0 experimental software. Preview packages use `0.x` versions until the API is intentionally stabilized.\n\n**Release status:** `0.1.0-preview.8` is the latest preview release. Install from NuGet:\n\n```bash\ndotnet add package SliceFx.Core --version 0.1.0-preview.8\ndotnet add package SliceFx.SourceGenerator --version 0.1.0-preview.8\n```\n\nSee the [package table](#project-status) for satellite packages. NuGet package pages: [SliceFx.Core](https://www.nuget.org/packages/SliceFx.Core), [SliceFx.SourceGenerator](https://www.nuget.org/packages/SliceFx.SourceGenerator), [SliceFx.Cli](https://www.nuget.org/packages/SliceFx.Cli).\n\n**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.\n\nWASI support (`SliceFx.Wasi`) is experimental and depends on an unstable upstream toolchain: [componentize-dotnet](https://github.com/bytecodealliance/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.\n\nAll 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`.\n\n| Package | Purpose |\n| --- | --- |\n| `SliceFx.Core` | Core runtime: `[Feature]`, `[Filter\u003cT\u003e]`, validation, and endpoint filters. |\n| `SliceFx.SourceGenerator` | AOT-friendly generated registrations and route metadata. |\n| `SliceFx.Lambda` | ASP.NET-hosted AWS Lambda adapter. |\n| `SliceFx.Lambda.FunctionPerFeature` | Experimental HTTP API v2 function-per-feature Lambda handlers. |\n| `SliceFx.TestHost` | In-process test host helpers. |\n| `SliceFx.Wasi` | ASP.NET-independent wasi:http dispatch. |\n| `SliceFx.Wasi.KeyValue` | `IKeyValueStore` abstraction and in-memory test double for WASI features. |\n| `SliceFx.Wasi.HttpClient` | `IWasiHttpClient` abstraction and in-memory test double for outgoing HTTP in WASI features. |\n| `SliceFx.Wasi.Spin` | `ISpinCronHandler` abstraction, `SpinCronDispatcher`, and recording test double for Spin cron trigger integration in WASI features. |\n| `SliceFx.Cli` | Scaffolding, route inspection, AWS SAM manifest/package helpers, and typed client generation. |\n\nAdd `SliceFx.Core` and `SliceFx.SourceGenerator` at the same preview version:\n\n```bash\ndotnet add package SliceFx.Core --version 0.1.0-preview.8\ndotnet add package SliceFx.SourceGenerator --version 0.1.0-preview.8\n```\n\n## Hello, SliceFx\n\n`Program.cs`:\n\n```csharp\nvar builder = WebApplication.CreateSlimBuilder(args);\n\nbuilder.Services.AddSlice();\nbuilder.Services.AddSingleton\u003cIUserStore, InMemoryUserStore\u003e();\n\nvar app = builder.Build();\n\napp.MapSlices();\napp.Run();\n```\n\n`Features/Users/CreateUser.cs`:\n\n```csharp\nnamespace SliceFx.Sample.Features.Users;\n\n[Feature(\"POST /users\", Summary = \"Create a new user\")]\npublic static class CreateUser\n{\n    public record Request(\n        [Required, MinLength(2)] string Name,\n        [Required, EmailAddress] string Email);\n\n    public record Response(Guid Id, string Name, string Email, DateTime CreatedAt);\n\n    public static async Task\u003cResponse\u003e Handle(Request req, IUserStore store, CancellationToken ct)\n    {\n        var user = await store.AddAsync(req.Name, req.Email, ct);\n        return new Response(user.Id, user.Name, user.Email, user.CreatedAt);\n    }\n}\n```\n\nThe 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()`.\n\n\u003e **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`](docs/guides/parameter-binding.md) and `samples/SliceFx.Sample/Features/Users/PromoteUser.cs`.\n\n## Filters and validation\n\nFeature filters are standard ASP.NET Core `IEndpointFilter` types:\n\n```csharp\n[Feature(\"DELETE /users/{id:guid}\", Summary = \"Delete a user\")]\n[Filter\u003cRequestLoggingFilter\u003e]\n[Filter\u003cRequireApiKeyFilter\u003e]\npublic static class DeleteUser\n{\n    public static async Task\u003cIResult\u003e Handle(Guid id, IUserStore store, CancellationToken ct)\n    {\n        var user = await store.GetAsync(id, ct);\n        if (user is null) return Results.NotFound();\n        await store.RemoveAsync(id, ct);\n        return Results.NoContent();\n    }\n}\n```\n\n`AddSlice()` registers referenced filters and matching validators as scoped services, and `[Filter\u003cT\u003e]` applies filters in declaration order. Supported DataAnnotations rules are generated and run first; closed `ISliceValidator\u003cTRequest\u003e` 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.\n\nFor production authorization policies, prefer ASP.NET Core Authorization. Slice filters are best for explicit per-feature endpoint filter behavior.\n\nRead more:\n\n- [Filter declarations](docs/guides/filter-declarations.md)\n- [Filter configuration](docs/patterns/filter-configuration.md)\n- [Return-type guidance](docs/guides/return-types.md)\n- [ASP.NET features and escape hatches](docs/guides/aspnet-features.md)\n\n## What you keep\n\nSliceFx generated code is pure Minimal API expansion — the full ASP.NET surface stays available.\n\n**Features you keep on every endpoint:**\n\n- ASP.NET Core Authorization — `[Authorize]`, policies, fallback policy, `RequireAuthorization()`\n- Output caching — `CacheOutput()` via route group\n- Rate limiting — `RequireRateLimiting()` via route group\n- CORS — `RequireCors()` via route group\n- Exception handling middleware and `IProblemDetailsService`\n- `[Filter\u003cT\u003e]` endpoint filters with full `IEndpointFilter` access\n- OpenAPI integration — `builder.Services.AddOpenApi()` / `app.MapOpenApi()`\n- Standard Minimal API binding — `[FromRoute]`, `[FromQuery]`, `[FromHeader]`, `[FromForm]`, `[FromServices]`, `[FromKeyedServices]`\n\n**Escape hatches for common needs:**\n\n| Need | Default path | Escape hatch |\n| --- | --- | --- |\n| Validation | DataAnnotations attributes on the request record | Implement `ISliceValidator\u003cT\u003e` for the request type |\n| Authorization | ASP.NET Core Authorization (`[Authorize]`, policies) | Group-level `RequireAuthorization(...)` or fallback policy |\n| Rate limiting / caching / CORS | Route group: `app.MapGroup(\"/api\").RequireRateLimiting(...).MapSlices()` | Per-group or per-endpoint policy |\n| Cross-cutting behavior | `[Filter\u003cT\u003e]` endpoint filter | Standard ASP.NET Core middleware |\n\nFor more detail see [ASP.NET features and escape hatches](docs/guides/aspnet-features.md).\n\n## What works today\n\n| Feature | Status |\n| --- | --- |\n| `[Feature(\"METHOD /path\")]` declarative routing | Implemented |\n| Source-generated `AddSlice()` / `MapSlices()` | Implemented |\n| Static handlers with body / route / query / DI / `CancellationToken` binding | Implemented |\n| Source-generated DataAnnotations validation for supported property/positional-record attributes | Implemented |\n| `ISliceValidator\u003cT\u003e` custom validation | Implemented |\n| `[Filter\u003cT\u003e]` endpoint filters | Implemented |\n| Route metadata manifest | Experimental |\n| `slicefx routes` portability classification | Experimental |\n| `slicefx client csharp` typed client generation | Experimental |\n| `slicefx client typescript` typed fetch client generation | Experimental |\n| AWS SAM manifest generation | Experimental |\n| ASP.NET-hosted Lambda adapter | Experimental |\n| Function-per-feature Lambda handlers | Experimental HTTP API v2 NativeAOT binary-per-feature packaging |\n| TestHost helper | Experimental |\n| WASI adapter | Experimental single-component in-process wasi:http dispatch; per-feature WASM packaging is not implemented |\n| `SliceResult\u003cT\u003e` / `SliceResult` typed WASI results | Implemented — host-neutral result structs in `SliceFx.Core`; source generator + CLI client generator unwrap to the payload type |\n\nThe 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\u003cT\u003e` generate `Task\u003cT\u003e` methods; routes returning the non-generic `SliceResult` generate `Task` (void) methods.\n\n## Adoption evidence\n\n| Evidence type | Current public count | Notes |\n| --- | ---: | --- |\n| Production adoption | 1 | Maintainer dogfooding: [slicefx-inbox](https://github.com/sano-suguru/slicefx-inbox) running on Fermyon Cloud (Spin WASI, `wasi:http/incoming-handler`) since preview.5. All 8 routes use `SliceResult\u003cT\u003e` / `SliceResult` (preview.7); `SliceApiClient.g.cs` is fully generated. |\n| Published personal dogfooding logs | 0 | A published write-up is planned; the dogfooding itself is live. |\n\n## Portability\n\nMost 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.\n\nThe 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.\n\n| Class | Meaning |\n| --- | --- |\n| `portable` | Returns a plain record or void. Eligible for typed-client generation, WASI dispatch, and function-per-feature Lambda. |\n| `partial` | Portable handler shape, but attached endpoint filters are ASP.NET-only today. |\n| `aspnet-only` | Returns `IResult` or uses ASP.NET-specific behavior. The full Minimal API feature set is available. |\n\n`aspnet-only` features are standard Minimal API endpoints with the complete ASP.NET ecosystem available — they are not penalized or degraded.\n\n### WASI and edge are optional\n\nYou do not need WASI or edge hosting to use SliceFx. The default path is still a normal ASP.NET Core app.\n\n**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`.\n\nThat 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.\n\n## OpenAPI\n\nSlice 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:\n\n```csharp\nbuilder.Services.AddSlice();\nbuilder.Services.AddOpenApi();\n\nvar app = builder.Build();\napp.MapSlices();\n\nif (app.Environment.IsDevelopment())\n{\n    app.MapOpenApi();\n}\n```\n\nThe 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](docs/guides/openapi.md).\n\n## Tooling and adapters\n\n| Topic | Details |\n| --- | --- |\n| Source generator and route manifest | [docs/source-generator.md](docs/source-generator.md) |\n| CLI commands | [docs/cli.md](docs/cli.md) |\n| Blazor WASM + generated typed client sample | [samples/SliceFx.BlazorSample/](samples/SliceFx.BlazorSample/README.md) |\n| OpenAPI integration | [docs/guides/openapi.md](docs/guides/openapi.md) |\n| Lambda hosting and function-per-feature Lambda | [docs/lambda.md](docs/lambda.md) |\n| Lambda function-per-feature sample | [samples/SliceFx.LambdaFunctionPerFeatureSample/](samples/SliceFx.LambdaFunctionPerFeatureSample/README.md) |\n| WASI deploy path | [samples/SliceFx.WasiSample/README.md](samples/SliceFx.WasiSample/README.md) |\n| Migration guides | [Minimal API](docs/migrations/from-minimal-api.md), [controllers](docs/migrations/from-controllers.md) |\n| Platform abstraction and DI swap patterns | [docs/patterns/platform-abstraction.md](docs/patterns/platform-abstraction.md) |\n| ASP.NET features and escape hatches | [docs/guides/aspnet-features.md](docs/guides/aspnet-features.md) |\n| Design decisions FAQ | [docs/design-decisions.md](docs/design-decisions.md) |\n| Product direction | [docs/product-direction.md](docs/product-direction.md) |\n| Production readiness | [docs/production-readiness.md](docs/production-readiness.md) |\n\n## Build \u0026 run\n\n```bash\ndotnet build\ndotnet run --project samples/SliceFx.Sample\n```\n\nThen:\n\n```bash\ncurl http://localhost:5099/health\ncurl -X POST http://localhost:5099/users \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"Alice\",\"email\":\"alice@example.com\"}'\ncurl -X DELETE http://localhost:5099/users/{id} -H \"X-API-Key: secret\"\n```\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsano-suguru%2Fslicefx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsano-suguru%2Fslicefx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsano-suguru%2Fslicefx/lists"}