diff --git a/src/content/docs/graphql/getting-started.mdx b/src/content/docs/graphql/getting-started.mdx index edc77b6..65ad555 100644 --- a/src/content/docs/graphql/getting-started.mdx +++ b/src/content/docs/graphql/getting-started.mdx @@ -57,9 +57,9 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ dotnet run --project ./src/Presentation ``` - It answers on `https://localhost:8081`. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + It answers on `https://localhost:7331`. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. -5. Open Nitro, the GraphQL IDE, at [https://localhost:8081/graphql](https://localhost:8081/graphql). The schema is on the left, with every type and field described, and the editor autocompletes as you type. Paste this in and press play: +5. Open Nitro, the GraphQL IDE, at [https://localhost:7331/graphql](https://localhost:7331/graphql). The schema is on the left, with every type and field described, and the editor autocompletes as you type. Paste this in and press play: ```graphql { @@ -74,7 +74,7 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ 6. Or ask from the terminal. ```bash - curl -X POST "https://localhost:8081/graphql" -H "Content-Type: application/json" \ + curl -X POST "https://localhost:7331/graphql" -H "Content-Type: application/json" \ -d '{"query":"{ movies(query: \"space\", first: 2) { totalCount nodes { id title reviewCount averageStars } } }"}' ``` diff --git a/src/content/docs/graphql/guides/add-a-field.mdx b/src/content/docs/graphql/guides/add-a-field.mdx index 3910ff9..1990b25 100644 --- a/src/content/docs/graphql/guides/add-a-field.mdx +++ b/src/content/docs/graphql/guides/add-a-field.mdx @@ -60,7 +60,7 @@ This guide adds `bestReview` to the `Movie` type: the highest rated review of th ```bash dotnet run --project ./src/Presentation - curl "https://localhost:8081/graphql?sdl" > tests/Presentation.Tests.Integration/GraphQL/Schema/schema.graphql + curl "https://localhost:7331/graphql?sdl" > tests/Presentation.Tests.Integration/GraphQL/Schema/schema.graphql ``` The diff is the one field, described: diff --git a/src/content/docs/graphql/guides/database.mdx b/src/content/docs/graphql/guides/database.mdx index 2d620b6..fca1b49 100644 --- a/src/content/docs/graphql/guides/database.mdx +++ b/src/content/docs/graphql/guides/database.mdx @@ -30,7 +30,7 @@ The next start builds a fresh database and seeds it again. Set `ConnectionStrings__MovieReviews`. To keep everything in memory, which is what the tests do: ```bash -docker run --rm -p 8080:8080 -e DOTNET_ENVIRONMENT=docker \ +docker run --rm -p 7330:7330 -e DOTNET_ENVIRONMENT=docker \ -e ConnectionStrings__MovieReviews="Data Source=MovieReviews;Mode=Memory;Cache=Shared" \ acme-movies:local ``` diff --git a/src/content/docs/graphql/guides/run-locally.mdx b/src/content/docs/graphql/guides/run-locally.mdx index 1c02489..fa51c50 100644 --- a/src/content/docs/graphql/guides/run-locally.mdx +++ b/src/content/docs/graphql/guides/run-locally.mdx @@ -17,19 +17,19 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data dotnet run --project ./src/Presentation ``` - `launchSettings.json` sets the environment to `local` and listens on [https://localhost:8081](https://localhost:8081), and on `https://localhost:8081`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7331](https://localhost:7331), and on `https://localhost:7331`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. ```bash docker compose up -d --build ``` - Compose builds the `run` stage, starts an OpenTelemetry Collector and the Aspire dashboard next to it, and publishes the API on [http://localhost:8080](http://localhost:8080). Shut it down with `docker compose down`, or `docker compose down -v` to drop the database too. + Compose builds the `run` stage, starts an OpenTelemetry Collector and the Aspire dashboard next to it, and publishes the API on [http://localhost:7330](http://localhost:7330). Shut it down with `docker compose down`, or `docker compose down -v` to drop the database too. ```bash docker build . --target run --tag acme-movies:local - docker run --rm -p 8080:8080 -e DOTNET_ENVIRONMENT=docker acme-movies:local + docker run --rm -p 7330:7330 -e DOTNET_ENVIRONMENT=docker acme-movies:local ``` Without Compose there's no collector, so the logs stay on the console and nothing else is exported. Set `OTEL_EXPORTER_OTLP_ENDPOINT` to send them to a collector of your own. @@ -44,19 +44,19 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data | `/graphql?sdl` | The schema in SDL, the same text the snapshot test checks | | `/health/live` | Answers 200 while the process is up | | `/health/ready` | Answers 200 when the database can be reached | -| [http://localhost:18888](http://localhost:18888) | The Aspire dashboard, with the logs, traces and metrics, when running with Docker Compose | +| [http://localhost:7332](http://localhost:7332) | The Aspire dashboard, with the logs, traces and metrics, when running with Docker Compose | The health endpoints answer without a token even when authentication is on, so a load balancer never needs to log in. ## See the telemetry -Docker Compose runs an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) beside the API, and the collector forwards everything to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888). Open **Traces** to follow a request from the HTTP request through the GraphQL operation to the use case, **Structured** for the logs, each linked to its trace, and **Metrics** for request durations, EF Core queries and the runtime. The dashboard keeps everything in memory, so it's empty again after a restart. The dashboard has no login, and the collector accepts OTLP from anyone on ports 4317 and 4318. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. +Docker Compose runs an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) beside the API, and the collector forwards everything to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7332](http://localhost:7332). Open **Traces** to follow a request from the HTTP request through the GraphQL operation to the use case, **Structured** for the logs, each linked to its trace, and **Metrics** for request durations, EF Core queries and the runtime. The dashboard keeps everything in memory, so it's empty again after a restart. The dashboard has no login, and the collector accepts OTLP from anyone on ports 7333 and 7334. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. The API only ever talks OTLP to the collector, and `otel-collector.yaml` decides where things go. To send them to a real backend, add its exporter there; the API doesn't change. To see a `dotnet run` in the dashboard, start the collector and point the API at it: ```bash docker compose up -d otel-collector -OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 dotnet run --project ./src/Presentation +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:7333 dotnet run --project ./src/Presentation ``` ## Try the schema @@ -117,5 +117,5 @@ docker build . --target run --tag acme-movies:latest \ The `version` query then reports `1.2.3-beta` and the commit it was built from. diff --git a/src/content/docs/graphql/guides/secure-the-api.mdx b/src/content/docs/graphql/guides/secure-the-api.mdx index 8561b56..6961112 100644 --- a/src/content/docs/graphql/guides/secure-the-api.mdx +++ b/src/content/docs/graphql/guides/secure-the-api.mdx @@ -30,7 +30,7 @@ Out of the box the API runs wide open, and there's no authentication code in it 2. Get a token from the authority for that audience, and send it. ```bash - curl -X POST "https://localhost:8081/graphql" -H "Authorization: Bearer eyJhbGciOi..." \ + curl -X POST "https://localhost:7331/graphql" -H "Authorization: Bearer eyJhbGciOi..." \ -H "Content-Type: application/json" -d '{"query":"{ movies { totalCount } }"}' ``` diff --git a/src/content/docs/graphql/guides/ship-the-container.mdx b/src/content/docs/graphql/guides/ship-the-container.mdx index 2567cae..099ae95 100644 --- a/src/content/docs/graphql/guides/ship-the-container.mdx +++ b/src/content/docs/graphql/guides/ship-the-container.mdx @@ -7,7 +7,7 @@ sidebar: import { Aside } from '@astrojs/starlight/components'; -The `run` stage of the `Dockerfile` is the whole API: one image, built on `mcr.microsoft.com/dotnet/aspnet:10.0-alpine`, that listens on port 8080 and runs as the image's non-root `app` user. It runs anywhere a container runs, which these days is everywhere, including a surprising number of fridges. +The `run` stage of the `Dockerfile` is the whole API: one image, built on `mcr.microsoft.com/dotnet/aspnet:10.0-alpine`, that listens on port 7330 and runs as the image's non-root `app` user. It runs anywhere a container runs, which these days is everywhere, including a surprising number of fridges. ## Build it @@ -58,5 +58,5 @@ The SQLite file lives in `/app/data`. Mount a volume there or, better, [point In In a solution created with `--include-auth`, set `Authentication__Authority` and `Authentication__Audience` as environment variables to point each environment at its own authorization server. Without `--include-auth` there's nothing to turn on yet. The [security guide](../secure-the-api/) has the details. diff --git a/src/content/docs/graphql/index.mdx b/src/content/docs/graphql/index.mdx index 4c012a2..4311e6b 100644 --- a/src/content/docs/graphql/index.mdx +++ b/src/content/docs/graphql/index.mdx @@ -44,7 +44,7 @@ cd WorksOnMyMachine.Movies docker compose up -d ``` -Then open Nitro, the GraphQL IDE, at [http://localhost:8080/graphql](http://localhost:8080/graphql) and start querying. The logs, traces and metrics go to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888), because `Console.WriteLine` is not an observability strategy. +Then open Nitro, the GraphQL IDE, at [http://localhost:7330/graphql](http://localhost:7330/graphql) and start querying. The logs, traces and metrics go to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7332](http://localhost:7332), because `Console.WriteLine` is not an observability strategy. Want it locked down? Add `--include-auth`, `--authority` and `--audience` when you create the solution and the movie, author and review queries and the review mutations need a JWT bearer token. Leave `--include-auth` off and there's no auth code at all, which is lovely on a laptop and less lovely in production. diff --git a/src/content/docs/graphql/reference/configuration.mdx b/src/content/docs/graphql/reference/configuration.mdx index 6c44903..aa489b3 100644 --- a/src/content/docs/graphql/reference/configuration.mdx +++ b/src/content/docs/graphql/reference/configuration.mdx @@ -12,7 +12,7 @@ Every setting in `appsettings.json` can be overridden with an environment variab | Variable | Default | Description | | --- | --- | --- | | `DOTNET_ENVIRONMENT` | none | Layers `appsettings..json` over `appsettings.json`. The template ships `local` and `docker` | -| `ASPNETCORE_URLS` | `http://+:8080` in the container | The addresses to listen on | +| `ASPNETCORE_HTTP_PORTS` | `7330` in the container | The port to listen on | | `ASPNETCORE_FORWARDEDHEADERS_ENABLED` | none | Set to `true` behind a proxy that ends TLS, so HTTPS redirection sees the original scheme | | `ConnectionStrings__MovieReviews` | `Data Source=movie-reviews.db` | The SQLite connection string. `appsettings.docker.json` points it at `/app/data/movie-reviews.db` | | `Database__SeedSampleData` | `false` | When `true`, seeds sample data into an empty database. On in `local` and `docker` | @@ -34,9 +34,11 @@ Every setting in `appsettings.json` can be overridden with an environment variab | Service | What it is | Port | | --- | --- | --- | -| `api` | The image, built from the `run` stage | 8080 | -| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 4317 (gRPC), 4318 (HTTP) | -| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 18888 | +| `api` | The image, built from the `run` stage | 7330, inside the container too | +| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 7333 (gRPC), 7334 (HTTP) | +| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 7332 | + +The ports are the ones on your machine. Each template has its own block of ten, so this one uses 7330 to 7339 and runs beside a solution made from any other template: Minimal API 7310, MCP 7320, GraphQL 7330, Web API 7340 and Lambda Function 7350. The app uses the same port inside its container; the dashboard and collector keep their usual ones. The `api` service runs with `DOTNET_ENVIRONMENT=docker`, mounts the `movie-reviews-data` volume at `/app/data`, and sends its logs, traces and metrics over OTLP to `otel-collector`, which forwards them to `aspire-dashboard`. @@ -55,4 +57,4 @@ Every span, metric and log also carries `service.version`, the version stamped i ## Ports when running with dotnet run -`src/Presentation/Properties/launchSettings.json` sets `DOTNET_ENVIRONMENT=local` and listens on `http://localhost:8080` and `https://localhost:8081`. +`src/Presentation/Properties/launchSettings.json` sets `DOTNET_ENVIRONMENT=local` and listens on `http://localhost:7330` and `https://localhost:7331`. diff --git a/src/content/docs/lambda/getting-started.mdx b/src/content/docs/lambda/getting-started.mdx index d993929..0a91bd5 100644 --- a/src/content/docs/lambda/getting-started.mdx +++ b/src/content/docs/lambda/getting-started.mdx @@ -57,10 +57,10 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) an docker compose up -d --build ``` -5. Invoke the function. The emulator listens on port 9000 and answers the same way Lambda does. +5. Invoke the function. The emulator listens on port 7350 and answers the same way Lambda does. ```bash - curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" \ + curl -X POST "http://localhost:7350/2015-03-31/functions/function/invocations" \ -d '{"query":"space","limit":2}' ``` diff --git a/src/content/docs/lambda/guides/add-a-function.mdx b/src/content/docs/lambda/guides/add-a-function.mdx index aa5c5b2..ac04c51 100644 --- a/src/content/docs/lambda/guides/add-a-function.mdx +++ b/src/content/docs/lambda/guides/add-a-function.mdx @@ -103,10 +103,10 @@ This guide adds a `GetMovie` function that returns one movie with all of its rev ```bash docker build . --target run --tag acme-reviews:local - docker run --rm -p 9000:8080 -e Database__SeedSampleData=true acme-reviews:local \ + docker run --rm -p 7350:8080 -e Database__SeedSampleData=true acme-reviews:local \ "Presentation::WorksOnMyMachine.Reviews.Presentation.LambdaFunction.Handler_GetMovie_Generated::GetMovie" - curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" \ + curl -X POST "http://localhost:7350/2015-03-31/functions/function/invocations" \ -d '{"id":"cb188ef6-14e7-f85f-2f78-924c2ab26b28"}' ``` diff --git a/src/content/docs/lambda/guides/database.mdx b/src/content/docs/lambda/guides/database.mdx index e9db935..9aef504 100644 --- a/src/content/docs/lambda/guides/database.mdx +++ b/src/content/docs/lambda/guides/database.mdx @@ -22,7 +22,7 @@ Every time a container starts, the handler applies any pending Entity Framework Set `ConnectionStrings__MovieReviews`. To keep everything in memory: ```bash -docker run --rm -p 9000:8080 \ +docker run --rm -p 7350:8080 \ -e ConnectionStrings__MovieReviews="Data Source=MovieReviews;Mode=Memory;Cache=Shared" \ -e Database__SeedSampleData=true \ acme-reviews:local diff --git a/src/content/docs/lambda/guides/run-locally.mdx b/src/content/docs/lambda/guides/run-locally.mdx index 5eda99b..da3db0f 100644 --- a/src/content/docs/lambda/guides/run-locally.mdx +++ b/src/content/docs/lambda/guides/run-locally.mdx @@ -17,12 +17,12 @@ The image is built on the [AWS Lambda .NET base image](https://gallery.ecr.aws/l docker compose up -d --build ``` - Compose builds the `run` stage, publishes port 9000, turns on sample data, and starts an OpenTelemetry Collector and the Aspire dashboard next to it. Shut it down with `docker compose down`. + Compose builds the `run` stage, publishes port 7350, turns on sample data, and starts an OpenTelemetry Collector and the Aspire dashboard next to it. Shut it down with `docker compose down`. ```bash docker build . --target run --tag acme-reviews:local - docker run --rm -p 9000:8080 -e Database__SeedSampleData=true acme-reviews:local + docker run --rm -p 7350:8080 -e Database__SeedSampleData=true acme-reviews:local ``` @@ -30,12 +30,12 @@ The image is built on the [AWS Lambda .NET base image](https://gallery.ecr.aws/l Then invoke it from another terminal: ```bash -curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"limit":5}' +curl -X POST "http://localhost:7350/2015-03-31/functions/function/invocations" -d '{"limit":5}' ``` ## See the telemetry -With Docker Compose, the function sends its traces, metrics and logs over OTLP to an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), which forwards them to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888). Each invocation is one trace: the function's span from the OpenTelemetry Lambda wrapper, with the use case under it. Traces and metrics are flushed before the function returns, so they're there by the time `curl` is. The logs still go to the console too, so `docker compose logs function` works as it always did. The dashboard has no login, and the collector accepts OTLP from anyone on ports 4317 and 4318. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. +With Docker Compose, the function sends its traces, metrics and logs over OTLP to an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), which forwards them to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7352](http://localhost:7352). Each invocation is one trace: the function's span from the OpenTelemetry Lambda wrapper, with the use case under it. Traces and metrics are flushed before the function returns, so they're there by the time `curl` is. The logs still go to the console too, so `docker compose logs function` works as it always did. The dashboard has no login, and the collector accepts OTLP from anyone on ports 7353 and 7354. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. Run the image on its own and nothing is exported, because `OTEL_EXPORTER_OTLP_ENDPOINT` isn't set. Set it to send the telemetry to a collector of your own. @@ -44,10 +44,10 @@ Run the image on its own and nothing is exported, because `OTEL_EXPORTER_OTLP_EN The image runs `GetMovies` by default. The same image also has `GetAuthors` and `GetReviews`. Pass the function's full handler name to `docker run` to start a different one. ```bash -docker run --rm -p 9000:8080 -e Database__SeedSampleData=true acme-reviews:local \ +docker run --rm -p 7350:8080 -e Database__SeedSampleData=true acme-reviews:local \ "Presentation::WorksOnMyMachine.Reviews.Presentation.LambdaFunction.Handler_GetReviews_Generated::GetReviews" -curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" \ +curl -X POST "http://localhost:7350/2015-03-31/functions/function/invocations" \ -d '{"movieId":"cb188ef6-14e7-f85f-2f78-924c2ab26b28","limit":2}' ``` @@ -85,5 +85,5 @@ docker build . --target run --tag acme-reviews:latest \ ``` diff --git a/src/content/docs/lambda/reference/configuration.mdx b/src/content/docs/lambda/reference/configuration.mdx index 8f8261a..84dace0 100644 --- a/src/content/docs/lambda/reference/configuration.mdx +++ b/src/content/docs/lambda/reference/configuration.mdx @@ -21,9 +21,11 @@ sidebar: | Service | What it is | Port | | --- | --- | --- | -| `function` | The image, built from the `run` stage, behind the runtime interface emulator | 9000 | -| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 4317 (gRPC), 4318 (HTTP) | -| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 18888 | +| `function` | The image, built from the `run` stage, behind the runtime interface emulator | 7350 (the emulator listens on 8080 inside the container) | +| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 7353 (gRPC), 7354 (HTTP) | +| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 7352 | + +The ports are the ones on your machine. Each template has its own block of ten, so this one uses 7350 to 7359 and runs beside a solution made from any other template: Minimal API 7310, MCP 7320, GraphQL 7330, Web API 7340 and Lambda Function 7350. Inside their containers the emulator, dashboard and collector keep their usual ports. ## Docker build arguments diff --git a/src/content/docs/mcp/getting-started.mdx b/src/content/docs/mcp/getting-started.mdx index ceb9d77..2bfbf7d 100644 --- a/src/content/docs/mcp/getting-started.mdx +++ b/src/content/docs/mcp/getting-started.mdx @@ -57,12 +57,12 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ dotnet run --project ./src/Presentation ``` - It answers on `https://localhost:8081`. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + It answers on `https://localhost:7321`. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. 5. Call a tool. The server speaks Streamable HTTP at `/mcp`, and because it's stateless you can send a single JSON-RPC request with nothing before it. ```bash - curl -X POST "https://localhost:8081/mcp" \ + curl -X POST "https://localhost:7321/mcp" \ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"movies_search","arguments":{"query":"space","limit":2}}}' ``` @@ -88,7 +88,7 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ docker compose up -d --build ``` - Open [http://localhost:6274](http://localhost:6274), connect, and the **Tools**, **Resources** and **Prompts** tabs show everything the server offers, with a form for each. + Open [http://localhost:7325](http://localhost:7325), connect, and the **Tools**, **Resources** and **Prompts** tabs show everything the server offers, with a form for each. 7. Run the tests while you're here. diff --git a/src/content/docs/mcp/guides/add-a-tool.mdx b/src/content/docs/mcp/guides/add-a-tool.mdx index e79ac3d..89a89a7 100644 --- a/src/content/docs/mcp/guides/add-a-tool.mdx +++ b/src/content/docs/mcp/guides/add-a-tool.mdx @@ -89,7 +89,7 @@ This guide adds `authors_get`, which returns one author with every review they'v ``` ```bash - curl -X POST "https://localhost:8081/mcp" \ + curl -X POST "https://localhost:7321/mcp" \ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"authors_get","arguments":{"authorId":"01fa8b58-05d2-abd4-e55c-2633222dd0a5"}}}' ``` diff --git a/src/content/docs/mcp/guides/connect-a-client.mdx b/src/content/docs/mcp/guides/connect-a-client.mdx index ce93e20..4c05cd0 100644 --- a/src/content/docs/mcp/guides/connect-a-client.mdx +++ b/src/content/docs/mcp/guides/connect-a-client.mdx @@ -7,14 +7,14 @@ sidebar: import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'; -The server speaks [Streamable HTTP](https://modelcontextprotocol.io/specification/latest/basic/transports), the current remote transport in the MCP spec, so any client that supports remote servers can connect to it. Start the server with Docker Compose and give the client `http://localhost:8080/mcp`. With `dotnet run` the address is `https://localhost:8081/mcp`, which needs a client that trusts the .NET development certificate, so Compose is the easier one to connect to. +The server speaks [Streamable HTTP](https://modelcontextprotocol.io/specification/latest/basic/transports), the current remote transport in the MCP spec, so any client that supports remote servers can connect to it. Start the server with Docker Compose and give the client `http://localhost:7320/mcp`. With `dotnet run` the address is `https://localhost:7321/mcp`, which needs a client that trusts the .NET development certificate, so Compose is the easier one to connect to. No client to hand? Docker Compose can start one for you: see [Chat with it](../run-locally/#chat-with-it). ```bash - claude mcp add --transport http acme-movies http://localhost:8080/mcp + claude mcp add --transport http acme-movies http://localhost:7320/mcp ``` Then ask it something like "which movie has the best reviews?" and watch it call `movies_search` and `movies_get` on its own. @@ -28,7 +28,7 @@ No client to hand? Docker Compose can start one for you: see [Chat with it](../r ```json { "servers": { - "acme-movies": { "type": "http", "url": "http://localhost:8080/mcp" } + "acme-movies": { "type": "http", "url": "http://localhost:7320/mcp" } } } ``` @@ -39,7 +39,7 @@ No client to hand? Docker Compose can start one for you: see [Chat with it](../r ```json { "mcpServers": { - "acme-movies": { "url": "http://localhost:8080/mcp" } + "acme-movies": { "url": "http://localhost:7320/mcp" } } } ``` @@ -51,7 +51,7 @@ No client to hand? Docker Compose can start one for you: see [Chat with it](../r using ModelContextProtocol.Client; await using var client = await McpClient.CreateAsync( - new HttpClientTransport(new HttpClientTransportOptions { Endpoint = new Uri("http://localhost:8080/mcp") })); + new HttpClientTransport(new HttpClientTransportOptions { Endpoint = new Uri("http://localhost:7320/mcp") })); var result = await client.CallToolAsync("movies_search", new Dictionary { ["query"] = "space" }); ``` diff --git a/src/content/docs/mcp/guides/database.mdx b/src/content/docs/mcp/guides/database.mdx index d532094..445f2e2 100644 --- a/src/content/docs/mcp/guides/database.mdx +++ b/src/content/docs/mcp/guides/database.mdx @@ -30,7 +30,7 @@ The next start builds a fresh database and seeds it again. Set `ConnectionStrings__MovieReviews`. To keep everything in memory, which is what the tests do: ```bash -docker run --rm -p 8080:8080 -e DOTNET_ENVIRONMENT=docker \ +docker run --rm -p 7320:7320 -e DOTNET_ENVIRONMENT=docker \ -e ConnectionStrings__MovieReviews="Data Source=MovieReviews;Mode=Memory;Cache=Shared" \ acme-movies:local ``` diff --git a/src/content/docs/mcp/guides/run-locally.mdx b/src/content/docs/mcp/guides/run-locally.mdx index f98e078..2e64fc8 100644 --- a/src/content/docs/mcp/guides/run-locally.mdx +++ b/src/content/docs/mcp/guides/run-locally.mdx @@ -17,19 +17,19 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data dotnet run --project ./src/Presentation ``` - `launchSettings.json` sets the environment to `local` and listens on [https://localhost:8081](https://localhost:8081), and on `https://localhost:8081`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. The server is at `/mcp`. + `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7321](https://localhost:7321), and on `https://localhost:7321`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. The server is at `/mcp`. ```bash docker compose up -d --build ``` - Compose builds the `run` stage, starts the MCP Inspector, an OpenTelemetry Collector and the Aspire dashboard next to it, and publishes the server on [http://localhost:8080/mcp](http://localhost:8080/mcp). Shut it down with `docker compose down`, or `docker compose down -v` to drop the database too. + Compose builds the `run` stage, starts the MCP Inspector, an OpenTelemetry Collector and the Aspire dashboard next to it, and publishes the server on [http://localhost:7320/mcp](http://localhost:7320/mcp). Shut it down with `docker compose down`, or `docker compose down -v` to drop the database too. ```bash docker build . --target run --tag acme-movies:local - docker run --rm -p 8080:8080 -e DOTNET_ENVIRONMENT=docker acme-movies:local + docker run --rm -p 7320:7320 -e DOTNET_ENVIRONMENT=docker acme-movies:local ``` Without Compose there's no collector, so the logs stay on the console and nothing else is exported. Set `OTEL_EXPORTER_OTLP_ENDPOINT` to send them to a collector of your own. @@ -44,21 +44,21 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data | `/health/live` | Answers 200 while the process is up | | `/health/ready` | Answers 200 when the database can be reached | | `/.well-known/oauth-protected-resource/mcp` | Protected resource metadata, only when [authentication is on](../secure-the-server/) | -| [http://localhost:6274](http://localhost:6274) | The MCP Inspector, when running with Docker Compose | -| [http://localhost:3000](http://localhost:3000) | Open WebUI, when running with Docker Compose and the `demo` profile | -| [http://localhost:18888](http://localhost:18888) | The Aspire dashboard, with the logs, traces and metrics, when running with Docker Compose | +| [http://localhost:7325](http://localhost:7325) | The MCP Inspector, when running with Docker Compose | +| [http://localhost:7326](http://localhost:7326) | Open WebUI, when running with Docker Compose and the `demo` profile | +| [http://localhost:7322](http://localhost:7322) | The Aspire dashboard, with the logs, traces and metrics, when running with Docker Compose | The health endpoints answer without a token even when authentication is on, so a load balancer never needs to log in. ## Use the Inspector -The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is the official test client, and Docker Compose runs it already pointed at `http://api:8080/mcp`. Open it, press **Connect**, and: +The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is the official test client, and Docker Compose runs it already pointed at `http://api:7320/mcp`. Open it, press **Connect**, and: - **Tools** lists every tool with its description, annotations and input schema, and gives you a form to call it. A result lists its movies, authors and reviews under **Resource Links**, and expanding one reads it. - **Resources** lets you read `movies://top-rated`, `server://version` or any `movies://`, `authors://` or `reviews://` URI, and the ids autocomplete as you type an id or a title. - **Prompts** renders each prompt with its arguments, and the title, name and id arguments autocomplete from the database. -Running with `dotnet run` instead? Start the Inspector yourself with `npx @modelcontextprotocol/inspector` and point it at `https://localhost:8081/mcp`. Node doesn't read the system's trusted certificates by default, so if it can't connect, use Docker Compose instead. +Running with `dotnet run` instead? Start the Inspector yourself with `npx @modelcontextprotocol/inspector` and point it at `https://localhost:7321/mcp`. Node doesn't read the system's trusted certificates by default, so if it can't connect, use Docker Compose instead. ## Chat with it @@ -68,36 +68,36 @@ Want to ask for things in plain English? The optional `demo` profile adds [Open docker compose --profile demo up -d --build ``` -Open [http://localhost:3000](http://localhost:3000), dismiss the release notes and ask it to list the movies. It uses Kilo's free gateway as the model, so there's no account or key, but it only works online, and your prompts and tool results go to Kilo, a third party. Keep it to sample data. Solutions created with `--include-auth` leave it out, because Open WebUI has no token to send. Stop it with `docker compose --profile demo down`. +Open [http://localhost:7326](http://localhost:7326), dismiss the release notes and ask it to list the movies. It uses Kilo's free gateway as the model, so there's no account or key, but it only works online, and your prompts and tool results go to Kilo, a third party. Keep it to sample data. Solutions created with `--include-auth` leave it out, because Open WebUI has no token to send. Stop it with `docker compose --profile demo down`. ## See the telemetry -Docker Compose runs an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) beside the server, and the collector forwards everything to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888). Open **Traces** to follow a request from the HTTP request through the tool call to the use case, **Structured** for the logs, each linked to its trace, and **Metrics** for request durations, EF Core queries and the runtime. The dashboard keeps everything in memory, so it's empty again after a restart. The dashboard has no login, and the collector accepts OTLP from anyone on ports 4317 and 4318. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. +Docker Compose runs an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) beside the server, and the collector forwards everything to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7322](http://localhost:7322). Open **Traces** to follow a request from the HTTP request through the tool call to the use case, **Structured** for the logs, each linked to its trace, and **Metrics** for request durations, EF Core queries and the runtime. The dashboard keeps everything in memory, so it's empty again after a restart. The dashboard has no login, and the collector accepts OTLP from anyone on ports 7323 and 7324. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. The server only ever talks OTLP to the collector, and `otel-collector.yaml` decides where things go. To send them to a real backend, add its exporter there; the server doesn't change. To see a `dotnet run` in the dashboard, start the collector and point the server at it: ```bash docker compose up -d otel-collector -OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 dotnet run --project ./src/Presentation +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:7323 dotnet run --project ./src/Presentation ``` ## Try the tools from the terminal -The server is stateless, so a single `tools/call` works without an `initialize` first. These use the `dotnet run` address; with Docker Compose, use `http://localhost:8080/mcp` instead. The sample data uses a fixed seed, so these ids are the same on every machine. See the [tool reference](../../reference/tools/) for every argument and result. +The server is stateless, so a single `tools/call` works without an `initialize` first. These use the `dotnet run` address; with Docker Compose, use `http://localhost:7320/mcp` instead. The sample data uses a fixed seed, so these ids are the same on every machine. See the [tool reference](../../reference/tools/) for every argument and result. ```bash # One movie, with every review -curl -X POST "https://localhost:8081/mcp" \ +curl -X POST "https://localhost:7321/mcp" \ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"movies_get","arguments":{"movieId":"cb188ef6-14e7-f85f-2f78-924c2ab26b28"}}}' # Write a review -curl -X POST "https://localhost:8081/mcp" \ +curl -X POST "https://localhost:7321/mcp" \ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"reviews_write","arguments":{"authorId":"01fa8b58-05d2-abd4-e55c-2633222dd0a5","movieId":"cb188ef6-14e7-f85f-2f78-924c2ab26b28","stars":5,"text":"Great film. I cried at the ending."}}}' # Read a resource -curl -X POST "https://localhost:8081/mcp" \ +curl -X POST "https://localhost:7321/mcp" \ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":3,"method":"resources/read","params":{"uri":"server://version"}}' ``` @@ -136,5 +136,5 @@ docker build . --target run --tag acme-movies:latest \ The `server://version` resource and the `serverInfo` in the initialize response then report `1.2.3-beta` and the commit it was built from. diff --git a/src/content/docs/mcp/guides/secure-the-server.mdx b/src/content/docs/mcp/guides/secure-the-server.mdx index bddd0af..2997a2f 100644 --- a/src/content/docs/mcp/guides/secure-the-server.mdx +++ b/src/content/docs/mcp/guides/secure-the-server.mdx @@ -42,7 +42,7 @@ Out of the box the server runs wide open, and there's no authentication code in 3. Get a token from the authority for that audience, and send it. ```bash - curl -X POST "https://localhost:8081/mcp" -H "Authorization: Bearer eyJhbGciOi..." \ + curl -X POST "https://localhost:7321/mcp" -H "Authorization: Bearer eyJhbGciOi..." \ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' ``` diff --git a/src/content/docs/mcp/guides/ship-the-container.mdx b/src/content/docs/mcp/guides/ship-the-container.mdx index b46623a..83c5187 100644 --- a/src/content/docs/mcp/guides/ship-the-container.mdx +++ b/src/content/docs/mcp/guides/ship-the-container.mdx @@ -7,7 +7,7 @@ sidebar: import { Aside } from '@astrojs/starlight/components'; -The `run` stage of the `Dockerfile` is the whole server: one image, built on `mcr.microsoft.com/dotnet/aspnet:10.0-alpine`, that listens on port 8080 and runs as the image's non-root `app` user. It runs anywhere a container runs, which these days is everywhere, including a surprising number of fridges. +The `run` stage of the `Dockerfile` is the whole server: one image, built on `mcr.microsoft.com/dotnet/aspnet:10.0-alpine`, that listens on port 7320 and runs as the image's non-root `app` user. It runs anywhere a container runs, which these days is everywhere, including a surprising number of fridges. ## Build it @@ -59,8 +59,8 @@ In a solution created with `--include-auth`, set `Authentication__Authority` and ## Leave the Inspector at home -`docker-compose.yml` starts the MCP Inspector next to the server because it's handy on a laptop. It's a development tool, not part of the server, so don't ship it. In production, the only thing listening is the server on port 8080. +`docker-compose.yml` starts the MCP Inspector next to the server because it's handy on a laptop. It's a development tool, not part of the server, so don't ship it. In production, the only thing listening is the server on port 7320. diff --git a/src/content/docs/mcp/index.mdx b/src/content/docs/mcp/index.mdx index 197c6b6..42272f4 100644 --- a/src/content/docs/mcp/index.mdx +++ b/src/content/docs/mcp/index.mdx @@ -44,7 +44,7 @@ cd WorksOnMyMachine.Movies docker compose up -d ``` -Then open the MCP Inspector at [http://localhost:6274](http://localhost:6274). It's already pointed at the server on [http://localhost:8080/mcp](http://localhost:8080/mcp), so connect, open **Tools** and start clicking. The logs, traces and metrics go to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888). +Then open the MCP Inspector at [http://localhost:7325](http://localhost:7325). It's already pointed at the server on [http://localhost:7320/mcp](http://localhost:7320/mcp), so connect, open **Tools** and start clicking. The logs, traces and metrics go to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7322](http://localhost:7322). Want it locked down? Add `--include-auth`, `--authority` and `--audience` when you create the solution and `/mcp` needs a bearer token, with protected resource metadata so MCP clients can find your authorization server and sign in. Leave `--include-auth` off and there's no auth code at all, which is lovely on a laptop and less lovely in production. diff --git a/src/content/docs/mcp/reference/configuration.mdx b/src/content/docs/mcp/reference/configuration.mdx index 71946eb..42861af 100644 --- a/src/content/docs/mcp/reference/configuration.mdx +++ b/src/content/docs/mcp/reference/configuration.mdx @@ -12,7 +12,7 @@ Every setting in `appsettings.json` can be overridden with an environment variab | Variable | Default | Description | | --- | --- | --- | | `DOTNET_ENVIRONMENT` | none | Layers `appsettings..json` over `appsettings.json`. The template ships `local` and `docker` | -| `ASPNETCORE_URLS` | `http://+:8080` in the container | The addresses to listen on | +| `ASPNETCORE_HTTP_PORTS` | `7320` in the container | The port to listen on | | `ASPNETCORE_FORWARDEDHEADERS_ENABLED` | none | Set to `true` behind a proxy that ends TLS, so HTTPS redirection sees the original scheme | | `ConnectionStrings__MovieReviews` | `Data Source=movie-reviews.db` | The SQLite connection string. `appsettings.docker.json` points it at `/app/data/movie-reviews.db` | | `Database__SeedSampleData` | `false` | When `true`, seeds sample data into an empty database. On in `local` and `docker` | @@ -35,10 +35,12 @@ Every setting in `appsettings.json` can be overridden with an environment variab | Service | What it is | Port | | --- | --- | --- | -| `api` | The image, built from the `run` stage | 8080 | -| `inspector` | The MCP Inspector, pointed at the server | 6274, on localhost only | -| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 4317 (gRPC), 4318 (HTTP) | -| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 18888 | +| `api` | The image, built from the `run` stage | 7320, inside the container too | +| `inspector` | The MCP Inspector, pointed at the server | 7325, on localhost only | +| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 7323 (gRPC), 7324 (HTTP) | +| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 7322 | + +The ports are the ones on your machine. Each template has its own block of ten, so this one uses 7320 to 7329 and runs beside a solution made from any other template: Minimal API 7310, MCP 7320, GraphQL 7330, Web API 7340 and Lambda Function 7350. The app and the Inspector use the same ports inside their containers. The dashboard and collector keep their usual ones. The `api` service runs with `DOTNET_ENVIRONMENT=docker`, mounts the `movie-reviews-data` volume at `/app/data`, and sends its logs, traces and metrics over OTLP to `otel-collector`, which forwards them to `aspire-dashboard`. @@ -57,4 +59,4 @@ Every span, metric and log also carries `service.version`, the version stamped i ## Ports when running with dotnet run -`src/Presentation/Properties/launchSettings.json` sets `DOTNET_ENVIRONMENT=local` and listens on `http://localhost:8080` and `https://localhost:8081`. +`src/Presentation/Properties/launchSettings.json` sets `DOTNET_ENVIRONMENT=local` and listens on `http://localhost:7320` and `https://localhost:7321`. diff --git a/src/content/docs/minimalapi/getting-started.mdx b/src/content/docs/minimalapi/getting-started.mdx index 159c89f..2587918 100644 --- a/src/content/docs/minimalapi/getting-started.mdx +++ b/src/content/docs/minimalapi/getting-started.mdx @@ -57,14 +57,14 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ dotnet run --project ./src/Presentation ``` - It answers on `https://localhost:8081`. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + It answers on `https://localhost:7311`. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. -5. Open the Scalar API reference at [https://localhost:8081/scalar](https://localhost:8081/scalar). Every endpoint is there with its parameters, responses and a **Send** button, so you never have to remember the shape of a request again. +5. Open the Scalar API reference at [https://localhost:7311/scalar](https://localhost:7311/scalar). Every endpoint is there with its parameters, responses and a **Send** button, so you never have to remember the shape of a request again. 6. Or call it from the terminal. ```bash - curl "https://localhost:8081/api/movies?query=space&limit=2" + curl "https://localhost:7311/api/movies?query=space&limit=2" ``` You get a page of movies back: diff --git a/src/content/docs/minimalapi/guides/add-an-endpoint.mdx b/src/content/docs/minimalapi/guides/add-an-endpoint.mdx index de14fe9..3cb7986 100644 --- a/src/content/docs/minimalapi/guides/add-an-endpoint.mdx +++ b/src/content/docs/minimalapi/guides/add-an-endpoint.mdx @@ -101,7 +101,7 @@ This guide adds `GET /api/movies/{id}/reviews`, one page of the reviews written ```bash dotnet test dotnet run --project ./src/Presentation - curl "https://localhost:8081/api/movies/cb188ef6-14e7-f85f-2f78-924c2ab26b28/reviews?limit=2" + curl "https://localhost:7311/api/movies/cb188ef6-14e7-f85f-2f78-924c2ab26b28/reviews?limit=2" ``` ```json diff --git a/src/content/docs/minimalapi/guides/database.mdx b/src/content/docs/minimalapi/guides/database.mdx index 2d620b6..0edef7b 100644 --- a/src/content/docs/minimalapi/guides/database.mdx +++ b/src/content/docs/minimalapi/guides/database.mdx @@ -30,7 +30,7 @@ The next start builds a fresh database and seeds it again. Set `ConnectionStrings__MovieReviews`. To keep everything in memory, which is what the tests do: ```bash -docker run --rm -p 8080:8080 -e DOTNET_ENVIRONMENT=docker \ +docker run --rm -p 7310:7310 -e DOTNET_ENVIRONMENT=docker \ -e ConnectionStrings__MovieReviews="Data Source=MovieReviews;Mode=Memory;Cache=Shared" \ acme-movies:local ``` diff --git a/src/content/docs/minimalapi/guides/run-locally.mdx b/src/content/docs/minimalapi/guides/run-locally.mdx index c4751cf..8502fe4 100644 --- a/src/content/docs/minimalapi/guides/run-locally.mdx +++ b/src/content/docs/minimalapi/guides/run-locally.mdx @@ -17,19 +17,19 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data dotnet run --project ./src/Presentation ``` - `launchSettings.json` sets the environment to `local` and listens on [https://localhost:8081](https://localhost:8081), and on `https://localhost:8081`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7311](https://localhost:7311), and on `https://localhost:7311`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. ```bash docker compose up -d --build ``` - Compose builds the `run` stage, starts an OpenTelemetry Collector and the Aspire dashboard next to it, and publishes the API on [http://localhost:8080](http://localhost:8080). Shut it down with `docker compose down`, or `docker compose down -v` to drop the database too. + Compose builds the `run` stage, starts an OpenTelemetry Collector and the Aspire dashboard next to it, and publishes the API on [http://localhost:7310](http://localhost:7310). Shut it down with `docker compose down`, or `docker compose down -v` to drop the database too. ```bash docker build . --target run --tag acme-movies:local - docker run --rm -p 8080:8080 -e DOTNET_ENVIRONMENT=docker acme-movies:local + docker run --rm -p 7310:7310 -e DOTNET_ENVIRONMENT=docker acme-movies:local ``` Without Compose there's no collector, so the logs stay on the console and nothing else is exported. Set `OTEL_EXPORTER_OTLP_ENDPOINT` to send them to a collector of your own. @@ -45,34 +45,34 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data | `/health/live` | Answers 200 while the process is up | | `/health/ready` | Answers 200 when the database can be reached | | `/api/version` | The version stamped into the build. Needs a token when authentication is on | -| [http://localhost:18888](http://localhost:18888) | The Aspire dashboard, with the logs, traces and metrics, when running with Docker Compose | +| [http://localhost:7312](http://localhost:7312) | The Aspire dashboard, with the logs, traces and metrics, when running with Docker Compose | The health endpoints answer without a token even when authentication is on, so a load balancer never needs to log in. ## See the telemetry -Docker Compose runs an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) beside the API, and the collector forwards everything to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888). Open **Traces** to follow a request from the HTTP request to the use case, **Structured** for the logs, each linked to its trace, and **Metrics** for request durations, EF Core queries and the runtime. The dashboard keeps everything in memory, so it's empty again after a restart. The dashboard has no login, and the collector accepts OTLP from anyone on ports 4317 and 4318. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. +Docker Compose runs an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) beside the API, and the collector forwards everything to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7312](http://localhost:7312). Open **Traces** to follow a request from the HTTP request to the use case, **Structured** for the logs, each linked to its trace, and **Metrics** for request durations, EF Core queries and the runtime. The dashboard keeps everything in memory, so it's empty again after a restart. The dashboard has no login, and the collector accepts OTLP from anyone on ports 7313 and 7314. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. The API only ever talks OTLP to the collector, and `otel-collector.yaml` decides where things go. To send them to a real backend, add its exporter there; the API doesn't change. To see a `dotnet run` in the dashboard, start the collector and point the API at it: ```bash docker compose up -d otel-collector -OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 dotnet run --project ./src/Presentation +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:7313 dotnet run --project ./src/Presentation ``` ## Try the endpoints -These use the `dotnet run` address; with Docker Compose, use `http://localhost:8080` instead. The sample data uses a fixed seed, so these ids are the same on every machine. See the [endpoint reference](../../reference/endpoints/) for every parameter and response. +These use the `dotnet run` address; with Docker Compose, use `http://localhost:7310` instead. The sample data uses a fixed seed, so these ids are the same on every machine. See the [endpoint reference](../../reference/endpoints/) for every parameter and response. ```bash # Search movies, two at a time -curl "https://localhost:8081/api/movies?query=space&limit=2" +curl "https://localhost:7311/api/movies?query=space&limit=2" # One movie, with its reviews -curl "https://localhost:8081/api/movies/cb188ef6-14e7-f85f-2f78-924c2ab26b28" +curl "https://localhost:7311/api/movies/cb188ef6-14e7-f85f-2f78-924c2ab26b28" # Write a review -curl -X POST "https://localhost:8081/api/reviews" -H "Content-Type: application/json" \ +curl -X POST "https://localhost:7311/api/reviews" -H "Content-Type: application/json" \ -d '{"authorId":"01fa8b58-05d2-abd4-e55c-2633222dd0a5","movieId":"cb188ef6-14e7-f85f-2f78-924c2ab26b28","stars":5,"text":"Great film. I cried at the ending."}' ``` @@ -110,5 +110,5 @@ docker build . --target run --tag acme-movies:latest \ `GET /api/version` then reports `1.2.3-beta` and the commit it was built from. diff --git a/src/content/docs/minimalapi/guides/secure-the-api.mdx b/src/content/docs/minimalapi/guides/secure-the-api.mdx index 47aa2c7..6c56f2d 100644 --- a/src/content/docs/minimalapi/guides/secure-the-api.mdx +++ b/src/content/docs/minimalapi/guides/secure-the-api.mdx @@ -30,7 +30,7 @@ Out of the box the API runs wide open, and there's no authentication code in it 2. Get a token from the authority for that audience, and send it. ```bash - curl "https://localhost:8081/api/movies" -H "Authorization: Bearer eyJhbGciOi..." + curl "https://localhost:7311/api/movies" -H "Authorization: Bearer eyJhbGciOi..." ``` Without a token, or with one from the wrong issuer or for the wrong audience, the API answers `401 Unauthorized`. diff --git a/src/content/docs/minimalapi/guides/ship-the-container.mdx b/src/content/docs/minimalapi/guides/ship-the-container.mdx index f80f264..3ab936e 100644 --- a/src/content/docs/minimalapi/guides/ship-the-container.mdx +++ b/src/content/docs/minimalapi/guides/ship-the-container.mdx @@ -7,7 +7,7 @@ sidebar: import { Aside } from '@astrojs/starlight/components'; -The `run` stage of the `Dockerfile` is the whole API: one image, built on `mcr.microsoft.com/dotnet/aspnet:10.0-alpine`, that listens on port 8080 and runs as the image's non-root `app` user. It runs anywhere a container runs, which these days is everywhere, including a surprising number of fridges. +The `run` stage of the `Dockerfile` is the whole API: one image, built on `mcr.microsoft.com/dotnet/aspnet:10.0-alpine`, that listens on port 7310 and runs as the image's non-root `app` user. It runs anywhere a container runs, which these days is everywhere, including a surprising number of fridges. ## Build it @@ -58,5 +58,5 @@ The SQLite file lives in `/app/data`. Mount a volume there or, better, [point In In a solution created with `--include-auth`, set `Authentication__Authority` and `Authentication__Audience` as environment variables to point each environment at its own authorization server. Without `--include-auth` there's nothing to turn on yet. The [security guide](../secure-the-api/) has the details. diff --git a/src/content/docs/minimalapi/index.mdx b/src/content/docs/minimalapi/index.mdx index 84bdd69..1f46b6f 100644 --- a/src/content/docs/minimalapi/index.mdx +++ b/src/content/docs/minimalapi/index.mdx @@ -44,7 +44,7 @@ cd WorksOnMyMachine.Movies docker compose up -d ``` -Then open the Scalar API reference at [http://localhost:8080/scalar](http://localhost:8080/scalar) and start poking. The logs, traces and metrics go to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888), because `Console.WriteLine` is not an observability strategy. +Then open the Scalar API reference at [http://localhost:7310/scalar](http://localhost:7310/scalar) and start poking. The logs, traces and metrics go to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7312](http://localhost:7312), because `Console.WriteLine` is not an observability strategy. Want it locked down? Add `--include-auth`, `--authority` and `--audience` when you create the solution and every movie, author and review endpoint needs a JWT bearer token. Leave `--include-auth` off and there's no auth code at all, which is lovely on a laptop and less lovely in production. diff --git a/src/content/docs/minimalapi/reference/configuration.mdx b/src/content/docs/minimalapi/reference/configuration.mdx index 863ca90..87d85d0 100644 --- a/src/content/docs/minimalapi/reference/configuration.mdx +++ b/src/content/docs/minimalapi/reference/configuration.mdx @@ -12,7 +12,7 @@ Every setting in `appsettings.json` can be overridden with an environment variab | Variable | Default | Description | | --- | --- | --- | | `DOTNET_ENVIRONMENT` | none | Layers `appsettings..json` over `appsettings.json`. The template ships `local` and `docker` | -| `ASPNETCORE_URLS` | `http://+:8080` in the container | The addresses to listen on | +| `ASPNETCORE_HTTP_PORTS` | `7310` in the container | The port to listen on | | `ASPNETCORE_FORWARDEDHEADERS_ENABLED` | none | Set to `true` behind a proxy that ends TLS, so HTTPS redirection sees the original scheme | | `ConnectionStrings__MovieReviews` | `Data Source=movie-reviews.db` | The SQLite connection string. `appsettings.docker.json` points it at `/app/data/movie-reviews.db` | | `Database__SeedSampleData` | `false` | When `true`, seeds sample data into an empty database. On in `local` and `docker` | @@ -34,9 +34,11 @@ Every setting in `appsettings.json` can be overridden with an environment variab | Service | What it is | Port | | --- | --- | --- | -| `api` | The image, built from the `run` stage | 8080 | -| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 4317 (gRPC), 4318 (HTTP) | -| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 18888 | +| `api` | The image, built from the `run` stage | 7310, inside the container too | +| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 7313 (gRPC), 7314 (HTTP) | +| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 7312 | + +The ports are the ones on your machine. Each template has its own block of ten, so this one uses 7310 to 7319 and runs beside a solution made from any other template: Minimal API 7310, MCP 7320, GraphQL 7330, Web API 7340 and Lambda Function 7350. The app uses the same port inside its container; the dashboard and collector keep their usual ones. The `api` service runs with `DOTNET_ENVIRONMENT=docker`, mounts the `movie-reviews-data` volume at `/app/data`, and sends its logs, traces and metrics over OTLP to `otel-collector`, which forwards them to `aspire-dashboard`. @@ -55,4 +57,4 @@ Every span, metric and log also carries `service.version`, the version stamped i ## Ports when running with dotnet run -`src/Presentation/Properties/launchSettings.json` sets `DOTNET_ENVIRONMENT=local` and listens on `http://localhost:8080` and `https://localhost:8081`. +`src/Presentation/Properties/launchSettings.json` sets `DOTNET_ENVIRONMENT=local` and listens on `http://localhost:7310` and `https://localhost:7311`. diff --git a/src/content/docs/minimalapi/reference/endpoints.mdx b/src/content/docs/minimalapi/reference/endpoints.mdx index 0816b4e..305658a 100644 --- a/src/content/docs/minimalapi/reference/endpoints.mdx +++ b/src/content/docs/minimalapi/reference/endpoints.mdx @@ -7,7 +7,7 @@ sidebar: Every endpoint lives in `src/Presentation/Endpoints`, one static class per feature. Requests and responses are JSON with camelCase property names, read case-insensitively. Properties with no value are left out of responses. In a solution created with `--include-auth`, every endpoint except health needs a token (see [Secure the API](../../guides/secure-the-api/)). -The OpenAPI document at `/openapi/v1.json` describes all of this too, and Scalar at `/scalar` lets you call it. The examples use the `dotnet run` address, `https://localhost:8081`; with Docker Compose it's `http://localhost:8080`. +The OpenAPI document at `/openapi/v1.json` describes all of this too, and Scalar at `/scalar` lets you call it. The examples use the `dotnet run` address, `https://localhost:7311`; with Docker Compose it's `http://localhost:7310`. | Method | Route | Returns | | --- | --- | --- | @@ -35,7 +35,7 @@ Lists movies ordered by title, one page at a time, optionally only those whose t | `limit` | integer | `10` | 1 to 50 | ```bash -curl "https://localhost:8081/api/movies?query=space&limit=2" +curl "https://localhost:7311/api/movies?query=space&limit=2" ``` ```json @@ -92,7 +92,7 @@ Lists reviews ordered by movie then author, one page at a time. Filter by movie, | `limit` | integer | `10` | 1 to 50 | ```bash -curl "https://localhost:8081/api/reviews?movieId=cb188ef6-14e7-f85f-2f78-924c2ab26b28&limit=2" +curl "https://localhost:7311/api/reviews?movieId=cb188ef6-14e7-f85f-2f78-924c2ab26b28&limit=2" ``` ```json @@ -108,7 +108,7 @@ curl "https://localhost:8081/api/reviews?movieId=cb188ef6-14e7-f85f-2f78-924c2ab ``` ```bash -curl "https://localhost:8081/api/reviews?query=funny&minStars=4&limit=2" +curl "https://localhost:7311/api/reviews?query=funny&minStars=4&limit=2" ``` ```json @@ -139,7 +139,7 @@ Creates a review. The author and the movie must already exist. | `text` | string | Optional. Up to 1000 characters | ```bash -curl -X POST "https://localhost:8081/api/reviews" -H "Content-Type: application/json" \ +curl -X POST "https://localhost:7311/api/reviews" -H "Content-Type: application/json" \ -d '{"authorId":"01fa8b58-05d2-abd4-e55c-2633222dd0a5","movieId":"cb188ef6-14e7-f85f-2f78-924c2ab26b28","stars":5,"text":"Great film. I cried at the ending."}' ``` diff --git a/src/content/docs/webapi/getting-started.mdx b/src/content/docs/webapi/getting-started.mdx index 8511294..bfe3f9e 100644 --- a/src/content/docs/webapi/getting-started.mdx +++ b/src/content/docs/webapi/getting-started.mdx @@ -57,14 +57,14 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ dotnet run --project ./src/Presentation ``` - It answers on `https://localhost:8081`. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + It answers on `https://localhost:7341`. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. -5. Open the Scalar API reference at [https://localhost:8081/scalar](https://localhost:8081/scalar). Every endpoint is there with its parameters, responses and a **Send** button, so you never have to remember the shape of a request again. +5. Open the Scalar API reference at [https://localhost:7341/scalar](https://localhost:7341/scalar). Every endpoint is there with its parameters, responses and a **Send** button, so you never have to remember the shape of a request again. 6. Or call it from the terminal. ```bash - curl "https://localhost:8081/api/movies?query=space&limit=2" + curl "https://localhost:7341/api/movies?query=space&limit=2" ``` You get a page of movies back: diff --git a/src/content/docs/webapi/guides/add-an-endpoint.mdx b/src/content/docs/webapi/guides/add-an-endpoint.mdx index 9c40c57..0c23e89 100644 --- a/src/content/docs/webapi/guides/add-an-endpoint.mdx +++ b/src/content/docs/webapi/guides/add-an-endpoint.mdx @@ -95,7 +95,7 @@ This guide adds `GET /api/movies/{id}/reviews`, one page of the reviews written ```bash dotnet test dotnet run --project ./src/Presentation - curl "https://localhost:8081/api/movies/cb188ef6-14e7-f85f-2f78-924c2ab26b28/reviews?limit=2" + curl "https://localhost:7341/api/movies/cb188ef6-14e7-f85f-2f78-924c2ab26b28/reviews?limit=2" ``` ```json diff --git a/src/content/docs/webapi/guides/database.mdx b/src/content/docs/webapi/guides/database.mdx index 2d620b6..dc4aed6 100644 --- a/src/content/docs/webapi/guides/database.mdx +++ b/src/content/docs/webapi/guides/database.mdx @@ -30,7 +30,7 @@ The next start builds a fresh database and seeds it again. Set `ConnectionStrings__MovieReviews`. To keep everything in memory, which is what the tests do: ```bash -docker run --rm -p 8080:8080 -e DOTNET_ENVIRONMENT=docker \ +docker run --rm -p 7340:7340 -e DOTNET_ENVIRONMENT=docker \ -e ConnectionStrings__MovieReviews="Data Source=MovieReviews;Mode=Memory;Cache=Shared" \ acme-movies:local ``` diff --git a/src/content/docs/webapi/guides/run-locally.mdx b/src/content/docs/webapi/guides/run-locally.mdx index c4751cf..d3454f2 100644 --- a/src/content/docs/webapi/guides/run-locally.mdx +++ b/src/content/docs/webapi/guides/run-locally.mdx @@ -17,19 +17,19 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data dotnet run --project ./src/Presentation ``` - `launchSettings.json` sets the environment to `local` and listens on [https://localhost:8081](https://localhost:8081), and on `https://localhost:8081`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7341](https://localhost:7341), and on `https://localhost:7341`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. ```bash docker compose up -d --build ``` - Compose builds the `run` stage, starts an OpenTelemetry Collector and the Aspire dashboard next to it, and publishes the API on [http://localhost:8080](http://localhost:8080). Shut it down with `docker compose down`, or `docker compose down -v` to drop the database too. + Compose builds the `run` stage, starts an OpenTelemetry Collector and the Aspire dashboard next to it, and publishes the API on [http://localhost:7340](http://localhost:7340). Shut it down with `docker compose down`, or `docker compose down -v` to drop the database too. ```bash docker build . --target run --tag acme-movies:local - docker run --rm -p 8080:8080 -e DOTNET_ENVIRONMENT=docker acme-movies:local + docker run --rm -p 7340:7340 -e DOTNET_ENVIRONMENT=docker acme-movies:local ``` Without Compose there's no collector, so the logs stay on the console and nothing else is exported. Set `OTEL_EXPORTER_OTLP_ENDPOINT` to send them to a collector of your own. @@ -45,34 +45,34 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data | `/health/live` | Answers 200 while the process is up | | `/health/ready` | Answers 200 when the database can be reached | | `/api/version` | The version stamped into the build. Needs a token when authentication is on | -| [http://localhost:18888](http://localhost:18888) | The Aspire dashboard, with the logs, traces and metrics, when running with Docker Compose | +| [http://localhost:7342](http://localhost:7342) | The Aspire dashboard, with the logs, traces and metrics, when running with Docker Compose | The health endpoints answer without a token even when authentication is on, so a load balancer never needs to log in. ## See the telemetry -Docker Compose runs an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) beside the API, and the collector forwards everything to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888). Open **Traces** to follow a request from the HTTP request to the use case, **Structured** for the logs, each linked to its trace, and **Metrics** for request durations, EF Core queries and the runtime. The dashboard keeps everything in memory, so it's empty again after a restart. The dashboard has no login, and the collector accepts OTLP from anyone on ports 4317 and 4318. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. +Docker Compose runs an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) beside the API, and the collector forwards everything to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7342](http://localhost:7342). Open **Traces** to follow a request from the HTTP request to the use case, **Structured** for the logs, each linked to its trace, and **Metrics** for request durations, EF Core queries and the runtime. The dashboard keeps everything in memory, so it's empty again after a restart. The dashboard has no login, and the collector accepts OTLP from anyone on ports 7343 and 7344. That's on purpose, so there's nothing to sign in to on your machine, and it's why the compose file is for your machine only. Don't run it anywhere other people can reach. The API only ever talks OTLP to the collector, and `otel-collector.yaml` decides where things go. To send them to a real backend, add its exporter there; the API doesn't change. To see a `dotnet run` in the dashboard, start the collector and point the API at it: ```bash docker compose up -d otel-collector -OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 dotnet run --project ./src/Presentation +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:7343 dotnet run --project ./src/Presentation ``` ## Try the endpoints -These use the `dotnet run` address; with Docker Compose, use `http://localhost:8080` instead. The sample data uses a fixed seed, so these ids are the same on every machine. See the [endpoint reference](../../reference/endpoints/) for every parameter and response. +These use the `dotnet run` address; with Docker Compose, use `http://localhost:7340` instead. The sample data uses a fixed seed, so these ids are the same on every machine. See the [endpoint reference](../../reference/endpoints/) for every parameter and response. ```bash # Search movies, two at a time -curl "https://localhost:8081/api/movies?query=space&limit=2" +curl "https://localhost:7341/api/movies?query=space&limit=2" # One movie, with its reviews -curl "https://localhost:8081/api/movies/cb188ef6-14e7-f85f-2f78-924c2ab26b28" +curl "https://localhost:7341/api/movies/cb188ef6-14e7-f85f-2f78-924c2ab26b28" # Write a review -curl -X POST "https://localhost:8081/api/reviews" -H "Content-Type: application/json" \ +curl -X POST "https://localhost:7341/api/reviews" -H "Content-Type: application/json" \ -d '{"authorId":"01fa8b58-05d2-abd4-e55c-2633222dd0a5","movieId":"cb188ef6-14e7-f85f-2f78-924c2ab26b28","stars":5,"text":"Great film. I cried at the ending."}' ``` @@ -110,5 +110,5 @@ docker build . --target run --tag acme-movies:latest \ `GET /api/version` then reports `1.2.3-beta` and the commit it was built from. diff --git a/src/content/docs/webapi/guides/secure-the-api.mdx b/src/content/docs/webapi/guides/secure-the-api.mdx index 834308f..34d4f3c 100644 --- a/src/content/docs/webapi/guides/secure-the-api.mdx +++ b/src/content/docs/webapi/guides/secure-the-api.mdx @@ -30,7 +30,7 @@ Out of the box the API runs wide open, and there's no authentication code in it 2. Get a token from the authority for that audience, and send it. ```bash - curl "https://localhost:8081/api/movies" -H "Authorization: Bearer eyJhbGciOi..." + curl "https://localhost:7341/api/movies" -H "Authorization: Bearer eyJhbGciOi..." ``` Without a token, or with one from the wrong issuer or for the wrong audience, the API answers `401 Unauthorized`. diff --git a/src/content/docs/webapi/guides/ship-the-container.mdx b/src/content/docs/webapi/guides/ship-the-container.mdx index f80f264..f06e1fc 100644 --- a/src/content/docs/webapi/guides/ship-the-container.mdx +++ b/src/content/docs/webapi/guides/ship-the-container.mdx @@ -7,7 +7,7 @@ sidebar: import { Aside } from '@astrojs/starlight/components'; -The `run` stage of the `Dockerfile` is the whole API: one image, built on `mcr.microsoft.com/dotnet/aspnet:10.0-alpine`, that listens on port 8080 and runs as the image's non-root `app` user. It runs anywhere a container runs, which these days is everywhere, including a surprising number of fridges. +The `run` stage of the `Dockerfile` is the whole API: one image, built on `mcr.microsoft.com/dotnet/aspnet:10.0-alpine`, that listens on port 7340 and runs as the image's non-root `app` user. It runs anywhere a container runs, which these days is everywhere, including a surprising number of fridges. ## Build it @@ -58,5 +58,5 @@ The SQLite file lives in `/app/data`. Mount a volume there or, better, [point In In a solution created with `--include-auth`, set `Authentication__Authority` and `Authentication__Audience` as environment variables to point each environment at its own authorization server. Without `--include-auth` there's nothing to turn on yet. The [security guide](../secure-the-api/) has the details. diff --git a/src/content/docs/webapi/index.mdx b/src/content/docs/webapi/index.mdx index c351ac8..53d9a07 100644 --- a/src/content/docs/webapi/index.mdx +++ b/src/content/docs/webapi/index.mdx @@ -44,7 +44,7 @@ cd WorksOnMyMachine.Movies docker compose up -d ``` -Then open the Scalar API reference at [http://localhost:8080/scalar](http://localhost:8080/scalar) and start poking. The logs, traces and metrics go to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:18888](http://localhost:18888), because `Console.WriteLine` is not an observability strategy. +Then open the Scalar API reference at [http://localhost:7340/scalar](http://localhost:7340/scalar) and start poking. The logs, traces and metrics go to the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at [http://localhost:7342](http://localhost:7342), because `Console.WriteLine` is not an observability strategy. Want it locked down? Add `--include-auth`, `--authority` and `--audience` when you create the solution and every movie, author and review endpoint needs a JWT bearer token. Leave `--include-auth` off and there's no auth code at all, which is lovely on a laptop and less lovely in production. diff --git a/src/content/docs/webapi/reference/configuration.mdx b/src/content/docs/webapi/reference/configuration.mdx index 1f617ee..4867295 100644 --- a/src/content/docs/webapi/reference/configuration.mdx +++ b/src/content/docs/webapi/reference/configuration.mdx @@ -12,7 +12,7 @@ Every setting in `appsettings.json` can be overridden with an environment variab | Variable | Default | Description | | --- | --- | --- | | `DOTNET_ENVIRONMENT` | none | Layers `appsettings..json` over `appsettings.json`. The template ships `local` and `docker` | -| `ASPNETCORE_URLS` | `http://+:8080` in the container | The addresses to listen on | +| `ASPNETCORE_HTTP_PORTS` | `7340` in the container | The port to listen on | | `ASPNETCORE_FORWARDEDHEADERS_ENABLED` | none | Set to `true` behind a proxy that ends TLS, so HTTPS redirection sees the original scheme | | `ConnectionStrings__MovieReviews` | `Data Source=movie-reviews.db` | The SQLite connection string. `appsettings.docker.json` points it at `/app/data/movie-reviews.db` | | `Database__SeedSampleData` | `false` | When `true`, seeds sample data into an empty database. On in `local` and `docker` | @@ -34,9 +34,11 @@ Every setting in `appsettings.json` can be overridden with an environment variab | Service | What it is | Port | | --- | --- | --- | -| `api` | The image, built from the `run` stage | 8080 | -| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 4317 (gRPC), 4318 (HTTP) | -| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 18888 | +| `api` | The image, built from the `run` stage | 7340, inside the container too | +| `otel-collector` | The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/), configured by `otel-collector.yaml` | 7343 (gRPC), 7344 (HTTP) | +| `aspire-dashboard` | The [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone), where the collector sends everything | 7342 | + +The ports are the ones on your machine. Each template has its own block of ten, so this one uses 7340 to 7349 and runs beside a solution made from any other template: Minimal API 7310, MCP 7320, GraphQL 7330, Web API 7340 and Lambda Function 7350. The app uses the same port inside its container; the dashboard and collector keep their usual ones. The `api` service runs with `DOTNET_ENVIRONMENT=docker`, mounts the `movie-reviews-data` volume at `/app/data`, and sends its logs, traces and metrics over OTLP to `otel-collector`, which forwards them to `aspire-dashboard`. @@ -55,4 +57,4 @@ Every span, metric and log also carries `service.version`, the version stamped i ## Ports when running with dotnet run -`src/Presentation/Properties/launchSettings.json` sets `DOTNET_ENVIRONMENT=local` and listens on `http://localhost:8080` and `https://localhost:8081`. +`src/Presentation/Properties/launchSettings.json` sets `DOTNET_ENVIRONMENT=local` and listens on `http://localhost:7340` and `https://localhost:7341`. diff --git a/src/content/docs/webapi/reference/endpoints.mdx b/src/content/docs/webapi/reference/endpoints.mdx index 4edc682..c5a2240 100644 --- a/src/content/docs/webapi/reference/endpoints.mdx +++ b/src/content/docs/webapi/reference/endpoints.mdx @@ -7,7 +7,7 @@ sidebar: Every endpoint lives in `src/Presentation/Controllers`, one controller per feature. Requests and responses are JSON with camelCase property names, read case-insensitively. Properties with no value are left out of responses. In a solution created with `--include-auth`, every endpoint except health needs a token (see [Secure the API](../../guides/secure-the-api/)). -The OpenAPI document at `/openapi/v1.json` describes all of this too, and Scalar at `/scalar` lets you call it. The examples use the `dotnet run` address, `https://localhost:8081`; with Docker Compose it's `http://localhost:8080`. +The OpenAPI document at `/openapi/v1.json` describes all of this too, and Scalar at `/scalar` lets you call it. The examples use the `dotnet run` address, `https://localhost:7341`; with Docker Compose it's `http://localhost:7340`. | Method | Route | Returns | | --- | --- | --- | @@ -35,7 +35,7 @@ Lists movies ordered by title, one page at a time, optionally only those whose t | `limit` | integer | `10` | 1 to 50 | ```bash -curl "https://localhost:8081/api/movies?query=space&limit=2" +curl "https://localhost:7341/api/movies?query=space&limit=2" ``` ```json @@ -92,7 +92,7 @@ Lists reviews ordered by movie then author, one page at a time. Filter by movie, | `limit` | integer | `10` | 1 to 50 | ```bash -curl "https://localhost:8081/api/reviews?movieId=cb188ef6-14e7-f85f-2f78-924c2ab26b28&limit=2" +curl "https://localhost:7341/api/reviews?movieId=cb188ef6-14e7-f85f-2f78-924c2ab26b28&limit=2" ``` ```json @@ -108,7 +108,7 @@ curl "https://localhost:8081/api/reviews?movieId=cb188ef6-14e7-f85f-2f78-924c2ab ``` ```bash -curl "https://localhost:8081/api/reviews?query=funny&minStars=4&limit=2" +curl "https://localhost:7341/api/reviews?query=funny&minStars=4&limit=2" ``` ```json @@ -139,7 +139,7 @@ Creates a review. The author and the movie must already exist. | `text` | string | Optional. Up to 1000 characters | ```bash -curl -X POST "https://localhost:8081/api/reviews" -H "Content-Type: application/json" \ +curl -X POST "https://localhost:7341/api/reviews" -H "Content-Type: application/json" \ -d '{"authorId":"01fa8b58-05d2-abd4-e55c-2633222dd0a5","movieId":"cb188ef6-14e7-f85f-2f78-924c2ab26b28","stars":5,"text":"Great film. I cried at the ending."}' ```