# Getting Started
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
| 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
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 (`true` 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
Clone the repo, then install the npm dependencies that the build needs:
```bash
cd Htmx.ApiDemo
npm install
```
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.
---
## Run the app
From the repository root:
```bash
dotnet run --project Htmx.ApiDemo/Htmx.ApiDemo.csproj
```
The app listens on `http://localhost:5120` by default (configured in `Htmx.ApiDemo/Properties/launchSettings.json`).
---
## Verify it works
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 happens at startup
`Program.cs` wires up the following in order:
- MongoDB service registration and index initialization (`EnsureIndexesAsync`)
- Cookie-based authentication and authorization
- Antiforgery middleware
- AOT-compatible JSON serialization via `AppJsonSerializerContext`
- All generated HTMX endpoints via `app.MapHtmxApiDemoEndpoints()`
---
## Build details
- **Tailwind** is compiled into `wwwroot/css/output.css` as a pre-build step.
- **`.htmx` files** are passed to the source generator as ``. 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
```
---
## Troubleshooting
### Build fails — Tailwind command not found
Run `npm install` inside the `Htmx.ApiDemo` directory. Confirm `node` and `npm` are on your `PATH`.
### MongoDB connection errors at startup
- Confirm the MongoDB service is running (`mongod`).
- Check that `ConnectionStrings:DefaultConnection` in `appsettings.json` points to `mongodb://localhost:27017`.
### App always redirects to `/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.