Skip to content

Commit f381520

Browse files
✨ Add support for .NET Aspire
1 parent 1b0aafd commit f381520

15 files changed

+298
-4
lines changed

.template.config/dotnetcli.host.json

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
},
1111
"UseSQLite": {
1212
"longName": "use-sqlite"
13+
},
14+
"UseAspire": {
15+
"longName": "use-aspire"
1316
}
1417
}
1518
}

.template.config/ide.host.json

+20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
"text": "Use SQLite for database (default is LocalDB)."
2323
},
2424
"isVisible": true
25+
},
26+
{
27+
"id": "PipelineProvider",
28+
"name": {
29+
"text": "Pipeline Provider"
30+
},
31+
"description": {
32+
"text": "Select the pipeline provider."
33+
},
34+
"isVisible": true
35+
},
36+
{
37+
"id": "UseAspire",
38+
"name": {
39+
"text": "Use Aspire"
40+
},
41+
"description": {
42+
"text": "Use .NET Aspire"
43+
},
44+
"isVisible": true
2545
}
2646
]
2747
}

.template.config/template.json

+13
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@
5656
"defaultValue": "false",
5757
"description": "Whether to use SQLite instead of LocalDB."
5858
},
59+
"UseAspire": {
60+
"type": "parameter",
61+
"datatype": "bool",
62+
"defaultValue": "false",
63+
"description": "Use .NET Aspire"
64+
},
5965
"PipelineProvider": {
6066
"type": "parameter",
6167
"datatype": "choice",
@@ -192,6 +198,13 @@
192198
"appsettings.SQLite.json": "appsettings.json",
193199
"TestDatabase.Sqlite.cs": "TestDatabase.cs"
194200
}
201+
},
202+
{
203+
"condition": "(!UseAspire)",
204+
"exclude": [
205+
"src/AppHost/**",
206+
"src/ServiceDefaults/**"
207+
]
195208
}
196209
]
197210
}

CleanArchitecture.sln

