Rewrote all the docs - more noob friendly now.
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
+155
-41
@@ -1,32 +1,141 @@
|
||||
# Getting Started
|
||||
|
||||
This guide gets the solution running locally and explains what happens during startup.
|
||||
This guide walks you through everything you need to get the project running locally — from installing tools to understanding why certain architectural decisions were made.
|
||||
|
||||
---
|
||||
|
||||
## What is in this solution
|
||||
|
||||
- `Htmx.ApiDemo`: ASP.NET Core app (Minimal API + generated HTMX endpoints)
|
||||
- `Htmx.SourceGenerator`: Roslyn source generator that discovers `.htmx` files and generates endpoint mapping code
|
||||
- `Htmx.slnx`: solution file at the repository root
|
||||
| Project | Purpose |
|
||||
|---|---|
|
||||
| `Htmx.ApiDemo` | ASP.NET Core web app using Minimal APIs and server-rendered HTMX templates |
|
||||
| `Htmx.SourceGenerator` | Roslyn source generator that reads `.htmx` template files and generates endpoint mapping code at build time |
|
||||
|
||||
The solution file is `Htmx.slnx` at the repository root.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- .NET SDK 10.x (target framework is `net10.0`)
|
||||
- Node.js + npm (used for Tailwind CSS compilation during build)
|
||||
- MongoDB running locally on `mongodb://localhost:27017`
|
||||
Install the following before cloning the repo.
|
||||
|
||||
### .NET SDK
|
||||
|
||||
The project targets `net10.0`. Download the .NET 10 SDK from [dot.net](https://dotnet.microsoft.com/download).
|
||||
|
||||
Verify with:
|
||||
|
||||
```bash
|
||||
dotnet --version
|
||||
```
|
||||
|
||||
### Node.js and npm
|
||||
|
||||
Tailwind CSS is compiled during the build using the Tailwind CLI via `npx`. Node.js must be installed.
|
||||
|
||||
Download from [nodejs.org](https://nodejs.org). Verify with:
|
||||
|
||||
```bash
|
||||
node -v
|
||||
npm -v
|
||||
```
|
||||
|
||||
### MongoDB
|
||||
|
||||
The app stores data in MongoDB. You need a local instance running on `mongodb://localhost:27017`.
|
||||
|
||||
**Windows:**
|
||||
|
||||
Download and install [MongoDB Community Server](https://www.mongodb.com/try/download/community). During installation, choose to run MongoDB as a Windows Service so it starts automatically.
|
||||
|
||||
**Linux:**
|
||||
|
||||
Follow the official guide for your distro at [docs.mongodb.com/manual/administration/install-on-linux](https://www.mongodb.com/docs/manual/administration/install-on-linux/). For Ubuntu/Debian:
|
||||
|
||||
```bash
|
||||
sudo systemctl start mongod
|
||||
sudo systemctl enable mongod # start on boot
|
||||
```
|
||||
|
||||
**MongoDB Compass (optional but recommended):**
|
||||
|
||||
Compass is a GUI for browsing and querying your MongoDB data. Download it from [mongodb.com/products/compass](https://www.mongodb.com/products/compass). Connect it to `mongodb://localhost:27017` to inspect collections while developing.
|
||||
|
||||
---
|
||||
|
||||
## VS Code setup
|
||||
|
||||
### Required extensions
|
||||
|
||||
- **C# Dev Kit** — provides IntelliSense, debugging, and project support for .NET
|
||||
Search for `ms-dotnettools.csdevkit` in the Extensions panel.
|
||||
|
||||
- **C# (OmniSharp / Roslyn)** — included with C# Dev Kit but can also be installed standalone as `ms-dotnettools.csharp`.
|
||||
|
||||
### Recommended settings
|
||||
|
||||
Add the following to your workspace or user `settings.json`. This teaches VS Code to treat `.htmx` files as HTML (for syntax highlighting and formatting) and nests generated companion files under their parent in the Explorer sidebar so the file tree stays clean.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"files.associations": {
|
||||
"*.htmx": "html"
|
||||
},
|
||||
"explorer.fileNesting.enabled": true,
|
||||
"explorer.fileNesting.expand": false,
|
||||
"explorer.fileNesting.patterns": {
|
||||
"*.razor": "$(capture).razor.cs, $(capture).razor.css, $(capture).razor.js",
|
||||
"*.htmx": "${capture}.htmx.cs, ${capture}.htmx.routing.cs, ${capture}.g.cs, ${capture}.css"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Without `files.associations`, `.htmx` files open as plain text with no highlighting. Without file nesting, every generated `.htmx.cs` and `.htmx.routing.cs` file appears as a separate top-level entry in the Explorer, making it hard to navigate.
|
||||
|
||||
### Optional extension
|
||||
|
||||
- **Tailwind CSS Fold** — collapses long Tailwind class strings in the editor so markup is easier to read. Search for `stivo.tailwind-fold`. This is purely a cosmetic convenience and has no effect on the build.
|
||||
|
||||
---
|
||||
|
||||
## Understanding AOT
|
||||
|
||||
AOT (Ahead-of-Time compilation) means the app is compiled to native machine code before it runs, rather than relying on the .NET JIT at runtime. This project has AOT enabled (`<PublishAot>true</PublishAot>` in the `.csproj`).
|
||||
|
||||
### Why AOT matters here
|
||||
|
||||
AOT produces smaller, faster deployments with no JIT warmup time. For a web app handling many requests, startup time and binary size are real concerns — especially in containerized or serverless environments.
|
||||
|
||||
### What AOT prevents you from doing
|
||||
|
||||
AOT is a significant constraint. It eliminates entire categories of patterns that are common in standard .NET development:
|
||||
|
||||
- **No Entity Framework Core** — EF Core relies heavily on runtime reflection and expression compilation. It is not AOT-compatible. This project uses the MongoDB driver directly instead.
|
||||
|
||||
- **No runtime reflection** — `Type.GetProperties()`, `Activator.CreateInstance()`, dynamic proxies, and similar patterns do not work (or produce warnings/errors) under AOT. If a pattern depends on inspecting types at runtime, it will not survive.
|
||||
|
||||
- **Many NuGet packages are incompatible** — Any package that uses reflection internally (serializers, mappers, validators, ORMs, DI containers with convention scanning, etc.) may break. Check a package's AOT compatibility before adding it.
|
||||
|
||||
- **Source generator-based serialization required** — Rather than `JsonSerializer.Serialize(myObject)` discovering properties at runtime, you must register types with a `JsonSerializerContext` subclass (see `AppJsonSerializerContext.cs`). The serializer then uses generated code instead of reflection.
|
||||
|
||||
- **Route handler code generation** — ASP.NET Core's Minimal API generator produces code for request binding and response writing. Some third-party packages produce code that conflicts with this. If adding a package causes build errors in generated files, AOT incompatibility is the likely cause.
|
||||
|
||||
The practical rule: before reaching for a package or pattern you know from standard ASP.NET Core, check whether it is AOT-compatible. The project will compile normally in Debug mode even with AOT-incompatible code — AOT issues typically only surface during `dotnet publish`.
|
||||
|
||||
---
|
||||
|
||||
## First-time setup
|
||||
|
||||
From the repository root:
|
||||
Clone the repo, then install the npm dependencies that the build needs:
|
||||
|
||||
```bash
|
||||
cd Htmx.ApiDemo
|
||||
npm install
|
||||
```
|
||||
|
||||
Why this is required:
|
||||
This installs the Tailwind CSS CLI package. The build runs `npx @tailwindcss/cli` as an MSBuild step, so if this is skipped the build will fail with a missing command error.
|
||||
|
||||
- The app build runs Tailwind via `npx @tailwindcss/cli ...` in a custom MSBuild target.
|
||||
- Without `npm install`, build fails because the Tailwind CLI package is missing.
|
||||
---
|
||||
|
||||
## Run the app
|
||||
|
||||
@@ -36,57 +145,62 @@ From the repository root:
|
||||
dotnet run --project Htmx.ApiDemo/Htmx.ApiDemo.csproj
|
||||
```
|
||||
|
||||
Default local URL:
|
||||
The app listens on `http://localhost:5120` by default (configured in `Htmx.ApiDemo/Properties/launchSettings.json`).
|
||||
|
||||
- `http://localhost:5120`
|
||||
|
||||
This comes from the launch profile in `Htmx.ApiDemo/Properties/launchSettings.json`.
|
||||
---
|
||||
|
||||
## Verify it works
|
||||
|
||||
1. Open `http://localhost:5120`
|
||||
2. If you are not authenticated, middleware redirects to `/login`
|
||||
3. Create an account at `/register`
|
||||
4. Sign in and navigate the app
|
||||
1. Open `http://localhost:5120` in your browser.
|
||||
2. If you are not signed in, the middleware redirects you to `/login` — this is expected.
|
||||
3. Go to `/register` and create an account.
|
||||
4. Sign in and explore the app.
|
||||
|
||||
## What startup config does
|
||||
---
|
||||
|
||||
`Htmx.ApiDemo/Program.cs` configures:
|
||||
## What happens at startup
|
||||
|
||||
- MongoDB DI and index initialization (`EnsureIndexesAsync`)
|
||||
- Cookie authentication + authorization
|
||||
`Program.cs` wires up the following in order:
|
||||
|
||||
- MongoDB service registration and index initialization (`EnsureIndexesAsync`)
|
||||
- Cookie-based authentication and authorization
|
||||
- Antiforgery middleware
|
||||
- AOT-friendly JSON resolver chain using `AppJsonSerializerContext`
|
||||
- Endpoint registration via generated mapping call:
|
||||
- `app.MapHtmxApiDemoEndpoints();`
|
||||
- AOT-compatible JSON serialization via `AppJsonSerializerContext`
|
||||
- All generated HTMX endpoints via `app.MapHtmxApiDemoEndpoints()`
|
||||
|
||||
## Build behavior worth knowing
|
||||
---
|
||||
|
||||
- Tailwind CSS is compiled before build into `Htmx.ApiDemo/wwwroot/css/output.css`
|
||||
- `.htmx` files are treated as generator inputs (`<AdditionalFiles Include="**/*.htmx" />`)
|
||||
- AOT is enabled (`<PublishAot>true</PublishAot>`), so reflection-heavy patterns can break publish/runtime
|
||||
## Build details
|
||||
|
||||
## Optional: publish as AOT
|
||||
- **Tailwind** is compiled into `wwwroot/css/output.css` as a pre-build step.
|
||||
- **`.htmx` files** are passed to the source generator as `<AdditionalFiles>`. The generator reads them and produces the abstract base classes and routing code.
|
||||
- **AOT** is active on publish. Run a publish build early and often to catch incompatibilities before they accumulate.
|
||||
|
||||
### Publish (AOT)
|
||||
|
||||
```bash
|
||||
dotnet publish Htmx.ApiDemo/Htmx.ApiDemo.csproj -c Release
|
||||
```
|
||||
|
||||
Use this early to catch AOT issues while developing features.
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build fails on Tailwind command
|
||||
### Build fails — Tailwind command not found
|
||||
|
||||
- Run `npm install` inside `Htmx.ApiDemo`
|
||||
- Confirm `node -v` and `npm -v` are available
|
||||
Run `npm install` inside the `Htmx.ApiDemo` directory. Confirm `node` and `npm` are on your `PATH`.
|
||||
|
||||
### Mongo connection errors
|
||||
### MongoDB connection errors at startup
|
||||
|
||||
- Confirm MongoDB is running on `localhost:27017`
|
||||
- Confirm `ConnectionStrings:DefaultConnection` in `Htmx.ApiDemo/appsettings.json`
|
||||
- Confirm the MongoDB service is running (`mongod`).
|
||||
- Check that `ConnectionStrings:DefaultConnection` in `appsettings.json` points to `mongodb://localhost:27017`.
|
||||
|
||||
### App keeps redirecting to login
|
||||
### App always redirects to `/login`
|
||||
|
||||
- This is expected for unauthenticated routes
|
||||
- Register at `/register` or sign in at `/login`
|
||||
This is intentional. Unauthenticated requests are redirected by the auth middleware. Register at `/register` first.
|
||||
|
||||
### AOT warnings or errors on publish
|
||||
|
||||
- Look at the warning message — it usually names the type or method causing the issue.
|
||||
- Remove or replace the offending package or pattern with an AOT-compatible alternative.
|
||||
- Run `dotnet publish` regularly during development so issues do not pile up.
|
||||
|
||||
Reference in New Issue
Block a user