From 8f32a06ce9e3f38363e6fdc9261bb2c9be972ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Thu, 20 Aug 2026 08:57:22 +0200 Subject: [PATCH 01/10] Adjust the readme for GenHTTP 11 --- Playground/Program.cs | 20 +++++--- README.md | 111 ++++++++++-------------------------------- 2 files changed, 39 insertions(+), 92 deletions(-) diff --git a/Playground/Program.cs b/Playground/Program.cs index 8333f9870..f7d1865ad 100644 --- a/Playground/Program.cs +++ b/Playground/Program.cs @@ -1,9 +1,17 @@ using GenHTTP.Engine.Internal; +using GenHTTP.Modules.ApiBrowsing; +using GenHTTP.Modules.Functional; +using GenHTTP.Modules.Layouting; +using GenHTTP.Modules.OpenApi; +using GenHTTP.Modules.Practices; -using GenHTTP.Modules.IO; +// use a handler of your choice (see the samples below) +var api = Layout.Create() + .Add(Inline.Create().Get(() => "Hello World")) + .AddOpenApi() + .AddScalar(); -var app = Content.From(Resource.FromString("Hello World!")); - -await Host.Create() - .Handler(app) - .RunAsync(); +var host = await Host.Create() + .Handler(api) + .Defaults() + .StartAsync(); // or .RunAsync() to block until the (console) application is shut down diff --git a/README.md b/README.md index 258dd6ce6..4bef100cd 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,45 @@ # GenHTTP Webserver GenHTTP is a lightweight, modular web server written in pure C# with a strong focus on developer experience. The main -purpose of this project is to quickly create web services written in .NET 8 / 9 / 10, allowing developers to concentrate on +purpose of this project is to quickly create web services written in .NET 10 / 11, allowing developers to concentrate on the functionality rather than on messing around with configuration files or complex concepts. -[![View - Documentation](https://img.shields.io/badge/view-Documentation-AB54FF)](https://genhttp.org/documentation/) [![nuget Package](https://img.shields.io/nuget/v/GenHTTP.Core.svg)](https://www.nuget.org/packages/GenHTTP.Core/) [![HTTP Arena](https://img.shields.io/endpoint?url=https://www.http-arena.com/badge/genhttp/h1.json)](https://www.http-arena.com/#type=emerging,flagship&tuned=1) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=GenHTTP&metric=coverage)](https://sonarcloud.io/dashboard?id=GenHTTP) [![Discord](https://discordapp.com/api/guilds/1177529388229734410/widget.png?style=shield)](https://discord.gg/PRkwKrnrB4) - -## Features - -- Setup new webservices in a couple of minutes using [project templates](https://genhttp.org/documentation/content/templates/) -- Supports [current standards](https://genhttp.org/features/) such as Open API, Websockets, Server Sent Events or JWT authentication -- Embed web services into a new or already existing console, service, WPF, WinForms, WinUI, MAUI, Avalonia or Uno application -- Projects are fully described in code - no configuration files needed, no magical behavior you need to learn -- Optionally supports [Kestrel](https://genhttp.org/documentation/server/engines/) as an underlying HTTP engine (enables HTTP/2 and HTTP/3 via QUIC) -- [Optimized](https://genhttp.org/features/) out of the box, small memory and storage [footprint](https://genhttp.org/features/#footprint) -- Carefully hand-crafted code, with stable releases and long-term [support options](https://genhttp.org/support/) -- Grade A+ security level according to SSL Labs, hardened against typical attack vectors +[![View - Documentation](https://img.shields.io/badge/view-Documentation-AB54FF)](https://genhttp.org/documentation/) [![nuget Package](https://img.shields.io/nuget/v/GenHTTP.Full.svg)](https://www.nuget.org/packages/GenHTTP.Full/) [![HTTP Arena](https://img.shields.io/endpoint?url=https://www.http-arena.com/badge/genhttp/h1.json)](https://www.http-arena.com/#type=emerging,flagship&tuned=0) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=GenHTTP&metric=coverage)](https://sonarcloud.io/dashboard?id=GenHTTP) [![Discord](https://discordapp.com/api/guilds/1177529388229734410/widget.png?style=shield)](https://discord.gg/PRkwKrnrB4) ## Getting Started -This section shows how to create a new project from scratch using project templates and how to extend your existing -application by embedding the GenHTTP engine. - -> [!NOTE] -> This is a brief overview to get you running. You might want to have a look at -> the [tutorials](https://genhttp.org/documentation/tutorials/) for detailed step-by-step guides. - -### New Project - -Project templates can be used to create apps for typical use cases with little effort. After installing -the [.NET SDK](https://dotnet.microsoft.com/en-us/download) and the templates via `dotnet new -i GenHTTP.Templates` in -the terminal, the templates are available via the console or directly in Visual Studio: +To host a GenHTTP server instance in an existing or new .NET project, add a reference to `GenHTTP.Full` to your +project and spin off a new host: - - -To create a project by using the terminal, create a new folder for your app and use one of the following commands: - -| Template | Command | Documentation | -|-------------------------------|---------------------------------------------|------------------------------------------------------------------------------------------------------------------| -| REST Webservice | `dotnet new genhttp-webservice` | [Webservices](https://genhttp.org/documentation/content/frameworks/webservices/) | -| REST Webservice (single file) | `dotnet new genhttp-webservice-minimal` | [Functional Handlers](https://genhttp.org/documentation/content/frameworks/functional/) | -| REST Webservice (controllers) | `dotnet new genhttp-webservice-controllers` | [Controllers](https://genhttp.org/documentation/content/frameworks/controllers/) | -| Websocket | `dotnet new genhttp-websocket` | [Websockets](https://genhttp.org/documentation/content/frameworks/websockets/) | -| Server Sent Events (SSE) | `dotnet new genhttp-sse` | [Server Sent Events](https://genhttp.org/documentation/content/handlers/server-sent-events/) | -| Website (Static HTML) | `dotnet new genhttp-website-static` | [Statics Websites](https://genhttp.org/documentation/content/frameworks/static-websites/) | -| Single Page Application (SPA) | `dotnet new genhttp-spa` | [Single Page Applications (SPA)](https://genhttp.org/documentation/content/frameworks/single-page-applications/) | - -After the project has been created, you can run it via `dotnet run` and access the server via http://localhost:8080. +```csharp +using GenHTTP.Engine.Internal; -### Extending Existing Apps +using GenHTTP.Modules.ApiBrowsing; +using GenHTTP.Modules.Functional; +using GenHTTP.Modules.Layouting; +using GenHTTP.Modules.OpenApi; +using GenHTTP.Modules.Practices; -If you would like to extend an existing .NET application, just add a nuget reference to the `GenHTTP.Core` nuget package. You can then spawn a new server instance with just a few lines of code: - -```csharp -var content = Content.From(Resource.FromString("Hello World!")); +// use a handler of your choice (see the samples below) +var api = Layout.Create() + .Add(Inline.Create().Get(() => "Hello World")) + .AddOpenApi() + .AddScalar(); var host = await Host.Create() - .Handler(content) + .Handler(api) .Defaults() - .StartAsync(); // or .RunAsync() to block until the application is shut down + .StartAsync(); // or .RunAsync() to block until the (console) application is shut down ``` -When you run this sample it can be accessed in the browser via http://localhost:8080. +When running this snippet, the host will answer any request to http://localhost:8080 with a "Hello World" text response, +serve an Open API specification at http://localhost:8080/openapi.json and provide a graphical API +viewer on http://localhost:8080/scalar/. -### Next Steps +## Samples -The [documentation](https://genhttp.org/documentation/) provides a step-by-step starting guide as well as additional -information on how to -implement [webservices](https://genhttp.org/documentation/content/frameworks/webservices/), [minimal webservices](https://genhttp.org/documentation/content/frameworks/functional/), [controller-based webservices](https://genhttp.org/documentation/content/frameworks/controllers/), [static websites](https://genhttp.org/documentation/content/frameworks/static-websites/), -or [single page applications](https://genhttp.org/documentation/content/frameworks/single-page-applications/) and how -to [host your application](https://genhttp.org/documentation/hosting/) via Docker. +This section contains a few typical examples to get you started. See [the documentation](https://genhttp.org/documentation/content/) +for all available capabilities. Additional, runnable samples can be found in the [playground](./Playground/) project. ## Support @@ -93,10 +63,7 @@ Additionally, our automated tests ensure full compatibility on the following pla ## Building the Server -> [!NOTE] -> The `main` branch reflects the upcoming changes for GenHTTP 11, which are rather drastic. For the current stable release, checkout `release/10.5` instead. - -To build the server from source, clone this repository and run the playground project launcher for .NET 10: +To build the server from source, clone this repository and run the playground project launcher for .NET 11: ```sh git clone https://github.com/Kaliumhexacyanoferrat/GenHTTP.git @@ -106,23 +73,6 @@ dotnet run This will build the playground project launcher with all the server dependencies and launch the server process on port 8080. You can access the playground in the browser via http://localhost:8080. -## Contributing - -Writing a general purpose web application server is a tremendous task, so any contribution is very welcome. Besides -extending the server core, you might want to - -- Leave a star on GitHub -- Extend the content capabilities of the server (e.g. by adding a new serialization format or rendering engine) -- Refine our [project templates](https://genhttp.org/documentation/content/templates/) -- Perform code reviews -- Analyze the performance or security of the server -- Clarfify and extend our tests -- Improve the documentation on the [website](https://genhttp.org/) or in code - -If you would like to contribute, please also have a look at -the [contribution guidelines](https://github.com/Kaliumhexacyanoferrat/GenHTTP/blob/master/CONTRIBUTING.md) and -the [good first issues](https://github.com/Kaliumhexacyanoferrat/GenHTTP/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). - ## History The web server was originally developed in 2008 to run on a netbook with an Intel Atom processor. Both IIS and Apache @@ -131,15 +81,6 @@ on [archive.org](https://web.archive.org/web/20100706192130/http://gene.homeip.n code has been moved to GitHub with the goal to rework the project to be able to run dockerized web applications written in C#. In 2024 the focus has shifted towards API development, dropping support for generating graphical web applications. -## Links - -- Related to - GenHTTP: [Templates](https://github.com/Kaliumhexacyanoferrat/GenHTTP.Templates) | [Website](https://github.com/Kaliumhexacyanoferrat/GenHTTP.Website) -- Reference - projects: [GenHTTP Gateway](https://github.com/Kaliumhexacyanoferrat/GenHTTP.Gateway) | [MockH](https://github.com/Kaliumhexacyanoferrat/MockH) | [LiquidPages](https://github.com/kinetq/liquid-pages) -- Similar - projects: [Wired.IO](https://github.com/MDA2AV/Wired.IO) | [Unhinged](https://github.com/MDA2AV/unhinged) | [SimpleW](https://github.com/stratdev3/SimpleW) | [Sisk](https://www.sisk-framework.org/) | [NetCoreServer](https://github.com/chronoxor/NetCoreServer) | [Watson Webserver](https://github.com/jchristn/WatsonWebserver) | [EmbedIO](https://github.com/unosquare/embedio) - ## Thanks - Powered by [.NET](https://github.com/dotnet/core) @@ -147,6 +88,4 @@ in C#. In 2024 the focus has shifted towards API development, dropping support f ### Supported by -[![HTTP Arena logo.](https://cdn.jsdelivr.net/gh/MDA2AV/httparena-badge/wordmark.svg)]([https://jb.gg/OpenSource](https://www.http-arena.com/leaderboard/)) - [![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSource) From 65e16e43fa041ecdf28d7bab26f42dcc5430080f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Wed, 26 Aug 2026 13:48:07 +0200 Subject: [PATCH 02/10] Add some samples --- Playground/Program.cs | 22 +++++----- Playground/Samples/LayoutingSample.cs | 38 ++++++++++++++++++ .../Samples/SinglePageApplicationSample.cs | 27 +++++++++++++ Playground/Samples/StaticFileSample.cs | 24 +++++++++++ Playground/Samples/StaticWebsiteSample.cs | 27 +++++++++++++ README.md | 40 +++++++++---------- 6 files changed, 145 insertions(+), 33 deletions(-) create mode 100644 Playground/Samples/LayoutingSample.cs create mode 100644 Playground/Samples/SinglePageApplicationSample.cs create mode 100644 Playground/Samples/StaticFileSample.cs create mode 100644 Playground/Samples/StaticWebsiteSample.cs diff --git a/Playground/Program.cs b/Playground/Program.cs index f7d1865ad..b7562c4e5 100644 --- a/Playground/Program.cs +++ b/Playground/Program.cs @@ -1,17 +1,13 @@ using GenHTTP.Engine.Internal; -using GenHTTP.Modules.ApiBrowsing; -using GenHTTP.Modules.Functional; -using GenHTTP.Modules.Layouting; -using GenHTTP.Modules.OpenApi; + using GenHTTP.Modules.Practices; -// use a handler of your choice (see the samples below) -var api = Layout.Create() - .Add(Inline.Create().Get(() => "Hello World")) - .AddOpenApi() - .AddScalar(); +using GenHTTP.Playground.Samples; + +var sample = LayoutingSample.Create(); -var host = await Host.Create() - .Handler(api) - .Defaults() - .StartAsync(); // or .RunAsync() to block until the (console) application is shut down +return await Host.Create() + .Handler(sample) + .Development() + .Defaults() + .RunAsync(); diff --git a/Playground/Samples/LayoutingSample.cs b/Playground/Samples/LayoutingSample.cs new file mode 100644 index 000000000..dd03f9c3e --- /dev/null +++ b/Playground/Samples/LayoutingSample.cs @@ -0,0 +1,38 @@ +using GenHTTP.Api.Content; + +using GenHTTP.Modules.Files; +using GenHTTP.Modules.Functional; +using GenHTTP.Modules.Layouting; + +namespace GenHTTP.Playground.Samples; + +public static class LayoutingSample +{ + + public static IHandlerBuilder Create() + { + /* + * + * Layouts allow you to structure your web application and divide it into + * different logical parts. The layout will route incoming requests to the designated + * handler. Layouts can be nested as needed. + * + * See https://genhttp.org/documentation/content/handlers/layouting/ + * + */ + + // serve static files from the current directory + var assets = Assets.From("./"); + + // define a simple REST API + var api = Inline.Create() + .Get(() => "Hello World!"); + + // assemble our application from the parts above and + // register them at the given URLs + return Layout.Create() + .Add("assets", assets) // e.g. GET http://localhost:8080/assets/GenHTTP.Playground.xml + .Add("api", api); // e.g. GET http://localhost:8080/api/ + } + +} diff --git a/Playground/Samples/SinglePageApplicationSample.cs b/Playground/Samples/SinglePageApplicationSample.cs new file mode 100644 index 000000000..e0163ca48 --- /dev/null +++ b/Playground/Samples/SinglePageApplicationSample.cs @@ -0,0 +1,27 @@ +using GenHTTP.Api.Content; + +using GenHTTP.Modules.IO; +using GenHTTP.Modules.SinglePageApplications; + +namespace GenHTTP.Playground.Samples; + +public static class SinglePageApplicationSample +{ + + public static IHandlerBuilder Create() + { + /* + * + * Serves a single page application (SPA) from a directory (or resource tree in general). + * + * See https://genhttp.org/documentation/content/frameworks/single-page-applications/ + * + */ + + var files = ResourceTree.FromDirectory("/var/app"); + + return SinglePageApplication.From(files); + } + +} + diff --git a/Playground/Samples/StaticFileSample.cs b/Playground/Samples/StaticFileSample.cs new file mode 100644 index 000000000..2e30d43e6 --- /dev/null +++ b/Playground/Samples/StaticFileSample.cs @@ -0,0 +1,24 @@ +using GenHTTP.Api.Content; + +using GenHTTP.Modules.Files; + +namespace GenHTTP.Playground.Samples; + +public static class StaticFileSample +{ + + public static IHandlerBuilder Create() + { + /* + * + * Serves files from a given directory or resource tree. + * + * See https://genhttp.org/documentation/content/handlers/static-content/ + * + */ + + // e.g. GET http://localhost:8080/assets/GenHTTP.Playground.xml + return Assets.From("./"); + } + +} diff --git a/Playground/Samples/StaticWebsiteSample.cs b/Playground/Samples/StaticWebsiteSample.cs new file mode 100644 index 000000000..7b2f88a5a --- /dev/null +++ b/Playground/Samples/StaticWebsiteSample.cs @@ -0,0 +1,27 @@ +using GenHTTP.Api.Content; + +using GenHTTP.Modules.IO; +using GenHTTP.Modules.StaticWebsites; + +namespace GenHTTP.Playground.Samples; + +public static class StaticWebsiteSample +{ + + public static IHandlerBuilder Create() + { + /* + * + * Serves a static website from a directory (or resource tree in general). + * + * See https://genhttp.org/documentation/content/frameworks/static-websites/ + * + */ + + var files = ResourceTree.FromDirectory("/var/www"); + + return StaticWebsite.From(files); + } + +} + diff --git a/README.md b/README.md index 4bef100cd..1002f38aa 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ the functionality rather than on messing around with configuration files or comp ## Getting Started -To host a GenHTTP server instance in an existing or new .NET project, add a reference to `GenHTTP.Full` to your +To host a GenHTTP server instance in an existing or new .NET project, add a nuget reference to `GenHTTP.Full` to your project and spin off a new host: ```csharp @@ -33,13 +33,21 @@ var host = await Host.Create() ``` When running this snippet, the host will answer any request to http://localhost:8080 with a "Hello World" text response, -serve an Open API specification at http://localhost:8080/openapi.json and provide a graphical API -viewer on http://localhost:8080/scalar/. +serve an Open API specification at http://localhost:8080/openapi.json and provide a graphical API viewer +on http://localhost:8080/scalar/. ## Samples -This section contains a few typical examples to get you started. See [the documentation](https://genhttp.org/documentation/content/) -for all available capabilities. Additional, runnable samples can be found in the [playground](./Playground/) project. +The [playground](./Playground/) project provides a quick starting point to view sample code and find more complex apps +built with GenHTTP. See [the documentation](https://genhttp.org/documentation/content/) +for all available capabilities. + +| Sample | Description | +|---------------------------------------------------------------------------------|-----------------------------------------------------------| +| [Layouting](./Playground/Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | +| [Static Files](./Playground/Samples/StaticFileSample.cs) | Serves static files from a directory. | +| [Static Websites](./Playground/Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | +| [Single Page Applications](./Playground/Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. | ## Support @@ -49,18 +57,6 @@ to [join our Discord community](https://discord.gg/PRkwKrnrB4) to get help. For commercial products and projects, GenHTTP provides additional support options [on request](https://genhttp.org/support/). -## Platforms & Releases - -GenHTTP targets all .NET versions currently [supported by Microsoft](https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core). -Major versions are released once a year, following the .NET release cycle. -Additionally, our automated tests ensure full compatibility on the following platforms: - -| OS | Architectures | -|---------|-------------------------| -| Linux | `x64`, `arm32`, `arm64` | -| Windows | `x64`, `arm64` | -| macOS | `x64`, `arm64` | - ## Building the Server To build the server from source, clone this repository and run the playground project launcher for .NET 11: @@ -71,7 +67,9 @@ cd ./GenHTTP/Playground dotnet run ``` -This will build the playground project launcher with all the server dependencies and launch the server process on port 8080. You can access the playground in the browser via http://localhost:8080. +This will build the playground project launcher with all the server dependencies and launch the server process on port + +8080. You can access the playground in the browser via http://localhost:8080. ## History @@ -79,12 +77,14 @@ The web server was originally developed in 2008 to run on a netbook with an Inte failed to render dynamic pages on such a slow CPU back then. The original project description can still be found on [archive.org](https://web.archive.org/web/20100706192130/http://gene.homeip.net/GenHTTPWebsite/). In 2019, the source code has been moved to GitHub with the goal to rework the project to be able to run dockerized web applications written -in C#. In 2024 the focus has shifted towards API development, dropping support for generating graphical web applications. +in C#. In 2024 the focus has shifted towards API development, dropping support for generating graphical web +applications. ## Thanks - Powered by [.NET](https://github.com/dotnet/core) -- Modules implemented with [NSwag](https://github.com/RicoSuter/NSwag) | [Cottle](https://r3c.github.io/cottle/) | [SharpCompress](https://github.com/adamhathcock/sharpcompress) +- Modules implemented + with [NSwag](https://github.com/RicoSuter/NSwag) | [Cottle](https://r3c.github.io/cottle/) | [SharpCompress](https://github.com/adamhathcock/sharpcompress) ### Supported by From a0890df7f1a77f68e50cdfdbc15ef082f1fce5a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Wed, 26 Aug 2026 13:50:38 +0200 Subject: [PATCH 03/10] Reduce URL clutter --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1002f38aa..c5792d4fb 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,13 @@ var host = await Host.Create() .StartAsync(); // or .RunAsync() to block until the (console) application is shut down ``` -When running this snippet, the host will answer any request to http://localhost:8080 with a "Hello World" text response, -serve an Open API specification at http://localhost:8080/openapi.json and provide a graphical API viewer -on http://localhost:8080/scalar/. +Running this snippet will provide the following endpoints: + +| Endpoint | Description | +|------------------------------------|------------------------------------------------------------------------| +| http://localhost:8080 | Serves the API, answering requests with a "Hello World" text response. | +| http://localhost:8080/openapi.json | Serves the automatically generated Open API specification of the API. | +| http://localhost:8080/scalar/ | Servers a graphical viewer of the API, using Scalar. | ## Samples From 0f5e68fe39fb4b6afdb6789a3b76bc1ced6241b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Wed, 26 Aug 2026 14:11:11 +0200 Subject: [PATCH 04/10] Add playground readme --- Playground/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Playground/README.md diff --git a/Playground/README.md b/Playground/README.md new file mode 100644 index 000000000..7345c0c34 --- /dev/null +++ b/Playground/README.md @@ -0,0 +1,11 @@ +# GenHTTP Playground + +The playground provides code samples for quick reference and allows developers to +quickly validate things. + +| Sample | Description | +|---------------------------------------------------------------------------------|-----------------------------------------------------------| +| [Layouting](./Playground/Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | +| [Static Files](./Playground/Samples/StaticFileSample.cs) | Serves static files from a directory. | +| [Static Websites](./Playground/Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | +| [Single Page Applications](./Playground/Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. | From 9e16d35d07edd928dead1566a224572347833d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Wed, 26 Aug 2026 14:11:47 +0200 Subject: [PATCH 05/10] Fix paths --- Playground/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Playground/README.md b/Playground/README.md index 7345c0c34..88586e2b0 100644 --- a/Playground/README.md +++ b/Playground/README.md @@ -3,9 +3,9 @@ The playground provides code samples for quick reference and allows developers to quickly validate things. -| Sample | Description | -|---------------------------------------------------------------------------------|-----------------------------------------------------------| -| [Layouting](./Playground/Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | -| [Static Files](./Playground/Samples/StaticFileSample.cs) | Serves static files from a directory. | -| [Static Websites](./Playground/Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | -| [Single Page Applications](./Playground/Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. | +| Sample | Description | +|-----------------------------------------------------------------------------|-----------------------------------------------------------| +| [Layouting](./Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | +| [Static Files](./Samples/StaticFileSample.cs) | Serves static files from a directory. | +| [Static Websites](./Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | +| [Single Page Applications](./Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. | From 241828ff52d66295a151704859aa12c4b786c49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Tue, 1 Sep 2026 19:11:26 +0200 Subject: [PATCH 06/10] Add webservice sample --- Playground/README.md | 11 +++-- Playground/Samples/WebserviceSample.cs | 63 ++++++++++++++++++++++++++ README.md | 16 ++----- 3 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 Playground/Samples/WebserviceSample.cs diff --git a/Playground/README.md b/Playground/README.md index 88586e2b0..6a89e1128 100644 --- a/Playground/README.md +++ b/Playground/README.md @@ -3,9 +3,10 @@ The playground provides code samples for quick reference and allows developers to quickly validate things. -| Sample | Description | -|-----------------------------------------------------------------------------|-----------------------------------------------------------| -| [Layouting](./Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | -| [Static Files](./Samples/StaticFileSample.cs) | Serves static files from a directory. | -| [Static Websites](./Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | +| Sample | Description | +|----------------------------------------------------------------------|-----------------------------------------------------------| +| [Layouting](./Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | +| [Webservices](./Samples/WebserviceSample.cs) | Implements a REST webservice via a handler class. | +| [Static Files](./Samples/StaticFileSample.cs) | Serves static files from a directory. | +| [Static Websites](./Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | | [Single Page Applications](./Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. | diff --git a/Playground/Samples/WebserviceSample.cs b/Playground/Samples/WebserviceSample.cs new file mode 100644 index 000000000..58c3e6161 --- /dev/null +++ b/Playground/Samples/WebserviceSample.cs @@ -0,0 +1,63 @@ +using GenHTTP.Api.Content; + +using GenHTTP.Modules.Controllers; +using GenHTTP.Modules.Layouting; +using GenHTTP.Modules.Reflection; +using GenHTTP.Modules.Webservices; + +namespace GenHTTP.Playground.Samples; + +public static class WebserviceSample +{ + + public static IHandlerBuilder Create() + { + /* + * + * Shows how to declare and register a class that will be invoked + * to handle incoming HTTP requests. + * + * See https://genhttp.org/documentation/content/frameworks/webservices/ + * + */ + + return Layout.Create() + .AddService("books"); + } + + public record Book(int Id, string Title); + + public class BookService + { + private readonly List _books = + [ + new(1, "Lord of the Rings") + ]; + + // GET http://localhost:8080/books/ + [ResourceMethod] + public List List() => _books; + + // PUT http://localhost:8080/books/ with JSON/XML/... payload + [ResourceMethod(Method.Put)] + public Book Create(Book book) + { + var toAdd = book with + { + Id = _books.Max(b => b.Id) + 1 + }; + + _books.Add(toAdd); + return toAdd; + } + + // DELETE http://localhost:8080/books/1 + [ResourceMethod(Method.Delete, ":id")] + public void Delete([FromPath] int id) + { + _books.RemoveAll(b => b.Id == id); + } + + } + +} diff --git a/README.md b/README.md index c5792d4fb..9e742dc1f 100644 --- a/README.md +++ b/README.md @@ -43,15 +43,7 @@ Running this snippet will provide the following endpoints: ## Samples The [playground](./Playground/) project provides a quick starting point to view sample code and find more complex apps -built with GenHTTP. See [the documentation](https://genhttp.org/documentation/content/) -for all available capabilities. - -| Sample | Description | -|---------------------------------------------------------------------------------|-----------------------------------------------------------| -| [Layouting](./Playground/Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | -| [Static Files](./Playground/Samples/StaticFileSample.cs) | Serves static files from a directory. | -| [Static Websites](./Playground/Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | -| [Single Page Applications](./Playground/Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. | +built with GenHTTP. See [the documentation](https://genhttp.org/documentation/content/) for all available capabilities. ## Support @@ -82,13 +74,13 @@ failed to render dynamic pages on such a slow CPU back then. The original projec on [archive.org](https://web.archive.org/web/20100706192130/http://gene.homeip.net/GenHTTPWebsite/). In 2019, the source code has been moved to GitHub with the goal to rework the project to be able to run dockerized web applications written in C#. In 2024 the focus has shifted towards API development, dropping support for generating graphical web -applications. +applications. In 2026, the API and internal engine have been rewritten to be allocation-free, greatly +improving performance in result. ## Thanks - Powered by [.NET](https://github.com/dotnet/core) -- Modules implemented - with [NSwag](https://github.com/RicoSuter/NSwag) | [Cottle](https://r3c.github.io/cottle/) | [SharpCompress](https://github.com/adamhathcock/sharpcompress) +- Modules implemented with [NSwag](https://github.com/RicoSuter/NSwag) | [Cottle](https://r3c.github.io/cottle/) | [SharpCompress](https://github.com/adamhathcock/sharpcompress) ### Supported by From 15feb3bb304774cb82d9619ba98a618bf776936a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Tue, 1 Sep 2026 19:20:21 +0200 Subject: [PATCH 07/10] Add web service samples --- Playground/README.md | 16 ++++--- Playground/Samples/ControllerSample.cs | 62 ++++++++++++++++++++++++++ Playground/Samples/FunctionalSample.cs | 47 +++++++++++++++++++ Playground/Samples/WebserviceSample.cs | 10 ++--- 4 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 Playground/Samples/ControllerSample.cs create mode 100644 Playground/Samples/FunctionalSample.cs diff --git a/Playground/README.md b/Playground/README.md index 6a89e1128..2dfb5673c 100644 --- a/Playground/README.md +++ b/Playground/README.md @@ -3,10 +3,12 @@ The playground provides code samples for quick reference and allows developers to quickly validate things. -| Sample | Description | -|----------------------------------------------------------------------|-----------------------------------------------------------| -| [Layouting](./Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | -| [Webservices](./Samples/WebserviceSample.cs) | Implements a REST webservice via a handler class. | -| [Static Files](./Samples/StaticFileSample.cs) | Serves static files from a directory. | -| [Static Websites](./Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | -| [Single Page Applications](./Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. | +| Sample | Description | +|----------------------------------------------------------------------|----------------------------------------------------------------------------------| +| [Layouting](./Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. | +| [Webservices](./Samples/WebserviceSample.cs) | Implements a REST webservice via a handler class. | +| [Functional](./Samples/FunctionalSample.cs) | Uses delegates to implement a web service (similar to ASP.NET Core Minimal API). | +| [Controllers](./Samples/ControllerSample.cs) | Uses controllers to implement a web service (similar to ASP.NET Core MVC). | +| [Static Files](./Samples/StaticFileSample.cs) | Serves static files from a directory. | +| [Static Websites](./Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). | +| [Single Page Applications](./Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. | diff --git a/Playground/Samples/ControllerSample.cs b/Playground/Samples/ControllerSample.cs new file mode 100644 index 000000000..e24a2ef25 --- /dev/null +++ b/Playground/Samples/ControllerSample.cs @@ -0,0 +1,62 @@ +using GenHTTP.Api.Content; + +using GenHTTP.Modules.Controllers; +using GenHTTP.Modules.Layouting; +using GenHTTP.Modules.Reflection; + +namespace GenHTTP.Playground.Samples; + +public static class ControllerSample +{ + + public static IHandlerBuilder Create() + { + /* + * + * Shows how to declare and register a controller that will be invoked + * to handle incoming HTTP requests. + * + * See https://genhttp.org/documentation/content/frameworks/controllers/ + * + */ + + return Layout.Create() + .AddController("books"); + } + + public record Book(int Id, string Title); + + public class BookController + { + private static readonly List Books = + [ + new(1, "Lord of the Rings") + ]; + + // GET http://localhost:8080/books/ + [ControllerAction] + public List Index() => Books; + + // PUT http://localhost:8080/books/create with JSON/XML/... payload + [ControllerAction(Method.Put)] + public Book Create(Book book) + { + var toAdd = book with + { + Id = Books.Max(b => b.Id) + 1 + }; + + Books.Add(toAdd); + return toAdd; + } + + // DELETE http://localhost:8080/books/delete/1 + [ControllerAction(Method.Delete)] + public void Delete([FromPath] int id) + { + Books.RemoveAll(b => b.Id == id); + } + + } + +} diff --git a/Playground/Samples/FunctionalSample.cs b/Playground/Samples/FunctionalSample.cs new file mode 100644 index 000000000..f4f6463c4 --- /dev/null +++ b/Playground/Samples/FunctionalSample.cs @@ -0,0 +1,47 @@ +using GenHTTP.Api.Content; + +using GenHTTP.Modules.Functional; +using GenHTTP.Modules.Layouting; + +namespace GenHTTP.Playground.Samples; + +public static class FunctionalSample +{ + + public static IHandlerBuilder Create() + { + /* + * + * Shows how to use delegates that will be invoked + * to handle incoming HTTP requests. + * + * See https://genhttp.org/documentation/content/frameworks/functional/ + * + */ + + var books = new List() + { + new(1, "Lord of the Rings") + }; + + var service = Inline.Create() + .Get(() => books) // GET http://localhost:8080/books/ + .Put((Book book) => // PUT http://localhost:8080/books/ with JSON/XML/... payload + { + var toAdd = book with + { + Id = books.Max(b => b.Id) + 1 + }; + + books.Add(toAdd); + return toAdd; + }) + .Delete(":id", (int id) => books.RemoveAll(b => b.Id == id)); // DELETE http://localhost:8080/books/1 + + return Layout.Create() + .Add("books", service); + } + + public record Book(int Id, string Title); + +} diff --git a/Playground/Samples/WebserviceSample.cs b/Playground/Samples/WebserviceSample.cs index 58c3e6161..6a672d5d8 100644 --- a/Playground/Samples/WebserviceSample.cs +++ b/Playground/Samples/WebserviceSample.cs @@ -29,14 +29,14 @@ public record Book(int Id, string Title); public class BookService { - private readonly List _books = + private static readonly List Books = [ new(1, "Lord of the Rings") ]; // GET http://localhost:8080/books/ [ResourceMethod] - public List List() => _books; + public List List() => Books; // PUT http://localhost:8080/books/ with JSON/XML/... payload [ResourceMethod(Method.Put)] @@ -44,10 +44,10 @@ public Book Create(Book book) { var toAdd = book with { - Id = _books.Max(b => b.Id) + 1 + Id = Books.Max(b => b.Id) + 1 }; - _books.Add(toAdd); + Books.Add(toAdd); return toAdd; } @@ -55,7 +55,7 @@ public Book Create(Book book) [ResourceMethod(Method.Delete, ":id")] public void Delete([FromPath] int id) { - _books.RemoveAll(b => b.Id == id); + Books.RemoveAll(b => b.Id == id); } } From ccacee4006e842a9c7acf0e4aa05d2dcc0c1a3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Tue, 1 Sep 2026 19:24:08 +0200 Subject: [PATCH 08/10] Make the initial sample a little bit more .. useful --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9e742dc1f..24e40dead 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,16 @@ using GenHTTP.Modules.OpenApi; using GenHTTP.Modules.Practices; // use a handler of your choice (see the samples below) -var api = Layout.Create() - .Add(Inline.Create().Get(() => "Hello World")) +var api = Inline.Create() + .Get((int a, int b) => a + b); + +var app = Layout.Create() + .Add(api) .AddOpenApi() .AddScalar(); var host = await Host.Create() - .Handler(api) + .Handler(app) .Defaults() .StartAsync(); // or .RunAsync() to block until the (console) application is shut down ``` @@ -36,7 +39,7 @@ Running this snippet will provide the following endpoints: | Endpoint | Description | |------------------------------------|------------------------------------------------------------------------| -| http://localhost:8080 | Serves the API, answering requests with a "Hello World" text response. | +| http://localhost:8080?a=1&b=2 | Serves the API, answering requests by calculating the sum of two query arguments. | | http://localhost:8080/openapi.json | Serves the automatically generated Open API specification of the API. | | http://localhost:8080/scalar/ | Servers a graphical viewer of the API, using Scalar. | From a326a33b92960facd98131c5ac63eda720a0da43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Thu, 3 Sep 2026 17:03:03 +0200 Subject: [PATCH 09/10] Revise thanks section Updated dependencies and monitoring tools in the README. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 24e40dead..4bf7ed65d 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,9 @@ improving performance in result. ## Thanks -- Powered by [.NET](https://github.com/dotnet/core) -- Modules implemented with [NSwag](https://github.com/RicoSuter/NSwag) | [Cottle](https://r3c.github.io/cottle/) | [SharpCompress](https://github.com/adamhathcock/sharpcompress) +- Powered by [.NET](https://github.com/dotnet/core) and the [.NET Web Stack](https://github.com/dotnet-web-stack) +- Modules implemented with [ioxide](https://github.com/MDA2AV/ioxide) | [NSwag](https://github.com/RicoSuter/NSwag) | [Cottle](https://r3c.github.io/cottle/) | [SharpCompress](https://github.com/adamhathcock/sharpcompress) +- Monitored by [HTTP Arena](https://www.http-arena.com) and [HTTP 1.1 Probe](https://www.http-probe.com/) ### Supported by From a016c0695165d4d9e7cd90cfb1d751ebfd42d1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Fri, 4 Sep 2026 07:34:03 +0200 Subject: [PATCH 10/10] Add a sample for custom frameworks --- Playground/Program.cs | 2 +- Playground/Samples/CustomFrameworkSample.cs | 81 +++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 Playground/Samples/CustomFrameworkSample.cs diff --git a/Playground/Program.cs b/Playground/Program.cs index b7562c4e5..96fe539a8 100644 --- a/Playground/Program.cs +++ b/Playground/Program.cs @@ -4,7 +4,7 @@ using GenHTTP.Playground.Samples; -var sample = LayoutingSample.Create(); +var sample = CustomFrameworkSample.Create(); return await Host.Create() .Handler(sample) diff --git a/Playground/Samples/CustomFrameworkSample.cs b/Playground/Samples/CustomFrameworkSample.cs new file mode 100644 index 000000000..992af6c1e --- /dev/null +++ b/Playground/Samples/CustomFrameworkSample.cs @@ -0,0 +1,81 @@ +using GenHTTP.Api.Content; +using GenHTTP.Api.Infrastructure; +using GenHTTP.Api.Protocol; + +using GenHTTP.Modules.ApiBrowsing; +using GenHTTP.Modules.Conversion; +using GenHTTP.Modules.Functional.Provider; +using GenHTTP.Modules.Layouting; +using GenHTTP.Modules.OpenApi; +using GenHTTP.Modules.Reflection; +using GenHTTP.Modules.Reflection.Operations; + +namespace GenHTTP.Playground.Samples; + +public static class CustomFrameworkSample +{ + + public static IHandlerBuilder Create() + { + /* + * + * Shows how to implement a custom framework. + * + * See https://genhttp.org/documentation/content/frameworks/custom/ + * + */ + + return Layout.Create() + .Add(new CustomFrameworkHandler()) + .AddOpenApi() + .AddScalar(); + } + + public class CustomFrameworkHandler : IHandler, IServiceMethodProvider + { + private MethodCollection? _methods; + + public MethodCollection Methods => _methods ?? throw new InvalidOperationException("Handler is not prepared yet"); + + public async ValueTask PrepareAsync(IServer server) + { + var list = new List(); + + // specify the supported methods of the operation we are exposing + var supportedMethods = new MethodConfiguration([RequestMethod.Get]); + + // the actual piece of code to be executed - either a method info or a delegate + var methodInfo = GetType().GetMethod("ExposedMethod")!; + + // auto enables code generation, otherwise reflection only + var executionSettings = new ExecutionSettings(ExecutionMode.Auto); + + // configures the behavior for serialization, injection and formatting + var registry = new MethodRegistry( + Serialization.Default().Build(), + Injection.Default().Build(), + Formatting.Default().Build() + ); + + // build the operation we would like to provide + var operation = OperationBuilder.Create(server, ":id", methodInfo, null, executionSettings, supportedMethods, registry); + + // create a method handler from the operation which will serve it as an HTTP endpoint + // this handler requires an instance provider which tells the framework on which + // object to invoke the given method info or delegate + list.Add(new MethodHandler(operation, (_) => new(this), registry)); + + // build a method collection handler from all collected operations + // this handler is responsible for routing + _methods = new MethodCollection(list); + + await _methods.PrepareAsync(server); + } + + public ValueTask HandleAsync(IRequest request) => Methods.HandleAsync(request); + + public string ExposedMethod(int id) => id.ToString(); + + } + +}