Conversation
Import 11 file-based Aspire samples from davidfowl/aspire-13-samples, normalize their AppHost package directives to 13.2.2, flatten image-gallery under samples/, and add the new entries to the root sample index. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
c44bd61 to
50ab10d
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Imports multiple Aspire 13.x file-based samples (TypeScript AppHosts and polyglot services), normalizes pinned package directives/SDK versions, and updates the build + catalog to recognize and build the new sample shapes.
Changes:
- Added new samples (polyglot task queue, Node+Redis, Go API, image gallery) including their AppHosts, services, and frontends.
- Updated build pipeline to detect/build single-file TypeScript AppHosts (
apphost.ts) alongside single-file C# AppHosts (apphost.cs). - Updated root README sample catalog with the newly imported samples.
Reviewed changes
Copilot reviewed 84 out of 218 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| samples/polyglot-task-queue/worker-python/pyproject.toml | Adds Python worker packaging (deps + dev deps) for the sample. |
| samples/polyglot-task-queue/worker-python/main.py | Implements Python RabbitMQ worker with OpenTelemetry propagation. |
| samples/polyglot-task-queue/worker-python/.python-version | Pins Python version for the sample. |
| samples/polyglot-task-queue/worker-csharp/worker-csharp.csproj | Adds C# worker project and NuGet dependencies. |
| samples/polyglot-task-queue/worker-csharp/Program.cs | Implements C# RabbitMQ worker with OpenTelemetry context propagation. |
| samples/polyglot-task-queue/worker-csharp/Extensions.cs | Adds “service defaults” helpers (OTel, health checks, discovery). |
| samples/polyglot-task-queue/tsconfig.apphost.json | TypeScript build config for the TS AppHost. |
| samples/polyglot-task-queue/package.json | Defines Node tooling/scripts for the TS AppHost (lint/build/start). |
| samples/polyglot-task-queue/frontend/vite.config.ts | Configures Vite dev proxy for the task queue UI. |
| samples/polyglot-task-queue/frontend/tsconfig.node.json | TS config for Vite config typing/build. |
| samples/polyglot-task-queue/frontend/tsconfig.json | TS config for the React frontend. |
| samples/polyglot-task-queue/frontend/src/style.css | Adds UI styling for the task queue frontend. |
| samples/polyglot-task-queue/frontend/src/main.tsx | React entrypoint for the task queue UI. |
| samples/polyglot-task-queue/frontend/src/App.tsx | Implements the task queue UI and polling logic. |
| samples/polyglot-task-queue/frontend/package.json | Frontend dependencies and build scripts. |
| samples/polyglot-task-queue/frontend/index.html | HTML entry for the Vite React frontend. |
| samples/polyglot-task-queue/eslint.config.mjs | ESLint config for the TS AppHost. |
| samples/polyglot-task-queue/aspire.config.json | Pins Aspire SDK/packages and declares TS AppHost configuration. |
| samples/polyglot-task-queue/apphost.ts | TypeScript AppHost wiring RabbitMQ, API, frontend, and workers. |
| samples/polyglot-task-queue/api/telemetry.js | Adds alternate Node OTel setup file for the API. |
| samples/polyglot-task-queue/api/package.json | Declares Node API dependencies including OpenTelemetry and AMQP. |
| samples/polyglot-task-queue/api/instrumentation.js | Adds Node OTel SDK initialization and exporter wiring. |
| samples/polyglot-task-queue/api/index.js | Implements Express API + RabbitMQ consumers/publishers with tracing. |
| samples/polyglot-task-queue/api/Properties/launchSettings.json | Local dev launch settings for the Node API project folder. |
| samples/polyglot-task-queue/README.md | Documents sample architecture, run/deploy commands, and patterns. |
| samples/polyglot-task-queue/.aspire/settings.json | Aspire tooling settings for the sample. |
| samples/node-express-redis/tsconfig.apphost.json | TypeScript build config for the TS AppHost. |
| samples/node-express-redis/package.json | Node tooling/scripts for the TS AppHost. |
| samples/node-express-redis/frontend/vite.config.ts | Configures Vite dev proxy for the visit counter UI. |
| samples/node-express-redis/frontend/tsconfig.node.json | TS config for Vite config typing/build. |
| samples/node-express-redis/frontend/tsconfig.json | TS config for the React frontend. |
| samples/node-express-redis/frontend/src/style.css | Adds UI styling for the visit counter frontend. |
| samples/node-express-redis/frontend/src/main.tsx | React entrypoint for the visit counter UI. |
| samples/node-express-redis/frontend/src/App.tsx | Implements visit counter UI and API calls. |
| samples/node-express-redis/frontend/package.json | Frontend dependencies and build scripts. |
| samples/node-express-redis/frontend/index.html | HTML entry for the Vite React frontend. |
| samples/node-express-redis/eslint.config.mjs | ESLint config for the TS AppHost. |
| samples/node-express-redis/aspire.config.json | Pins Aspire SDK/packages and declares TS AppHost configuration. |
| samples/node-express-redis/apphost.ts | TypeScript AppHost wiring Redis, API, frontend, and YARP. |
| samples/node-express-redis/api/package.json | Node API dependencies for Express + Redis. |
| samples/node-express-redis/api/index.js | Implements Express API with Redis-backed counters. |
| samples/node-express-redis/README.md | Documents sample architecture and Aspire patterns. |
| samples/node-express-redis/.aspire/settings.json | Aspire tooling settings for the sample. |
| samples/image-gallery/worker/worker.csproj | Adds image gallery worker project and dependencies. |
| samples/image-gallery/worker/appsettings.json | Worker logging configuration. |
| samples/image-gallery/worker/Services/ThumbnailWorker.cs | Implements queue-driven thumbnail generation worker. |
| samples/image-gallery/worker/Properties/launchSettings.json | Local dev launch settings for worker. |
| samples/image-gallery/worker/Program.cs | Worker host wiring (service defaults, storage, SQL, hosted service). |
| samples/image-gallery/worker/Models/Image.cs | Worker-side EF model for images. |
| samples/image-gallery/worker/Data/ImageDbContext.cs | Worker EF Core DbContext configuration. |
| samples/image-gallery/shared/Extensions.cs | Shared “service defaults” helpers for API/worker. |
| samples/image-gallery/frontend/vite.config.ts | Vite proxy to backend API for local dev. |
| samples/image-gallery/frontend/tsconfig.node.json | TS config for Vite config typing/build. |
| samples/image-gallery/frontend/tsconfig.json | TS config for the React frontend. |
| samples/image-gallery/frontend/src/main.tsx | React entrypoint for image gallery UI. |
| samples/image-gallery/frontend/src/App.tsx | Implements upload/gallery UI including antiforgery token usage. |
| samples/image-gallery/frontend/src/App.css | UI styling for image gallery. |
| samples/image-gallery/frontend/package.json | Frontend dependencies and build scripts. |
| samples/image-gallery/frontend/index.html | HTML entry for the Vite React frontend. |
| samples/image-gallery/apphost.run.json | Run-time launch profile for the C# AppHost. |
| samples/image-gallery/apphost.cs | C# AppHost wiring Azure resources, API, frontend, and job worker. |
| samples/image-gallery/api/api.csproj | Adds image gallery API project and dependencies. |
| samples/image-gallery/api/Services/DatabaseInitializer.cs | Adds startup database init/migration hosted service. |
| samples/image-gallery/api/Properties/launchSettings.json | Local dev launch settings for API. |
| samples/image-gallery/api/Program.cs | API host wiring including antiforgery, OpenAPI, and endpoints. |
| samples/image-gallery/api/Models/ImageDto.cs | Adds DTO for image API responses. |
| samples/image-gallery/api/Models/Image.cs | API-side EF model for images. |
| samples/image-gallery/api/Extensions/ImageEndpoints.cs | Implements image API endpoints including upload/delete/streaming. |
| samples/image-gallery/api/Data/ImageDbContext.cs | API EF Core DbContext configuration. |
| samples/image-gallery/README.md | Documents event-triggered job architecture and security notes. |
| samples/image-gallery/.aspire/settings.json | Aspire tooling settings for the sample. |
| samples/golang-api/tsconfig.apphost.json | TypeScript build config for the TS AppHost. |
| samples/golang-api/package.json | Node tooling/scripts for the TS AppHost. |
| samples/golang-api/eslint.config.mjs | ESLint config for the TS AppHost. |
| samples/golang-api/aspire.config.json | Pins Aspire SDK and declares TS AppHost configuration. |
| samples/golang-api/apphost.ts | TypeScript AppHost that runs Go locally and Dockerfile on publish. |
| samples/golang-api/api/main.go | Implements Go chi REST API with in-memory store. |
| samples/golang-api/api/go.mod | Go module definition and dependency. |
| samples/golang-api/api/Dockerfile | Dockerfile for publishing the Go API. |
| samples/golang-api/README.md | Documents sample behavior and patterns. |
| samples/golang-api/.editorconfig | Suppresses a diagnostic for Dockerfile builder evaluation types. |
| samples/golang-api/.aspire/settings.json | Aspire tooling settings for the sample. |
| build/Build.proj | Updates sample build to also restore/build TS apphost.ts samples. |
| README.md | Adds newly imported samples to the root sample catalog. |
Files not reviewed (8)
- samples/golang-api/package-lock.json: Language not supported
- samples/image-gallery/frontend/package-lock.json: Language not supported
- samples/node-express-redis/api/package-lock.json: Language not supported
- samples/node-express-redis/frontend/package-lock.json: Language not supported
- samples/node-express-redis/package-lock.json: Language not supported
- samples/polyglot-task-queue/api/package-lock.json: Language not supported
- samples/polyglot-task-queue/frontend/package-lock.json: Language not supported
- samples/polyglot-task-queue/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
samples/node-express-redis/.aspire/settings.json:1
- This directory contains a TypeScript AppHost (
apphost.ts), but the Aspire settings referenceapphost.cs. PointappHostPathto../apphost.tsso Aspire tooling runs the intended AppHost.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| group.MapGet("/images/{id}/thumbnail", async ( | ||
| int id, | ||
| ImageDbContext db, | ||
| BlobContainerClient containerClient) => | ||
| { | ||
| var image = await db.Images.FindAsync(id); | ||
| if (image is null || image.ThumbnailUrl is null) | ||
| { | ||
| return Results.NotFound(); | ||
| } | ||
|
|
||
| var thumbnailName = image.ThumbnailUrl.Split('/').Last(); | ||
| var blobClient = containerClient.GetBlobClient(thumbnailName); | ||
|
|
||
| var download = await blobClient.DownloadStreamingAsync(); | ||
| return Results.Stream(download.Value.Content, image.ContentType); | ||
| }); |
There was a problem hiding this comment.
The worker saves thumbnails as JPEG (SaveAsJpegAsync), but the API serves the thumbnail with the original image’s ContentType. This can cause incorrect Content-Type headers and broken rendering/caching (e.g., PNG original but JPEG thumbnail). Either store a thumbnail content-type (and use it here) or serve thumbnails consistently as image/jpeg and ensure the thumbnail blob name/extension aligns with that.
| // Upload image | ||
| group.MapPost("/images", async ( | ||
| IFormFile file, | ||
| ImageDbContext db, | ||
| BlobContainerClient containerClient, | ||
| QueueServiceClient queueService, | ||
| ILogger<Program> logger) => | ||
| { |
There was a problem hiding this comment.
The sample fetches and sends antiforgery tokens from the frontend, but these endpoints don’t appear to be marked to require antiforgery validation. With app.UseAntiforgery(), minimal API endpoints typically need antiforgery metadata (e.g., RequireAntiforgeryToken) to enforce checks. Add antiforgery requirements to the POST/DELETE endpoints so the stated XSRF protection is actually enforced.
| <span className="task-count"> | ||
| {tasks.filter(t => t.status === 'queued').length} queued,{' '} | ||
| {tasks.filter(t => t.status === 'completed').length} completed | ||
| </span> |
There was a problem hiding this comment.
The workers/API publish statuses like processing, skipped, and error, but the UI only styles/counts queued, completed, and failed. This means error tasks won’t be counted/styled correctly (and failed may never be produced). Either standardize on a single status vocabulary across services (e.g., use failed everywhere) or update the UI to handle error/processing/skipped consistently (badges + counts).
| **OpenTelemetry** - Automatic configuration via environment variables: | ||
| - `OTEL_EXPORTER_OTLP_ENDPOINT`: Aspire dashboard endpoint | ||
| - `OTEL_SERVICE_NAME`: Service identifier for traces | ||
|
|
There was a problem hiding this comment.
The comment claims withReference(rabbitmq) injects RABBITMQ_URI, but the resource name used in the AppHost is "messaging" and the services read MESSAGING_URI. Update the README to reflect the actual injected env var name to avoid confusing readers.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
|
||
| - name: Build | ||
| run: ${{ matrix.os == 'ubuntu-latest' && './build/build.sh' || '.\build\build.cmd' }} | ||
| - name: Restore TypeScript AppHosts |
| @@ -0,0 +1,3 @@ | |||
| { | |||
| "appHostPath": "../apphost.ts" | |||
There was a problem hiding this comment.
We should remove this now right?
| @@ -0,0 +1,3 @@ | |||
| { | |||
| "appHostPath": "../apphost.cs" | |||
There was a problem hiding this comment.
Where is aspire.config.json?
| | [Azure Functions](./samples/aspire-with-azure-functions) | C# | ASP.NET Core, Blazor, Azure Functions, Azure Blob Storage | Shows how to integrate [Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-overview) with Aspire. | | ||
| | [Image Gallery](./samples/image-gallery) | C#, JavaScript, TypeScript | Azure Blob Storage, Azure Queues, Azure SQL, Container Apps Jobs | Upload and process images with event-triggered thumbnail generation using Azure resources and local emulators. | | ||
| | [Go API](./samples/golang-api) | Go, C# | Go, chi, Containers | Shows a custom Go integration for running and publishing a Go API with Aspire. | | ||
| | [Node + Redis + Vite](./samples/node-express-redis) | JavaScript, TypeScript, C# | Express, Redis, React, YARP | Visit counter sample with an Express API, Redis, and a Vite frontend served through YARP. | |
There was a problem hiding this comment.
A few of the new rows in this section still list C# in Languages Used even when the sample is actually TypeScript-hosted and has no C# project (for example node-express-redis, golang-api, python-fastapi-postgres, python-openai-agent, python-script, rag-document-qa-svelte, vite-react-fastapi, and vite-yarp-static). That makes the imported set read as less polyglot / less full-stack JS than it actually is. Can we make this column reflect the languages that are actually present in each sample so the top-level catalog tells the right story?
There was a problem hiding this comment.
Concretely, I think the top-level README should move away from a single flat table and group samples by scenario so the polyglot story is obvious at a glance. Something like: Full-stack JavaScript / TypeScript, Polyglot full-stack, Backend integrations by language, Cloud / AI / event-driven, and .NET + frontend. Within each section, split Workload languages from AppHost instead of folding them together, and add a Deploy column (Docker Compose, Azure, Run only). That would let samples like node-express-redis read as JavaScript, TypeScript | TypeScript AppHost | Docker Compose instead of looking C#-anchored just because Aspire orchestration exists.
|
Here's a concrete sketch of what I mean: ## Browse by scenario
- Full-stack JavaScript / TypeScript
- Polyglot full-stack
- Backend integrations by language
- Cloud / AI / event-driven
- .NET + frontend
## Full-stack JavaScript / TypeScript
| Sample | Workload languages | AppHost | Deploy | Description |
| --- | --- | --- | --- | --- |
| [Node + Redis + Vite](./samples/node-express-redis) | JavaScript, TypeScript | TypeScript | Docker Compose | Express API + React/Vite frontend + Redis behind YARP. |
| [Vite + YARP Static Files](./samples/vite-yarp-static) | JavaScript, TypeScript | TypeScript | Docker Compose | Vite frontend served through YARP in run and publish modes. |
## Polyglot full-stack
| Sample | Workload languages | AppHost | Deploy | Description |
| --- | --- | --- | --- | --- |
| [Vite + React + FastAPI](./samples/vite-react-fastapi) | Python, JavaScript, TypeScript | TypeScript | Docker Compose | React frontend + FastAPI backend behind YARP. |
| [Polyglot Task Queue](./samples/polyglot-task-queue) | JavaScript, Python, C# | TypeScript | Docker Compose | React + Node API + Python/C# workers with RabbitMQ. |
| [RAG Document Q&A](./samples/rag-document-qa-svelte) | Python, JavaScript | TypeScript | Run only | Svelte frontend + FastAPI + Qdrant + OpenAI. |
## Backend integrations by language
| Sample | Primary stack | AppHost | Deploy | Description |
| --- | --- | --- | --- | --- |
| [Go API](./samples/golang-api) | Go | TypeScript | Docker Compose | Go + chi API with Aspire-managed run/publish flows. |
| [Python FastAPI + PostgreSQL](./samples/python-fastapi-postgres) | Python | TypeScript | Docker Compose | FastAPI CRUD API with PostgreSQL and pgAdmin. |
| [Python OpenAI Agent](./samples/python-openai-agent) | Python | TypeScript | Docker Compose | FastAPI AI agent with OpenAI integration. |
| [Python Script](./samples/python-script) | Python | TypeScript | Run only | Minimal Python script sample. |The important bit is separating workload languages from AppHost so the app code tells the story first. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Validation