<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Samples on GenHTTP Webserver</title><link>https://genhttp.org/samples/</link><description>Recent content in Samples on GenHTTP Webserver</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://genhttp.org/samples/index.xml" rel="self" type="application/rss+xml"/><item><title>Authentication</title><link>https://genhttp.org/samples/authentication/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/authentication/</guid><description>&lt;p&gt;A notes API where every user sees their own notes, and administrators see the notes of everyone. Clients&#10;send an API key in the &lt;code&gt;X-API-Key&lt;/code&gt; header, and &lt;code&gt;AuthenticateAsync&lt;/code&gt; turns the key into a user - or rejects&#10;it. This is where you would look the key up in your database.&lt;/p&gt;&#10;&lt;p&gt;The user injector passes the user to the service methods as a parameter, and &lt;code&gt;[RequireRole(&amp;quot;ADMIN&amp;quot;)]&lt;/code&gt;&#10;restricts a method to administrators. Basic, bearer (JWT) and client certificate authentication work the&#10;same way. Try it with the keys &lt;code&gt;alice-key&lt;/code&gt; (a user) and &lt;code&gt;bob-key&lt;/code&gt; (an administrator).&lt;/p&gt;</description></item><item><title>Dependency Injection</title><link>https://genhttp.org/samples/dependency-injection/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/dependency-injection/</guid><description>&lt;p&gt;Lets the framework construct the book service and pass it what it depends on - a repository and the clock -&#10;so the service does not need to know how they are made, and tests can pass fakes instead. The services are&#10;registered with Microsoft&amp;rsquo;s dependency injection, and &lt;code&gt;AddDependencyInjection&lt;/code&gt; makes them available to&#10;the server.&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;AddDependentService&lt;/code&gt; creates &lt;code&gt;BookService&lt;/code&gt; with the repository passed to its constructor, and &lt;code&gt;Add&lt;/code&gt; receives&#10;the &lt;code&gt;TimeProvider&lt;/code&gt; as a parameter of the method.&lt;/p&gt;</description></item><item><title>File Share</title><link>https://genhttp.org/samples/file-share/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/file-share/</guid><description>&lt;p&gt;Shares a folder with friends: they log in with their browser, browse through the files and download them.&#10;&lt;code&gt;Listing&lt;/code&gt; renders a page for every folder, and basic authentication asks for a user name and a password -&#10;here &lt;code&gt;friend&lt;/code&gt; and &lt;code&gt;secret&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;Range support lets browsers and download managers pause and resume the download of a large file. Put the&#10;files to share into a &lt;code&gt;files&lt;/code&gt; folder next to the program.&lt;/p&gt;</description></item><item><title>Layouting</title><link>https://genhttp.org/samples/layouting/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/layouting/</guid><description>&lt;p&gt;Most applications are made of several parts, such as an API, static files and a website. A layout routes&#10;every request to the part it belongs to by its path: here, &lt;code&gt;/assets/&lt;/code&gt; serves files and &lt;code&gt;/api/&lt;/code&gt; a small API.&lt;/p&gt;&#10;&lt;p&gt;Layouts can be nested to build deeper structures, and what you add to a layout - such as authentication or&#10;CORS - applies to everything below it. Put some files into a &lt;code&gt;files&lt;/code&gt; folder next to the program to have&#10;something to serve.&lt;/p&gt;</description></item><item><title>Webservices</title><link>https://genhttp.org/samples/webservices/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/webservices/</guid><description>&lt;p&gt;A small API for a book shelf: clients list the books, add one and delete one. The API is a plain C# class&#10;whose methods are marked with &lt;code&gt;[ResourceMethod]&lt;/code&gt; - the attribute sets the HTTP method and path, and GenHTTP&#10;reads the parameters from the request and writes the return value as the response.&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;AddService&amp;lt;BookService&amp;gt;(&amp;quot;books&amp;quot;)&lt;/code&gt; serves the class below &lt;code&gt;/books/&lt;/code&gt;. Books are read and written as JSON,&#10;or in another format such as XML if the client asks for it. Throwing a &lt;code&gt;ProviderException&lt;/code&gt; ends a request&#10;with the given status, here 409 when the shelf is full.&lt;/p&gt;</description></item><item><title>CORS</title><link>https://genhttp.org/samples/cors/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/cors/</guid><description>&lt;p&gt;Lets a frontend on another origin - here a React app on the Vite dev server, at http://localhost:5173 - call&#10;the API from the browser. Browsers block such requests unless the server allows them with CORS headers, and&#10;ask with a preflight request (&lt;code&gt;OPTIONS&lt;/code&gt;) before they send anything but simple requests.&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;CorsPolicy.Restrictive()&lt;/code&gt; allows the origins you add, with the methods you name, and answers the preflight&#10;requests for you. Requests from any other origin get no CORS headers, so the browser blocks them.&lt;/p&gt;</description></item><item><title>Functional</title><link>https://genhttp.org/samples/functional/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/functional/</guid><description>&lt;p&gt;The book shelf API of the &lt;a href="../webservices/"&gt;webservice sample&lt;/a&gt;, written as delegates instead of a class -&#10;similar to the Minimal APIs of ASP.NET Core. &lt;code&gt;Inline.Create()&lt;/code&gt; takes one delegate per HTTP method (and path,&#10;such as &lt;code&gt;:id&lt;/code&gt; for the id of a book); GenHTTP reads their parameters from the request and writes their result&#10;as the response.&lt;/p&gt;&#10;&lt;p&gt;This keeps small APIs short. The books live in a local list here, which the delegates share.&lt;/p&gt;</description></item><item><title>Legacy Migration</title><link>https://genhttp.org/samples/legacy-migration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/legacy-migration/</guid><description>&lt;p&gt;Replaces an old web application step by step instead of all at once. GenHTTP runs in front of the legacy&#10;application: new endpoints and pages are served by GenHTTP, moved pages are redirected, and everything else&#10;is passed on to the legacy application by a reverse proxy.&lt;/p&gt;&#10;&lt;p&gt;The layout tries its own routes first, so &lt;code&gt;/api/v2/&lt;/code&gt; and &lt;code&gt;/contact&lt;/code&gt; are new, &lt;code&gt;/contact.php&lt;/code&gt; redirects&#10;permanently (search engines learn the new address), and any other path - such as &lt;code&gt;/login.php&lt;/code&gt; - still&#10;reaches the legacy application on port 5000. Move one route at a time until the proxy can go.&lt;/p&gt;</description></item><item><title>Static Files</title><link>https://genhttp.org/samples/static-files/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/static-files/</guid><description>&lt;p&gt;Serves the files of a folder, for example downloads or the assets of an application. GenHTTP sends each file&#10;with the content type of its extension, and &lt;code&gt;Defaults()&lt;/code&gt; adds compression and lets browsers cache the files.&lt;/p&gt;&#10;&lt;p&gt;Put your files into a &lt;code&gt;files&lt;/code&gt; folder next to the program, so &lt;code&gt;/README.md&lt;/code&gt; serves &lt;code&gt;files/README.md&lt;/code&gt;.&#10;&lt;code&gt;Assets.From(&amp;quot;./files&amp;quot;)&lt;/code&gt; is a shorter way to serve a folder from disk.&lt;/p&gt;</description></item><item><title>API Documentation</title><link>https://genhttp.org/samples/api-docs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/api-docs/</guid><description>&lt;p&gt;Documents the book shelf API with an Open API definition and three viewers to explore and try it: Swagger UI,&#10;Redoc and Scalar. &lt;code&gt;AddOpenApi()&lt;/code&gt; generates the definition from the service itself - its paths, parameters and&#10;the shape of a book - so it is always up to date.&lt;/p&gt;&#10;&lt;p&gt;The viewers are served by GenHTTP and need no internet connection. Functional handlers and controllers are&#10;documented the same way.&lt;/p&gt;</description></item><item><title>Controllers</title><link>https://genhttp.org/samples/controllers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/controllers/</guid><description>&lt;p&gt;The book shelf API once more, in the style of MVC controllers: every public method of &lt;code&gt;BookController&lt;/code&gt; is an&#10;action, and its name is its path - &lt;code&gt;Index()&lt;/code&gt; answers &lt;code&gt;/books/&lt;/code&gt;, &lt;code&gt;Create()&lt;/code&gt; answers &lt;code&gt;/books/create/&lt;/code&gt; and&#10;&lt;code&gt;Delete()&lt;/code&gt; answers &lt;code&gt;/books/delete/1/&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;[ControllerAction]&lt;/code&gt; sets the HTTP method of an action, and &lt;code&gt;[FromPath]&lt;/code&gt; takes a parameter from the path&#10;instead of the query. Controllers suit APIs with many actions, where a naming convention saves declaring&#10;every route.&lt;/p&gt;</description></item><item><title>Error Handling</title><link>https://genhttp.org/samples/errors/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/errors/</guid><description>&lt;p&gt;A shop with a website for people and an API for programs, each reporting errors in its own way: the API&#10;answers with JSON (or the format the client asks for), the website with HTML error pages, such as the 404&#10;for an address that does not exist.&lt;/p&gt;&#10;&lt;p&gt;The business logic throws an &lt;code&gt;OutOfStockException&lt;/code&gt; without knowing about HTTP, and &lt;code&gt;OutOfStockMapper&lt;/code&gt; turns&#10;it into a 409 response. A &lt;code&gt;ProviderException&lt;/code&gt; brings its status with it, as for an order that does not&#10;exist.&lt;/p&gt;</description></item><item><title>Localization</title><link>https://genhttp.org/samples/localization/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/localization/</guid><description>&lt;p&gt;Greets visitors in their language and writes the date the way they are used to. The language is taken from&#10;the &lt;code&gt;lang&lt;/code&gt; query parameter, or else from the &lt;code&gt;Accept-Language&lt;/code&gt; header that browsers send; English is the&#10;fallback.&lt;/p&gt;&#10;&lt;p&gt;The localization concern sets the culture for every request, so the code simply uses&#10;&lt;code&gt;CultureInfo.CurrentCulture&lt;/code&gt;. &lt;code&gt;Supports&lt;/code&gt; decides which languages the application offers - here the ones it&#10;has a greeting for, regional variants such as de-CH included.&lt;/p&gt;</description></item><item><title>Server Sent Events</title><link>https://genhttp.org/samples/sse/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/sse/</guid><description>&lt;p&gt;A stock ticker whose price changes every second, pushed by the server to the browser. Server sent events keep&#10;a response open and write an event to it whenever there is news - simpler than websockets when data only&#10;flows from the server to the client.&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;EventSource.Create()&lt;/code&gt; runs &lt;code&gt;SendQuotesAsync&lt;/code&gt; for every client, as long as it stays connected. In the&#10;browser, &lt;code&gt;new EventSource('quotes/')&lt;/code&gt; receives the events, and reconnects on its own if the connection&#10;drops. The prices are made up.&lt;/p&gt;</description></item><item><title>Websockets</title><link>https://genhttp.org/samples/websockets/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/websockets/</guid><description>&lt;p&gt;A chat in the browser: every message is pushed to everyone in the same room, instantly and without polling.&#10;The page connects to &lt;code&gt;/chat&lt;/code&gt; via a websocket, and &lt;code&gt;ChatHandler&lt;/code&gt; forwards every message it receives to the&#10;connections in the room of the sender.&lt;/p&gt;&#10;&lt;p&gt;The reactive websocket API calls &lt;code&gt;OnConnected&lt;/code&gt;, &lt;code&gt;OnMessage&lt;/code&gt; and &lt;code&gt;OnClose&lt;/code&gt; for you, and reads and writes JSON&#10;with &lt;code&gt;ReadPayloadAsync&lt;/code&gt; and &lt;code&gt;WritePayloadAsync&lt;/code&gt;. Open the page in two windows with the same room to chat&#10;with yourself.&lt;/p&gt;</description></item><item><title>Inspection</title><link>https://genhttp.org/samples/inspection/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/inspection/</guid><description>&lt;p&gt;Shows what the server received and what it answered, to find out why a client gets a certain response.&#10;Add &lt;code&gt;?inspect&lt;/code&gt; to an address below the layout, and instead of the response you get the request as GenHTTP&#10;read it - method, path, query and headers - together with the response it would have sent.&lt;/p&gt;&#10;&lt;p&gt;Add the inspector while developing only, as it reveals details of your server.&lt;/p&gt;</description></item><item><title>MCP Tools</title><link>https://genhttp.org/samples/mcp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/mcp/</guid><description>&lt;p&gt;A library that AI agents such as Claude can use: it offers tools to find books and to lend them to readers,&#10;via the Model Context Protocol (MCP). Every method of &lt;code&gt;LibraryTools&lt;/code&gt; marked with &lt;code&gt;[Tool]&lt;/code&gt; is a tool. Its name,&#10;its parameters and the &lt;code&gt;[Summary]&lt;/code&gt; texts tell the agent what the tool does and how to call it, and &lt;code&gt;[Range]&lt;/code&gt;&#10;limits what it may pass.&lt;/p&gt;&#10;&lt;p&gt;Add the server to your agent (see the commands below) and ask it, for example, which books about Rome the&#10;library has: the agent finds them with &lt;code&gt;find_books&lt;/code&gt;, and may lend one with &lt;code&gt;lend_book&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Pages</title><link>https://genhttp.org/samples/pages/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/pages/</guid><description>&lt;p&gt;Renders HTML pages on the server, for example for an internal tool that does not need a frontend framework.&#10;The list of books is rendered from a Cottle template with the books as its model; the about page uses the&#10;look of the pages GenHTTP renders itself, such as its error pages.&lt;/p&gt;&#10;&lt;p&gt;Templates do not escape HTML for you, so the titles pass &lt;code&gt;Escaped()&lt;/code&gt; first. In an application, the template&#10;would rather be a file or an embedded resource than a string.&lt;/p&gt;</description></item><item><title>Static Websites</title><link>https://genhttp.org/samples/static-website/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/static-website/</guid><description>&lt;p&gt;Serves a website made of HTML, CSS and image files, such as the output of a static site generator. A request&#10;for a folder is answered with its &lt;code&gt;index.html&lt;/code&gt;, so &lt;code&gt;/about/&lt;/code&gt; serves &lt;code&gt;about/index.html&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;Put your files into a &lt;code&gt;website&lt;/code&gt; folder next to the program. &lt;code&gt;ResourceTree.FromDirectory&lt;/code&gt; reads them from&#10;there; files embedded into your assembly (&lt;code&gt;ResourceTree.FromAssembly&lt;/code&gt;) work the same way.&lt;/p&gt;</description></item><item><title>Virtual Hosting</title><link>https://genhttp.org/samples/virtual-hosting/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/virtual-hosting/</guid><description>&lt;p&gt;Hosts a blog and a shop on one server, each on a domain of its own. &lt;code&gt;VirtualHosts&lt;/code&gt; picks the website by the&#10;domain the request was sent to (its &lt;code&gt;Host&lt;/code&gt; header), and sends the visitors of any other domain to the blog.&lt;/p&gt;&#10;&lt;p&gt;Browsers resolve every name ending in &lt;code&gt;.localhost&lt;/code&gt; to your own machine, so you can try it without setting up&#10;any domain: open &lt;a href="http://blog.localhost:8080/" rel="noopener"&gt;http://blog.localhost:8080/&lt;/a&gt; and &lt;a href="http://shop.localhost:8080/" rel="noopener"&gt;http://shop.localhost:8080/&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Load Balancing</title><link>https://genhttp.org/samples/load-balancing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/load-balancing/</guid><description>&lt;p&gt;Spreads the requests to an API over three workers and sends downloads to one of two mirror servers.&#10;&lt;code&gt;Proxy&lt;/code&gt; forwards a request to a worker and passes its response on; &lt;code&gt;Redirect&lt;/code&gt; sends the client to a mirror,&#10;so downloads do not pass through this server.&lt;/p&gt;&#10;&lt;p&gt;A priority decides where a request may go: requests with an &lt;code&gt;X-Canary&lt;/code&gt; header prefer the third worker,&#10;which can run a new version you want to test with some real traffic first. Everything else goes to the&#10;other two workers, which share the load.&lt;/p&gt;</description></item><item><title>Single Page Applications</title><link>https://genhttp.org/samples/spa/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/spa/</guid><description>&lt;p&gt;Hosts a single page application, such as the build output of a React, Angular or Vue app. With&#10;&lt;code&gt;ServerSideRouting()&lt;/code&gt;, every path that is no file is answered with the &lt;code&gt;index.html&lt;/code&gt; of the application, so&#10;it can render routes such as &lt;code&gt;/books/42&lt;/code&gt; in the browser - even when they are opened directly or reloaded.&lt;/p&gt;&#10;&lt;p&gt;Put the build output of your application into a &lt;code&gt;spa&lt;/code&gt; folder next to the program.&lt;/p&gt;</description></item><item><title>Custom Frameworks</title><link>https://genhttp.org/samples/custom-framework/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://genhttp.org/samples/custom-framework/</guid><description>&lt;p&gt;Shows the layer that webservices, controllers and functional handlers are built on, to write a framework of&#10;your own - for example one that offers scripts or database queries as endpoints. The handler describes an&#10;operation - a path, its HTTP methods and the C# method to call - and GenHTTP reads the arguments, calls the&#10;method and writes the result.&lt;/p&gt;&#10;&lt;p&gt;As the operation is one like any other, the Open API definition and Scalar describe it as well. The reflection&#10;layer counts as internal, so it may change in a minor version.&lt;/p&gt;</description></item></channel></rss>