Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
00cf76c
Initial plan for issue
Copilot Jun 20, 2025
a02a4a1
Implement basic ExternalServiceResource with service discovery support
Copilot Jun 20, 2025
9d4b64d
Complete ExternalServiceResource implementation with working endpoint…
Copilot Jun 20, 2025
ca43b32
Update implementation to follow DamianEdwards' proposal - WIP endpoin…
Copilot Jun 20, 2025
b6d971b
Fix port determination for external service endpoints to consider scheme
Copilot Jun 20, 2025
b28113b
Address code review feedback - add health checks, fix endpoint naming…
Copilot Jun 20, 2025
8696040
Refactor ExternalServiceResource to follow DamianEdwards feedback - u…
Copilot Jun 20, 2025
0f3918e
WIP
DamianEdwards Jun 26, 2025
38822e4
Merge branch 'main' into copilot/fix-2311
DamianEdwards Jun 26, 2025
fdd7e8c
ExternalServiceResource working now
DamianEdwards Jun 26, 2025
8c3edca
Add support for Yarp and ExternalServiceResource
DamianEdwards Jun 27, 2025
4e98018
Fix things
DamianEdwards Jun 27, 2025
facb128
Yarp fixes
DamianEdwards Jun 27, 2025
bd0f2fc
Use playground ServiceDefaults
DamianEdwards Jun 27, 2025
7a1ce28
Address code review feedback - use "http" endpoint name and remove un…
Copilot Jun 27, 2025
cc6f735
More changes
DamianEdwards Jun 27, 2025
a107a76
Merge branch 'copilot/fix-2311' of https://github.com/dotnet/aspire i…
DamianEdwards Jun 27, 2025
b08db43
Use the parameter to set env var values directly
DamianEdwards Jun 27, 2025
d5c44de
Don't read parameter value in publish mode
DamianEdwards Jun 27, 2025
f187960
Throw at publish time if URLs come from parameters
DamianEdwards Jun 28, 2025
490717d
Make publishing URL from parameter a warning & dashboard updates for …
DamianEdwards Jun 28, 2025
6e1268f
Fix uninstrumented peers name resolution for hypens & show non-endpoi…
DamianEdwards Jun 30, 2025
83fe7a5
Merge branch 'main' into copilot/fix-2311
DamianEdwards Jun 30, 2025
baaaeb8
Post merge fix
DamianEdwards Jun 30, 2025
b52d120
Make Yarp usable with service discovery
DamianEdwards Jun 30, 2025
2275f4e
Update Aspire.slnx
DamianEdwards Jun 30, 2025
35f6b8d
PR review feedback
DamianEdwards Jun 30, 2025
7580749
Update ApplicationKeyTests.cs
DamianEdwards Jun 30, 2025
973652e
Update StringComparers.cs
DamianEdwards Jun 30, 2025
e579d05
Rewrite ExternalServiceTests with comprehensive test coverage for cur…
Copilot Jun 30, 2025
56848cb
Reimplement ExternalServiceResource to follow @DamianEdwards' proposal
Copilot Jul 1, 2025
71175bd
Remove Bootstrap vendor files and use CDN instead to reduce diff size
Copilot Jul 1, 2025
6392b16
Revert changes from commit 56848cb and update tests appropriately
Copilot Jul 1, 2025
1813278
Fix build
DamianEdwards Jul 1, 2025
207cf72
Fix tests
DamianEdwards Jul 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Aspire.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@
<Project Path="playground/AspireEventHub/EventHubsApi/EventHubsApi.csproj" />
<Project Path="playground/AspireEventHub/EventHubsConsumer/EventHubsConsumer.csproj" />
</Folder>
<Folder Name="/playground/ExternalServices/">
<Project Path="playground/ExternalServices/ExternalServices.AppHost/ExternalServices.AppHost.csproj" />
<Project Path="playground/ExternalServices/WebFrontEnd/WebFrontEnd.csproj" />
</Folder>
<Folder Name="/playground/HealthChecks/">
<Project Path="playground/HealthChecks/HealthChecksSandbox.AppHost/HealthChecksSandbox.AppHost.csproj" />
</Folder>
Expand Down
37 changes: 37 additions & 0 deletions playground/ExternalServices/ExternalServices.AppHost/AppHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.Yarp.Transforms;

var builder = DistributedApplication.CreateBuilder(args);

// URL value is in appsettings.json, or can be overridden by environment variable
var externalService = builder.AddExternalService("external-service", builder.AddParameter("external-service-url"));

var nuget = builder.AddExternalService("nuget", "https://api.nuget.org/")
.WithHttpHealthCheck(path: "/v3/index.json");

var externalGateway = builder.AddYarp("gateway")
.WithConfiguration(c =>
{
var nugetCluster = c.AddCluster(nuget);
c.AddRoute("/nuget/{**catchall}", nugetCluster).WithTransformPathRemovePrefix("/nuget");
c.AddRoute("/external-service/{**catchall}", externalService).WithTransformPathRemovePrefix("/external-service");
});