+22-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application.FunctionalTests
3737
EndProject
3838
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure.IntegrationTests", "tests\Infrastructure.IntegrationTests\Infrastructure.IntegrationTests.csproj", "{01FA6786-921D-4CE8-8C50-4FDA66C9477D}"
3939
EndProject
40+
#if (UseAspire)
41+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppHost", "src\AppHost\AppHost.csproj", "{36483B25-E165-46F3-AA1C-ADE75A46BD8E}"
42+
EndProject
43+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceDefaults", "src\ServiceDefaults\ServiceDefaults.csproj", "{15AFAC17-7E6E-4DB9-A5D9-EA96C5287CD2}"
44+
EndProject
45+
#endif
4046
Global
4147
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4248
Debug|Any CPU = Debug|Any CPU
@@ -67,12 +73,12 @@ Global
6773
{4E4EE20C-F06A-4A1B-851F-C5577796941C}.Debug|Any CPU.Build.0 = Debug|Any CPU
6874
{4E4EE20C-F06A-4A1B-851F-C5577796941C}.Release|Any CPU.ActiveCfg = Release|Any CPU
6975
{4E4EE20C-F06A-4A1B-851F-C5577796941C}.Release|Any CPU.Build.0 = Release|Any CPU
70-
#if (!UseApiOnly)
76+
#if (!UseApiOnly)
7177
{21334974-6B07-47BB-B664-AC62FE58C12B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
7278
{21334974-6B07-47BB-B664-AC62FE58C12B}.Debug|Any CPU.Build.0 = Debug|Any CPU
7379
{21334974-6B07-47BB-B664-AC62FE58C12B}.Release|Any CPU.ActiveCfg = Release|Any CPU
7480
{21334974-6B07-47BB-B664-AC62FE58C12B}.Release|Any CPU.Build.0 = Release|Any CPU
75-
#endif
81+
#endif
7682
{EA6127A5-94C9-4C31-AD11-E6811B92B520}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
7783
{EA6127A5-94C9-4C31-AD11-E6811B92B520}.Debug|Any CPU.Build.0 = Debug|Any CPU
7884
{EA6127A5-94C9-4C31-AD11-E6811B92B520}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -81,6 +87,16 @@ Global
8187
{01FA6786-921D-4CE8-8C50-4FDA66C9477D}.Debug|Any CPU.Build.0 = Debug|Any CPU
8288
{01FA6786-921D-4CE8-8C50-4FDA66C9477D}.Release|Any CPU.ActiveCfg = Release|Any CPU
8389
{01FA6786-921D-4CE8-8C50-4FDA66C9477D}.Release|Any CPU.Build.0 = Release|Any CPU
90+
#if (UseAspire)
91+
{36483B25-E165-46F3-AA1C-ADE75A46BD8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
92+
{36483B25-E165-46F3-AA1C-ADE75A46BD8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
93+
{36483B25-E165-46F3-AA1C-ADE75A46BD8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
94+
{36483B25-E165-46F3-AA1C-ADE75A46BD8E}.Release|Any CPU.Build.0 = Release|Any CPU
95+
{15AFAC17-7E6E-4DB9-A5D9-EA96C5287CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
96+
{15AFAC17-7E6E-4DB9-A5D9-EA96C5287CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
97+
{15AFAC17-7E6E-4DB9-A5D9-EA96C5287CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
98+
{15AFAC17-7E6E-4DB9-A5D9-EA96C5287CD2}.Release|Any CPU.Build.0 = Release|Any CPU
99+
#endif
84100
EndGlobalSection
85101
GlobalSection(SolutionProperties) = preSolution
86102
HideSolutionNode = FALSE
@@ -97,6 +113,10 @@ Global
97113
#endif
98114
{EA6127A5-94C9-4C31-AD11-E6811B92B520} = {664D406C-2F83-48F0-BFC3-408D5CB53C65}
99115
{01FA6786-921D-4CE8-8C50-4FDA66C9477D} = {664D406C-2F83-48F0-BFC3-408D5CB53C65}
116+
#if (UseAspire)
117+
{36483B25-E165-46F3-AA1C-ADE75A46BD8E} = {6ED356A7-8B47-4613-AD01-C85CF28491BD}
118+
{15AFAC17-7E6E-4DB9-A5D9-EA96C5287CD2} = {6ED356A7-8B47-4613-AD01-C85CF28491BD}
119+
#endif
100120
EndGlobalSection
101121
GlobalSection(ExtensibilityGlobals) = postSolution
102122
SolutionGuid = {3CB609D9-5D54-4C11-A371-DAAC8B74E430}

Directory.Build.props

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<WarningsNotAsErrors>NU1901;NU1902;NU1903;NU1904</WarningsNotAsErrors>
77
<!-- <ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath> -->
88
<ImplicitUsings>enable</ImplicitUsings>
9+
<DefineConstants>UseAspire</DefineConstants>
910
<Nullable>enable</Nullable>
1011
</PropertyGroup>
1112
</Project>

Directory.Packages.props

+11-1
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,24 @@
77
<MicrosoftExtensionsVersion>9.0.0</MicrosoftExtensionsVersion>
88
</PropertyGroup>
99
<ItemGroup>
10+
<!-- Begin Aspire -->
11+
<PackageVersion Include="Aspire.Hosting.AppHost" Version="9.0.0" />
12+
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
13+
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="9.0.0" />
14+
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
15+
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
16+
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
17+
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
18+
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
19+
<!-- End Aspire -->
1020
<PackageVersion Include="Ardalis.GuardClauses" Version="4.6.0" />
1121
<PackageVersion Include="AutoMapper" Version="13.0.1" />
1222
<PackageVersion Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.3.2" />
1323
<PackageVersion Include="Azure.Identity" Version="1.13.1" />
1424
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
1525
<PackageVersion Include="FluentAssertions" Version="6.12.2" />
1626
<PackageVersion Include="FluentValidation.AspNetCore" Version="11.3.0" />
17-
<PackageVersion Include="FluentValidation.DependencyInjectionExtensions" Version="11.10.0" />
27+
<PackageVersion Include="FluentValidation.DependencyInjectionExtensions" Version="11.11.0" />
1828
<PackageVersion Include="MediatR" Version="12.4.1" />
1929
<PackageVersion Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="$(AspnetVersion)" />
2030
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="$(AspnetVersion)" />

src/AppHost/AppHost.csproj

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />
4+
5+
<PropertyGroup>
6+
<OutputType>Exe</OutputType>
7+
<TargetFramework>net9.0</TargetFramework>
8+
<ImplicitUsings>enable</ImplicitUsings>
9+
<Nullable>enable</Nullable>
10+
<IsAspireHost>true</IsAspireHost>
11+
<RootNamespace>CleanArchitecture.AppHost</RootNamespace>
12+
<AssemblyName>CleanArchitecture.AppHost</AssemblyName>
13+
</PropertyGroup>
14+
15+
<ItemGroup>
16+
<PackageReference Include="Aspire.Hosting.AppHost" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<ProjectReference Include="..\Web\Web.csproj" />
21+
</ItemGroup>
22+
23+
</Project>

src/AppHost/Program.cs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
var builder = DistributedApplication.CreateBuilder(args);
2+
3+
builder.AddProject<Projects.Web>("web");
4+
5+
builder.Build().Run();
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"$schema": "https://json.schemastore.org/launchsettings.json",
3+
"profiles": {
4+
"https": {
5+
"commandName": "Project",
6+
"dotnetRunMessages": true,
7+
"launchBrowser": true,
8+
"applicationUrl": "https://localhost:17078;http://localhost:15010",
9+
"environmentVariables": {
10+
"ASPNETCORE_ENVIRONMENT": "Development",
11+
"DOTNET_ENVIRONMENT": "Development",
12+
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21118",
13+
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22071"
14+
}
15+
},
16+
"http": {
17+
"commandName": "Project",
18+
"dotnetRunMessages": true,
19+
"launchBrowser": true,
20+
"applicationUrl": "http://localhost:15010",
21+
"environmentVariables": {
22+
"ASPNETCORE_ENVIRONMENT": "Development",
23+
"DOTNET_ENVIRONMENT": "Development",
24+
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19152",
25+
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20152"
26+
}
27+
}
28+
}
29+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
}
8+
}

src/AppHost/appsettings.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning",
6+
"Aspire.Hosting.Dcp": "Warning"
7+
}
8+
}
9+
}

src/ServiceDefaults/Extensions.cs

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Diagnostics.HealthChecks;
5+
using Microsoft.Extensions.Logging;
6+
using Microsoft.Extensions.ServiceDiscovery;
7+
using OpenTelemetry;
8+
using OpenTelemetry.Metrics;
9+
using OpenTelemetry.Trace;
10+
11+
namespace Microsoft.Extensions.Hosting;
12+
13+
// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
14+
// This project should be referenced by each service project in your solution.
15+
// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
16+
public static class Extensions
17+
{
18+
public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
19+
{
20+
builder.ConfigureOpenTelemetry();
21+
22+
builder.AddDefaultHealthChecks();
23+
24+
builder.Services.AddServiceDiscovery();
25+
26+
builder.Services.ConfigureHttpClientDefaults(http =>
27+
{
28+
// Turn on resilience by default
29+
http.AddStandardResilienceHandler();
30+
31+
// Turn on service discovery by default
32+
http.AddServiceDiscovery();
33+
});
34+
35+
// Uncomment the following to restrict the allowed schemes for service discovery.
36+
// builder.Services.Configure<ServiceDiscoveryOptions>(options =>
37+
// {
38+
// options.AllowedSchemes = ["https"];
39+
// });
40+
41+
return builder;
42+
}
43+
44+
public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
45+
{
46+
builder.Logging.AddOpenTelemetry(logging =>
47+
{
48+
logging.IncludeFormattedMessage = true;
49+
logging.IncludeScopes = true;
50+
});
51+
52+
builder.Services.AddOpenTelemetry()
53+
.WithMetrics(metrics =>
54+
{
55+
metrics.AddAspNetCoreInstrumentation()
56+
.AddHttpClientInstrumentation()
57+
.AddRuntimeInstrumentation();
58+
})
59+
.WithTracing(tracing =>
60+
{
61+
tracing.AddSource(builder.Environment.ApplicationName)
62+
.AddAspNetCoreInstrumentation()
63+
// Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
64+
//.AddGrpcClientInstrumentation()
65+
.AddHttpClientInstrumentation();
66+
});
67+
68+
builder.AddOpenTelemetryExporters();
69+
70+
return builder;
71+
}
72+
73+
private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
74+
{
75+
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
76+
77+
if (useOtlpExporter)
78+
{
79+
builder.Services.AddOpenTelemetry().UseOtlpExporter();
80+
}
81+
82+
// Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
83+
//if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
84+
//{
85+
// builder.Services.AddOpenTelemetry()
86+
// .UseAzureMonitor();
87+
//}
88+
89+
return builder;
90+
}
91+
92+
public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
93+
{
94+
builder.Services.AddHealthChecks()
95+
// Add a default liveness check to ensure app is responsive
96+
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
97+
98+
return builder;
99+
}
100+
101+
public static WebApplication MapDefaultEndpoints(this WebApplication app)
102+
{
103+
// Adding health checks endpoints to applications in non-development environments has security implications.
104+
// See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
105+
if (app.Environment.IsDevelopment())
106+
{
107+
// All health checks must pass for app to be considered ready to accept traffic after starting
108+
app.MapHealthChecks("/health");
109+
110+
// Only health checks tagged with the "live" tag must pass for app to be considered alive
111+
app.MapHealthChecks("/alive", new HealthCheckOptions
112+
{
113+
Predicate = r => r.Tags.Contains("live")
114+
});
115+
}
116+
117+
return app;
118+
}
119+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<IsAspireSharedProject>true</IsAspireSharedProject>
8+
<RootNamespace>CleanArchitecture.ServiceDefaults</RootNamespace>
9+
<AssemblyName>CleanArchitecture.ServiceDefaults</AssemblyName>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
14+
15+
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
16+
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" />
17+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
18+
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
19+
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
20+
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
21+
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
22+
</ItemGroup>
23+
24+
</Project>

0 commit comments

Comments
 (0)