From ac606485642a4fc7d87f3841d78147690844116d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 20:53:18 +0000 Subject: [PATCH 1/3] Initial plan From c33b92cf64c09c8105a50866c7d5508ca66b5b96 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 21:02:01 +0000 Subject: [PATCH 2/3] Address integration-specific documentation gaps from Discord feedback - JavaScript: Add VITE_API_BASE_URL pattern and monorepo/Turborepo sections - Python: Add HTTPS configuration and internal vs external service exposure sections - Dapr: Add state store + actor state store config, and ACA deployment note - YARP: Add HTTPS endpoints section and See also links - Azure PostgreSQL: Add database creation after initial deployment note - New WPF/WinForms page with explicit support status and dev-only patterns - Sidebar: Add WPF and Windows Forms entry to Frameworks & runtimes Co-authored-by: IEvangelist <7679720+IEvangelist@users.noreply.github.com> --- .../config/sidebar/integrations.topics.ts | 1 + .../azure-postgresql-host.mdx | 17 +++ .../docs/integrations/frameworks/dapr.mdx | 83 +++++++++++ .../integrations/frameworks/javascript.mdx | 88 +++++++++++ .../docs/integrations/frameworks/python.mdx | 64 ++++++++ .../integrations/frameworks/wpf-winforms.mdx | 137 ++++++++++++++++++ .../integrations/reverse-proxies/yarp.mdx | 33 +++++ 7 files changed, 423 insertions(+) create mode 100644 src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx diff --git a/src/frontend/config/sidebar/integrations.topics.ts b/src/frontend/config/sidebar/integrations.topics.ts index 538559694..6a52f1262 100644 --- a/src/frontend/config/sidebar/integrations.topics.ts +++ b/src/frontend/config/sidebar/integrations.topics.ts @@ -813,6 +813,7 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { { label: 'PowerShell', slug: 'integrations/frameworks/powershell' }, { label: 'Python', slug: 'integrations/frameworks/python' }, { label: 'Rust', slug: 'integrations/frameworks/rust' }, + { label: 'WPF and Windows Forms', slug: 'integrations/frameworks/wpf-winforms' }, ], }, { diff --git a/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-host.mdx b/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-host.mdx index afdc9b7a8..464483656 100644 --- a/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-host.mdx +++ b/src/frontend/src/content/docs/integrations/cloud/azure/azure-postgresql/azure-postgresql-host.mdx @@ -254,3 +254,20 @@ The preceding code: - A tag is added to the flexible server with a key of `ExampleKey` and a value of `Example value`. There are many more configuration options available to customize the PostgreSQL resource. For more information, see [Azure.Provisioning customization](/integrations/cloud/azure/customize-resources/#azureprovisioning-customization). + +## Database creation after initial deployment + +When you call `AddDatabase` on an Azure PostgreSQL resource, Aspire provisions the database during the **first** deployment. On subsequent deployments with `azd up`, only the server-level Bicep is redeployed—databases that already exist are not recreated or deleted. + + + +If you need to add a new database to an existing server, redeploy with the updated AppHost code or manually create the database in the Azure portal or via the PostgreSQL CLI: + +```bash title="Bash — Create database manually" +az postgres flexible-server db create \ + --resource-group \ + --server-name \ + --database-name +``` diff --git a/src/frontend/src/content/docs/integrations/frameworks/dapr.mdx b/src/frontend/src/content/docs/integrations/frameworks/dapr.mdx index 47b8c7614..0aea20d57 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/dapr.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/dapr.mdx @@ -132,6 +132,89 @@ app.Run(); For more information on Dapr service invocation, see [Dapr service invocation](https://docs.dapr.io/developing-applications/building-blocks/service-invocation/). +## Configure Dapr state stores + +The Aspire Dapr integration supports adding Dapr state store components. Use the `AddDaprStateStore` method to register a state store and reference it from your services: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var stateStore = builder.AddDaprStateStore("statestore"); + +builder.AddProject("exampleproject") + .WithDaprSidecar() + .WithReference(stateStore); + +// After adding all resources, run the app... +``` + +### Configure an actor state store + +To configure a state store as an Actor state store (required by Dapr actors), add the `actorStateStore` metadata entry to your component file. Create a `components` directory in your app host and add a component YAML file: + +```yaml title="YAML — components/statestore.yaml" +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore +spec: + type: state.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: actorStateStore + # Setting actorStateStore to "true" designates this state store + # as the actor state store. Dapr actors require exactly one state + # store to be configured with this flag. + value: "true" +``` + +Reference the component directory in your AppHost using `WithDaprSidecar` options: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddProject("actorservice") + .WithDaprSidecar(new DaprSidecarOptions + { + ResourcesDirectory = "./components" + }); + +// After adding all resources, run the app... +``` + +## Deploy with Azure Container Apps + +The Aspire Dapr Community Toolkit integration configures Dapr sidecars for local development. When deploying to Azure Container Apps (ACA), Dapr sidecar settings are part of the container app configuration and must be preserved on each deployment. + + + +To ensure Dapr settings are preserved on Azure Container Apps deployments, configure the sidecar explicitly using `PublishAsAzureContainerApp`: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +builder.AddProject("exampleproject") + .WithDaprSidecar() + .PublishAsAzureContainerApp((infra, app) => + { + // Enable Dapr on the container app and set the app ID + app.Configuration.Dapr = new() + { + IsEnabled = true, + AppId = "exampleproject", + AppPort = 8080, + }; + }); + +// After adding all resources, run the app... +``` + +For more information on customizing Azure Container Apps resources, see [Configure Azure Container Apps](/integrations/cloud/azure/configure-container-apps/). + ## See also - [Dapr documentation](https://docs.dapr.io/) diff --git a/src/frontend/src/content/docs/integrations/frameworks/javascript.mdx b/src/frontend/src/content/docs/integrations/frameworks/javascript.mdx index 817015183..a02aa3001 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/javascript.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/javascript.mdx @@ -289,6 +289,94 @@ var viteApp = builder.AddViteApp("vite-app", "./vite-app") The HTTPS configuration is automatically applied without modifying your `vite.config.js` file. For more information about certificate configuration, see [Certificate configuration](/app-host/certificate-configuration/). +## Pass API URLs to Vite apps + +When your Vite app needs to communicate with a backend API, pass the API URL via an environment variable. Vite only exposes variables prefixed with `VITE_` to client-side code. + +In your AppHost, expose the API URL to the Vite app using `WithEnvironment`: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var api = builder.AddProject("api") + .WithExternalHttpEndpoints(); + +var viteApp = builder.AddViteApp("vite-app", "./vite-app") + .WithReference(api) + .WithEnvironment("VITE_API_BASE_URL", api.GetEndpoint("https")); + +// After adding all resources, run the app... +``` + +In your Vite app, read the variable from `import.meta.env`: + +```typescript title="TypeScript — src/api.ts" +const apiBaseUrl = import.meta.env.VITE_API_BASE_URL; + +export async function fetchData() { + const response = await fetch(`${apiBaseUrl}/api/data`); + return response.json(); +} +``` + + + +## Monorepo and Turborepo patterns + +Aspire supports monorepo layouts where multiple JavaScript apps share a single root workspace. Each app is added as a separate resource in the AppHost pointing to its own subdirectory. + +### pnpm workspaces + +For a pnpm monorepo, install dependencies from the workspace root and reference individual app directories: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var api = builder.AddProject("api"); + +// Each app lives in its own subdirectory with its own package.json +var frontend = builder.AddViteApp("frontend", "./apps/frontend") + .WithPnpm() + .WithReference(api); + +var dashboard = builder.AddViteApp("dashboard", "./apps/dashboard") + .WithPnpm() + .WithReference(api); + +// After adding all resources, run the app... +``` + + + +### Turborepo + +Turborepo orchestrates builds across a monorepo. Use a custom run script that delegates to the Turborepo pipeline for a specific app: + +```json title="apps/frontend/package.json" +{ + "scripts": { + "dev": "turbo run dev --filter=frontend" + } +} +``` + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var api = builder.AddProject("api"); + +var frontend = builder.AddJavaScriptApp("frontend", "./apps/frontend") + .WithPnpm() + .WithRunScript("dev") + .WithReference(api); + +// After adding all resources, run the app... +``` + ## Production builds When you publish your application using `aspire deploy`, Aspire automatically: diff --git a/src/frontend/src/content/docs/integrations/frameworks/python.mdx b/src/frontend/src/content/docs/integrations/frameworks/python.mdx index 681fdfd7b..d40397e00 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/python.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/python.mdx @@ -291,6 +291,70 @@ var python = builder.AddPythonApp("python-api", "../python-app", "main.py") The connection string will be available as an environment variable in the Python application. +## HTTPS configuration + +By default, Python apps run over HTTP in local development. To enable HTTPS, use `WithHttpsEndpoint` and configure the developer certificate in your app host: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var python = builder.AddUvicornApp("python-api", "../python-app", "main:app") + .WithHttpsEndpoint(port: 8443, env: "PORT") + .WithHttpsDeveloperCertificate(); + +// After adding all resources, run the app... +``` + +When you call `WithHttpsDeveloperCertificate`, Aspire exports the ASP.NET Core development certificate and injects it into the Python process as environment variables. Read those variables in your Uvicorn startup: + +```python title="Python — main.py" +import os +import uvicorn + +if __name__ == "__main__": + ssl_keyfile = os.environ.get("ASPNETCORE_Kestrel__Certificates__Default__KeyPath") + ssl_certfile = os.environ.get("ASPNETCORE_Kestrel__Certificates__Default__Path") + + uvicorn.run( + "main:app", + host="0.0.0.0", + port=int(os.environ.get("PORT", 8443)), + ssl_keyfile=ssl_keyfile, + ssl_certfile=ssl_certfile, + ) +``` + + + +## Internal vs. external service exposure + +By default, Aspire services are only accessible within the distributed application—they are not exposed to external traffic. To control whether a Python service is reachable from outside the app, use `WithExternalHttpEndpoints`: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var internalApi = builder.AddUvicornApp("internal-api", "../internal-api", "main:app") + .WithHttpEndpoint(port: 8001, env: "PORT"); +// internalApi is NOT exposed publicly — only reachable by other Aspire resources + +var publicApi = builder.AddUvicornApp("public-api", "../public-api", "main:app") + .WithHttpEndpoint(port: 8000, env: "PORT") + .WithExternalHttpEndpoints(); +// publicApi IS exposed publicly + +builder.AddProject() + .WithReference(internalApi) + .WithReference(publicApi); + +// After adding all resources, run the app... +``` + + + ## Debugging The Python hosting integration provides full debugging support in Visual Studio Code: diff --git a/src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx b/src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx new file mode 100644 index 000000000..a70c9c969 --- /dev/null +++ b/src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx @@ -0,0 +1,137 @@ +--- +title: WPF and Windows Forms with Aspire +description: Learn how to use WPF and Windows Forms desktop applications with Aspire for development-time service orchestration. +--- + +import { Aside, Steps } from '@astrojs/starlight/components'; +import { Image } from 'astro:assets'; +import dotnetIcon from '@assets/icons/dotnet.svg'; + +.NET logo + +WPF (Windows Presentation Foundation) and Windows Forms are .NET desktop UI frameworks for building Windows desktop applications. While Aspire's primary focus is on cloud-native and web workloads, you can use WPF and Windows Forms applications alongside Aspire for **development-time orchestration** of backend services. + + + +## Add a WPF or Windows Forms app to Aspire + +Because WPF and Windows Forms projects are standard .NET projects, you can reference them directly from your AppHost using `AddProject`. This starts the desktop app alongside your backend services when you run the AppHost. + +### Step 1: Add a project reference + +In your AppHost `.csproj`, add a project reference to your WPF or Windows Forms app: + +```xml title="XML — AppHost.csproj" + + + +``` + +### Step 2: Register the project in AppHost + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var api = builder.AddProject("api"); + +// Start the WPF or WinForms app as a resource in local development +var desktop = builder.AddProject("desktop") + .WithReference(api); + +// After adding all resources, run the app... +builder.Build().Run(); +``` + +When you run the AppHost, the WPF or Windows Forms application starts automatically as a process resource. + +### Step 3: Consume service URLs in the desktop app + +Add the `Aspire.ServiceDefaults` (or `Microsoft.Extensions.ServiceDiscovery`) package to your desktop project to enable service discovery: + +```csharp title="C# — App.xaml.cs (WPF)" +public partial class App : Application +{ + public IServiceProvider Services { get; private set; } = default!; + + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + + var host = Host.CreateDefaultBuilder() + .ConfigureServices(services => + { + services.AddServiceDiscovery(); + services.AddHttpClient(client => + { + // Service name matches the name in AppHost + client.BaseAddress = new Uri("https+http://api"); + }).AddServiceDiscovery(); + }) + .Build(); + + Services = host.Services; + host.Start(); + } +} +``` + + + +## Dev-only resources + +A common pattern is to start certain resources (databases, mock services, dev tools) only during local development and skip them in production. Use `builder.Environment.IsDevelopment()` to conditionally add resources: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddPostgres("postgres") + .AddDatabase("mydb"); + +var api = builder.AddProject("api") + .WithReference(postgres); + +if (builder.Environment.IsDevelopment()) +{ + // Only launch the desktop app during local development + builder.AddProject("desktop") + .WithReference(api); +} + +// After adding all resources, run the app... +builder.Build().Run(); +``` + +## Limitations + +- **Windows only**: WPF and Windows Forms require Windows. If your team develops on macOS or Linux, the desktop resource will fail to start on non-Windows machines. +- **No deployment support**: `aspire deploy` does not produce deployment artifacts for desktop apps. They are treated as local-only resources. +- **No auto-launch from dashboard**: Desktop apps registered with Aspire start automatically when the AppHost runs—they cannot be manually started or stopped from the Aspire dashboard the same way containerized services can be. + +## Comparison with .NET MAUI + +| Feature | WPF / WinForms | .NET MAUI | +|---------|---------------|-----------| +| First-class Aspire support | Via `AddProject` (manual) | Via `Aspire.Hosting.Maui` package | +| Cross-platform | Windows only | Windows, macOS, iOS, Android | +| Dev Tunnels support | Not applicable | Built-in for iOS/Android | +| Production deployment via Aspire | Not supported | Not supported | + +For cross-platform desktop and mobile scenarios, consider [.NET MAUI integration](/integrations/frameworks/maui/). + +## See also + +- [.NET MAUI integration](/integrations/frameworks/maui/) +- [AppHost overview](/get-started/app-host/) +- [WPF documentation](https://learn.microsoft.com/dotnet/desktop/wpf/) +- [Windows Forms documentation](https://learn.microsoft.com/dotnet/desktop/winforms/) diff --git a/src/frontend/src/content/docs/integrations/reverse-proxies/yarp.mdx b/src/frontend/src/content/docs/integrations/reverse-proxies/yarp.mdx index c1e88e626..e6a8ce554 100644 --- a/src/frontend/src/content/docs/integrations/reverse-proxies/yarp.mdx +++ b/src/frontend/src/content/docs/integrations/reverse-proxies/yarp.mdx @@ -192,3 +192,36 @@ var gateway = builder.AddYarp("gateway") // Static files are served for all other routes }); ``` + +## HTTPS endpoints + +When both the YARP gateway and backend services use HTTPS, configure HTTPS endpoints using `WithHttpsEndpoint` and the developer certificate. YARP can proxy HTTPS-to-HTTPS when the backend service exposes an HTTPS endpoint: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +// Backend service with HTTPS +var razorPages = builder.AddProject("razorpages") + .WithHttpsEndpoint(); + +// YARP gateway proxying to the HTTPS backend +var gateway = builder.AddYarp("gateway") + .WithHttpsEndpoint() + .WithHttpsDeveloperCertificate() + .WithConfiguration(yarp => + { + yarp.AddRoute("/{**catch-all}", razorPages); + }); + +// After adding all resources, run the app... +``` + + + +## See also + +- [YARP documentation](https://microsoft.github.io/reverse-proxy/) +- [Aspire integrations overview](/integrations/overview/) +- [Aspire GitHub repo](https://github.com/dotnet/aspire) From 75285613404b441a15ea6b5908595a3f931473c7 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 23 Feb 2026 15:50:22 -0600 Subject: [PATCH 3/3] Update src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../src/content/docs/integrations/frameworks/wpf-winforms.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx b/src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx index a70c9c969..10e13c01f 100644 --- a/src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx +++ b/src/frontend/src/content/docs/integrations/frameworks/wpf-winforms.mdx @@ -3,7 +3,7 @@ title: WPF and Windows Forms with Aspire description: Learn how to use WPF and Windows Forms desktop applications with Aspire for development-time service orchestration. --- -import { Aside, Steps } from '@astrojs/starlight/components'; +import { Aside } from '@astrojs/starlight/components'; import { Image } from 'astro:assets'; import dotnetIcon from '@assets/icons/dotnet.svg';