builder.AddProject<Projects.WebFrontEnd>("frontend")
.WithReference(nuget)
.WithEnvironment("EXTERNAL_SERVICE_URL", externalService)
.WithReference(externalGateway);

#if !SKIP_DASHBOARD_REFERENCE
// This project is only added in playground projects to support development/debugging
// of the dashboard. It is not required in end developer code. Comment out this code
// or build with `/p:SkipDashboardReference=true`, to test end developer
// dashboard launch experience, Refer to Directory.Build.props for the path to
// the dashboard binary (defaults to the Aspire.Dashboard bin output in the
// artifacts dir).
builder.AddProject<Projects.Aspire_Dashboard>(KnownResourceNames.AspireDashboard);
#endif

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>f06669fd-2612-489e-a971-1ff9e9cda2a2</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\..\KnownResourceNames.cs" Link="KnownResourceNames.cs" />
</ItemGroup>

<ItemGroup>
<AspireProjectOrPackageReference Include="Aspire.Hosting.AppHost" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Aspire.Hosting.Yarp\Aspire.Hosting.Yarp.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\WebFrontEnd\WebFrontEnd.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17225;http://localhost:15262",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21140",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22266"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15262",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19146",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20283"
}
},
"generate-manifest": {
"commandName": "Project",
"dotnetRunMessages": true,
"commandLineArgs": "--publisher manifest --output-path aspire-manifest.json",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production",
"DOTNET_ENVIRONMENT": "Production"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
},
"Parameters": {
"external-service-url": "https://example.com"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"$schema": "https://json.schemastore.org/aspire-8.0.json",
"resources": {
"external-service-url": {
"type": "parameter.v0",
"value": "{external-service-url.inputs.value}",
"inputs": {
"value": {
"type": "string"
}
}
},
"gateway": {
"type": "container.v0",
"image": "mcr.microsoft.com/dotnet/nightly/yarp:latest",
"env": {
"ASPNETCORE_ENVIRONMENT": "Production",
"services__nuget__https__0": "https://api.nuget.org",
"services__external-service__default__0": "{external-service-url.value}"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http",
"targetPort": 5000
}
}
},
"frontend": {
"type": "project.v0",
"path": "../WebFrontEnd/WebFrontEnd.csproj",
"env": {
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true",
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true",
"OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory",
"ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
"HTTP_PORTS": "{frontend.bindings.http.targetPort}",
"services__nuget__https__0": "https://api.nuget.org",
"EXTERNAL_SERVICE_URL": "{external-service-url.value}",
"services__gateway__http__0": "{gateway.bindings.http.url}"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http"
},
"https": {
"scheme": "https",
"protocol": "tcp",
"transport": "http"
}
}
}
}
}
20 changes: 20 additions & 0 deletions playground/ExternalServices/WebFrontEnd/Components/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="WebFrontEnd.styles.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
</head>

<body>
<Routes />
<script src="_framework/blazor.web.js"></script>
</body>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@inherits LayoutComponentBase

<div class="page">
<div class="sidebar">
<NavMenu />
</div>

<main>
<div class="top-row px-4">
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>

<article class="content px-4">
@Body
</article>
</main>
</div>

<div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred.
<a href="." class="reload">Reload</a>
<span class="dismiss">🗙</span>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
.page {
position: relative;
display: flex;
flex-direction: column;
}

main {
flex: 1;
}

.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}

.top-row {
background-color: #f7f7f7;
border-bottom: 1px solid #d6d5d5;
justify-content: flex-end;
height: 3.5rem;
display: flex;
align-items: center;
}

.top-row ::deep a, .top-row ::deep .btn-link {
white-space: nowrap;
margin-left: 1.5rem;
text-decoration: none;
}

.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
text-decoration: underline;
}

.top-row ::deep a:first-child {
overflow: hidden;
text-overflow: ellipsis;
}

@media (max-width: 640.98px) {
.top-row {
justify-content: space-between;
}

.top-row ::deep a, .top-row ::deep .btn-link {
margin-left: 0;
}
}

@media (min-width: 641px) {
.page {
flex-direction: row;
}

.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}

.top-row {
position: sticky;
top: 0;
z-index: 1;
}

.top-row.auth ::deep a:first-child {
flex: 1;
text-align: right;
width: 0;
}

.top-row, article {
padding-left: 2rem !important;
padding-right: 1.5rem !important;
}
}

#blazor-error-ui {
color-scheme: light only;
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
box-sizing: border-box;
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}

#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">WebFrontEnd</a>
</div>
</div>

<input type="checkbox" title="Navigation menu" class="navbar-toggler" />

<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
<nav class="nav flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
</NavLink>
</div>

<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
</NavLink>
</div>

<div class="nav-item px-3">
<NavLink class="nav-link" href="external-services">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> External Services
</NavLink>
</div>
</nav>
</div>

Loading
Loading