Skip to content

Conversation

benjaminpetit
Copy link
Member

Description

This PR enables developers to configure a YARP instance directly in the AppHost using code. It adopts the same configuration model as standard YARP, making it easier for developers already familiar with YARP to transition to this approach.

Key Details

  • Leverages the existing YARP configuration model for consistency and ease of migration.
  • Implements custom JSON serialization for certain types, as YARP does not currently support configuration serialization out of the box.
  • Providing a configuration file directly is still supported.
  • Configuration merging is not supported at this stage.
  • While the long-term goal is to upstream this configuration generation to the YARP repository, keeping it within Aspire for now allows for greater agility and iteration speed.
  • Note: This PR does not include any helper methods or extensions to simplify configuration. These will be introduced in a future PR, with the goal of providing easy-to-use extensions that cover the most common use cases.

Usage example

var yarp = builder.AddYarp("yarp")
    .Configure(configuration =>
    {
        configuration
          .AddRoute(new RouteConfig()
          {
              RouteId = "route1",
              ClusterId = "cluster1",
              Match = new RouteMatch()
              {
                  Path = "/aspnetapp/{**catch-all}"
              },
              Transforms = new[]
              {
                  new Dictionary<string, string>
                  {
                      { "PathRemovePrefix", "/aspnetapp" },
                  }
              }
          })
          .AddCluster(new ClusterConfig()
          {
              ClusterId = "cluster1",
              Destinations = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase)
              {
                  { "destination1", new DestinationConfig { Address = "http://backend" } },
              }
          });
    })
    .WithReference(backend.GetEndpoint("http"));

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?

@Copilot Copilot AI review requested due to automatic review settings June 9, 2025 12:52
@github-actions github-actions bot added the area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication label Jun 9, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces programmatic configuration of YARP in the AppHost by leveraging an existing YARP configuration model and adding custom JSON serialization support.

  • New test methods to verify YARP configuration via config files and programmatically.
  • Refactored YARP service extensions and resource classes to support programmatic configuration through a dedicated builder interface and implementation.
  • Updated the project file to add the required package reference and test visibility.

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Aspire.Hosting.Yarp.Tests/YarpFunctionalTests.cs Added tests to verify both config file and programmatic configuration.
src/Aspire.Hosting.Yarp/YarpServiceExtensions.cs Updated extensions to use the new configuration builder API.
src/Aspire.Hosting.Yarp/YarpResource.cs Replaced the config file property with a configuration builder.
src/Aspire.Hosting.Yarp/YarpConfigurationBuilder.cs New builder implementation for programmatic configuration.
src/Aspire.Hosting.Yarp/IYarpConfigurationBuilder.cs Introduced the builder interface.
src/Aspire.Hosting.Yarp/Aspire.Hosting.Yarp.csproj Updated to include the YARP package and expose internals to tests.
spelling.dic Added a duplicate entry for "Yarp".
Comments suppressed due to low confidence (1)

tests/Aspire.Hosting.Yarp.Tests/YarpFunctionalTests.cs:78

  • The health check endpoint '/heath' may be a misspelling; consider verifying if '/health' is the intended path.
.WithHttpHealthCheck("/heath", 404); // TODO we don't have real health check path yet

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@mitchdenny
Copy link
Member

Not necessarily to merge with this PR but we can we try out a higher level API that composes on top of this lower level API. I just want to make sure there are no gotchas if we want to do something like:

builder.AddYarp(...)
       .FowardsTo(backend, "/api/{**catch-all}");

@benjaminpetit
Copy link
Member Author

Not necessarily to merge with this PR but we can we try out a higher level API that composes on top of this lower level API. I just want to make sure there are no gotchas if we want to do something like:

builder.AddYarp(...)
       .FowardsTo(backend, "/api/{**catch-all}");

Sure thing, have a look at my current proto: https://github.com/benjaminpetit/aspire/blob/8b4df33c99dbe76d63489fc20bef6840c352901f/tests/Aspire.Hosting.Yarp.Tests/YarpFunctionalTests.cs#L83

and https://github.com/benjaminpetit/aspire/blob/8b4df33c99dbe76d63489fc20bef6840c352901f/src/Aspire.Hosting.Yarp/YarpServiceExtensions.cs

(or just this branch in general: https://github.com/benjaminpetit/aspire/tree/8b4df33c99dbe76d63489fc20bef6840c352901f)

Right now I manage to do things like this:

yarp.WithReference(
    proxiedResource: backend.GetEndpoint("http"),
    routeMatch: new RouteMatch { Path = "/aspnetapp/{**catch-all}" },
    transforms: transforms => transforms.WithTransformPathRemovePrefix("/aspnetapp")
);

I am also experimenting with having extensions directly on the proxied resource, instead of on the YARP instance.

Copy link
Member

@davidfowl davidfowl left a comment

Choose a reason for hiding this comment

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

The only test is quarantined?

@davidfowl davidfowl merged commit 4ab60e1 into dotnet:main Jun 11, 2025
496 of 498 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Jul 11, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants