Handlers, not controllers
A route is an attribute on a method of a plain class. No base class, no IActionResult, no AddControllers(). The generator reads the attribute and emits the handler that calls your method.
Routing
Mark a method with a route or a function name, and a source generator emits the routing table, the parameter binding and the registration code before the assembly is written.
Attribute the method. The routing table, the parameter binding and the registration code are emitted during the build.
[HardenedModule]
[KestrelRuntime]
public partial class Application;
public class GreetingController {
[Get("/hello/{name}")]
public string Hello(string name) => $"Hello, {name}!";
}// Program.cs
var services = new ServiceCollection();
services.AddLogging(logging => logging.AddSimpleConsole(options => options.SingleLine = true));
services.AddHardenedEnvironment(args);
new Application().PopulateServiceCollection(services);
await using var app = HardenedKestrelApplication.Create(
services, kestrel => kestrel.ListenAnyIP(5080));
await app.RunAsync();Or skip the wiring — dotnet new hardened-web writes all of it, with tests:
dotnet new install Hardened.Templates
dotnet new hardened-web -n GreeterSet EmitCompilerGeneratedFiles in the project file and the routing table, the handler and the binding code are all under obj/ as ordinary C#.
The core framework and the AWS integrations version and ship separately, so an application only carries what it uses.
| Repository | What it holds |
|---|---|
| Hardened.Framework | Modules, DI, configuration, routing, binding, templates, testing |
| Hardened.Amz | Lambda runtimes, DynamoDB and SQS clients, CDK constructs |