Skip to content

Aspire Integration#6775

Draft
sbrown-livefront wants to merge 70 commits intomainfrom
billing/aspire
Draft

Aspire Integration#6775
sbrown-livefront wants to merge 70 commits intomainfrom
billing/aspire

Conversation

@sbrown-livefront
Copy link
Copy Markdown
Collaborator

@sbrown-livefront sbrown-livefront commented Dec 23, 2025

🎟️ Tracking

📔 Objective

Introduces a new AppHost project to the solution, providing a centralized entry point for orchestrating local development and distributed application resources using .NET Aspire. The changes include new configuration files, project setup, and builder extensions to streamline the setup of databases, secrets, mail, storage emulation, and service dependencies. It also adds support for optional community plugins (NodeJS and Ngrok) and dynamic inclusion of additional projects through configuration.

The most important changes are:

New AppHost Project Integration:

  • Added the AppHost project to the solution, including its project file (AppHost.csproj), main entry point (AppHost.cs), and supporting builder extensions (BuilderExtensions.cs). This project coordinates the setup and orchestration of all major services and infrastructure required for local development. [1] [2] [3] [4] [5]

Configuration and Environment Setup:

  • Introduced environment and application settings files for AppHost, including appsettings.json, appsettings.Development.json, and launch profiles (launchSettings.json), to define logging, ports, database, mail, storage, and plugin settings. [1] [2] [3]
  • Added .aspire/settings.json to specify the path to the AppHost project for Aspire tooling.

Builder Extension Utilities:

  • Implemented BuilderExtensions.cs to encapsulate reusable logic for configuring secrets setup, database, migrations, Azurite storage emulator, mail catcher, service wiring, and optional community plugins (NodeJS frontend and Ngrok tunneling). This modularizes and simplifies the orchestration of resources and dependencies.

Solution File Updates:

  • Updated bitwarden-server.sln to include the new AppHost project and ensure it participates in solution builds and configurations. [1] [2]

📸 Screenshots

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Dec 23, 2025

Logo
Checkmarx One – Scan Summary & Details094b1115-40eb-4e48-9275-b6516c549314

Great job! No new security vulnerabilities introduced in this pull request

Comment thread AppHost/AppHost.csproj Fixed
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.26%. Comparing base (329b144) to head (ed09ed1).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6775   +/-   ##
=======================================
  Coverage   59.26%   59.26%           
=======================================
  Files        2082     2082           
  Lines       92060    92060           
  Branches     8181     8181           
=======================================
  Hits        54557    54557           
  Misses      35562    35562           
  Partials     1941     1941           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sonarqubecloud
Copy link
Copy Markdown

@withinfocus
Copy link
Copy Markdown
Contributor

@sbrown-livefront is there a reason this keeps being synced? I think we can leave it for a moment and wait until .NET 10 gets applied to the platform.

@sbrown-livefront
Copy link
Copy Markdown
Collaborator Author

@sbrown-livefront is there a reason this keeps being synced? I think we can leave it for a moment and wait until .NET 10 gets applied to the platform.

Sorry about the noise. I had it auto-sync when merging main in locally to make sure it stayed up-to-date. I'll shut that down.

Copy link
Copy Markdown
Member

@justindbaur justindbaur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial thoughts

Comment thread dev/setup_secrets.ps1 Outdated
Comment thread ServiceDefaults/Extensions.cs Outdated
Comment on lines +49 to +53
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should be able to become just this. The Server SDK does most of below and more. It doesn't filter out health endpoints from instrumentation but it will likely be adding that soon.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Great work on the SDK. The entire servicedefaults wasn't needed anymore!

I had some request/response pieces that enriched the httpclient, but they can be added by devs if needed.

It looked like:

   {
                            httpClient.EnrichWithHttpRequestMessage = (activity, message) =>
                            {
                                if (context.HostingEnvironment.IsDevelopment())
                                {
                                    activity.SetTag("http.request_content_length", message.Content?.Headers.ContentLength);
                                    activity.SetTag("http.request_method", message.Method.Method);
                                    activity.SetTag("http.request_url", message.RequestUri?.ToString());
                                    activity.SetTag("http.request_message_headers", message.Headers.ToString());
                                    activity.SetTag("http.request_body", message.Content?.ReadAsStringAsync().Result);
                                }
                            };
                            httpClient.EnrichWithHttpResponseMessage = (activity, message) =>
                            {
                                if (context.HostingEnvironment.IsDevelopment())
                                {
                                    activity.SetTag("http.response_content_length",
                                        message.Content.Headers.ContentLength);
                                    activity.SetTag("http.response_status_code", (int)message.StatusCode);
                                    activity.SetTag("http.response_status_text", message.ReasonPhrase);
                                    activity.SetTag("http.response_content_type",
                                        message.Content.Headers.ContentType?.MediaType);
                                    activity.SetTag("http.response_message_headers", message.Headers.ToString());
                                    activity.SetTag("http.response_body", message.Content.ReadAsStringAsync().Result);
                                }
                            };

Comment thread ServiceDefaults/Extensions.cs Outdated
services.AddServiceDiscovery();
services.ConfigureHttpClientDefaults(http =>
{
http.AddStandardResilienceHandler();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm cautious to add AddStandardResilienceHandler() right now. It's likely a good thing to add but I wouldn't want it just added for DEBUG builds. I would want it added to Release as well but we will want to audit the effects it will have first. I don't think it's a requirement for Aspire but correct me if I am wrong.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, it wasn't required.

Looking at the internals it added some okay defaults for resilience, but I think we'll be fine for it running locally until the SDK includes it.

Comment thread dev/secrets.json.example
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is where we should put aspire configuration, for starters this is my thinking of what the layout would be:

{
  .. Logging
  "Services": {
    "admin": {
      "BasePort": 1111,
    },
    .. Other services
  }
  "AdditionalProjects": {},
  "ClientsPath": "../clients",
  "SelfHost": false,
  "Database": {
    "Type": "MsSql",
    "Password": "MyPassword"
  }
}

The idea with this is that AdditionalProjects will start as an empty object but consumers that want to integrate with billing-pricing for example can do:

dotnet user-secrets set "AdditionalProjects:billing-pricing" "../billing-pricing/Path/To/Project.csproj"

With base port we can get cute and when they choose self host we just increment the number by one.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a great idea.

I have the service ports empty for now for users to overwrite them.

I also added the more context for the AdditionalProjects. You can add an object like this to make sure it is referenced in the correct projects.

    "pricing-service": {
      "Path": "../../billing-pricing/src/REST/REST.csproj",
      "ReferencedBy": [ "api", "billing" ]
    }

I'll probably expand it to have projects it want's to reference also, but for now I think it's fine.

Comment thread AppHost/BuilderExtensions.cs Outdated
Comment thread AppHost/BuilderExtensions.cs Outdated
@sbrown-livefront
Copy link
Copy Markdown
Collaborator Author

@justindbaur Sorry for the delay on these fixes. Thank you for the great feedback. That SDK add made everything less intrusive.

I added some MSBuild properties for including community plugins I've been using. That way they don't get included if the user doesn't want them. Since they aren't official plugins for Aspire, I didn't want to include them by default. Let me know your thoughts.

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants