From 21ad138c962133a8c9f865f587ea95bf53b1b11e Mon Sep 17 00:00:00 2001
From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com>
Date: Sun, 15 Feb 2026 08:15:07 -0600
Subject: [PATCH] feat: aspirify the solution
---
.aspire/settings.json | 3 +
FiscalOS.sln | 28 ++++++
src/Directory.Packages.props | 9 +-
src/FiscalOS.API/FiscalOS.API.csproj | 1 +
src/FiscalOS.API/Program.cs | 6 ++
.../Properties/launchSettings.json | 2 +-
src/FiscalOS.AppHost/AppHost.cs | 6 ++
src/FiscalOS.AppHost/FiscalOS.AppHost.csproj | 15 ++++
.../Properties/launchSettings.json | 31 +++++++
.../FiscalOS.ServiceDefaults.csproj | 22 +++++
.../ServiceDefaultsExtensions.cs | 89 +++++++++++++++++++
src/FiscalOS.ServiceDefaults/Usings.cs | 10 +++
12 files changed, 220 insertions(+), 2 deletions(-)
create mode 100644 .aspire/settings.json
create mode 100644 src/FiscalOS.AppHost/AppHost.cs
create mode 100644 src/FiscalOS.AppHost/FiscalOS.AppHost.csproj
create mode 100644 src/FiscalOS.AppHost/Properties/launchSettings.json
create mode 100644 src/FiscalOS.ServiceDefaults/FiscalOS.ServiceDefaults.csproj
create mode 100644 src/FiscalOS.ServiceDefaults/ServiceDefaultsExtensions.cs
create mode 100644 src/FiscalOS.ServiceDefaults/Usings.cs
diff --git a/.aspire/settings.json b/.aspire/settings.json
new file mode 100644
index 0000000..6f21d44
--- /dev/null
+++ b/.aspire/settings.json
@@ -0,0 +1,3 @@
+{
+ "appHostPath": "../src/FiscalOS.AppHost/FiscalOS.AppHost.csproj"
+}
\ No newline at end of file
diff --git a/FiscalOS.sln b/FiscalOS.sln
index d67874e..0b60569 100644
--- a/FiscalOS.sln
+++ b/FiscalOS.sln
@@ -21,6 +21,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FiscalOS.Infra.Tests", "tes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FiscalOS.Core.Tests", "tests\FiscalOS.Core.Tests\FiscalOS.Core.Tests.csproj", "{2D9C02A9-C704-4275-88E9-1BBD3AC12700}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FiscalOS.AppHost", "src\FiscalOS.AppHost\FiscalOS.AppHost.csproj", "{B7E4D089-C0EA-4DF2-B828-D5B0E5332098}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FiscalOS.ServiceDefaults", "src\FiscalOS.ServiceDefaults\FiscalOS.ServiceDefaults.csproj", "{40804CFE-50CA-4C5B-864A-672C67C6A667}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -115,6 +119,30 @@ Global
{2D9C02A9-C704-4275-88E9-1BBD3AC12700}.Release|x64.Build.0 = Release|Any CPU
{2D9C02A9-C704-4275-88E9-1BBD3AC12700}.Release|x86.ActiveCfg = Release|Any CPU
{2D9C02A9-C704-4275-88E9-1BBD3AC12700}.Release|x86.Build.0 = Release|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Debug|x64.Build.0 = Debug|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Debug|x86.Build.0 = Debug|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Release|x64.ActiveCfg = Release|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Release|x64.Build.0 = Release|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Release|x86.ActiveCfg = Release|Any CPU
+ {B7E4D089-C0EA-4DF2-B828-D5B0E5332098}.Release|x86.Build.0 = Release|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Debug|x64.Build.0 = Debug|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Debug|x86.Build.0 = Debug|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Release|Any CPU.Build.0 = Release|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Release|x64.ActiveCfg = Release|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Release|x64.Build.0 = Release|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Release|x86.ActiveCfg = Release|Any CPU
+ {40804CFE-50CA-4C5B-864A-672C67C6A667}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 2591312..7b3cebf 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -13,5 +13,12 @@
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/src/FiscalOS.API/FiscalOS.API.csproj b/src/FiscalOS.API/FiscalOS.API.csproj
index 9bf99ec..95fa599 100644
--- a/src/FiscalOS.API/FiscalOS.API.csproj
+++ b/src/FiscalOS.API/FiscalOS.API.csproj
@@ -10,6 +10,7 @@
+
diff --git a/src/FiscalOS.API/Program.cs b/src/FiscalOS.API/Program.cs
index c69fcce..409bb9b 100644
--- a/src/FiscalOS.API/Program.cs
+++ b/src/FiscalOS.API/Program.cs
@@ -1,5 +1,9 @@
+using FiscalOS.ServiceDefaults;
+
var builder = WebApplication.CreateBuilder(args);
+builder.AddServiceDefaults();
+
builder.Services.AddValidation();
builder.Services.AddProblemDetails();
@@ -32,6 +36,8 @@ app.UseAuthentication();
app.UseAuthorization();
app.UseStatusCodePages();
+app.MapDefaultEndpoints();
+
app.MapAuthEndpoints();
app.MapAccountsEndpoints();
app.MapInstitutionsEndpoints();
diff --git a/src/FiscalOS.API/Properties/launchSettings.json b/src/FiscalOS.API/Properties/launchSettings.json
index 8f695e1..e27550b 100644
--- a/src/FiscalOS.API/Properties/launchSettings.json
+++ b/src/FiscalOS.API/Properties/launchSettings.json
@@ -18,6 +18,6 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
- },
+ }
}
}
diff --git a/src/FiscalOS.AppHost/AppHost.cs b/src/FiscalOS.AppHost/AppHost.cs
new file mode 100644
index 0000000..93c5cbb
--- /dev/null
+++ b/src/FiscalOS.AppHost/AppHost.cs
@@ -0,0 +1,6 @@
+var builder = DistributedApplication.CreateBuilder(args);
+
+var api = builder.AddProject("API")
+ .WithHttpHealthCheck("/health");
+
+builder.Build().Run();
\ No newline at end of file
diff --git a/src/FiscalOS.AppHost/FiscalOS.AppHost.csproj b/src/FiscalOS.AppHost/FiscalOS.AppHost.csproj
new file mode 100644
index 0000000..21fa935
--- /dev/null
+++ b/src/FiscalOS.AppHost/FiscalOS.AppHost.csproj
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+ 80a27726-36cc-4a4d-a55d-11af527158bc
+
+
+
diff --git a/src/FiscalOS.AppHost/Properties/launchSettings.json b/src/FiscalOS.AppHost/Properties/launchSettings.json
new file mode 100644
index 0000000..85a61ce
--- /dev/null
+++ b/src/FiscalOS.AppHost/Properties/launchSettings.json
@@ -0,0 +1,31 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:17104;http://localhost:15068",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21226",
+ "ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "https://localhost:23228",
+ "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22081"
+ }
+ },
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:15068",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19221",
+ "ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:18206",
+ "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20097"
+ }
+ }
+ }
+}
diff --git a/src/FiscalOS.ServiceDefaults/FiscalOS.ServiceDefaults.csproj b/src/FiscalOS.ServiceDefaults/FiscalOS.ServiceDefaults.csproj
new file mode 100644
index 0000000..8128a10
--- /dev/null
+++ b/src/FiscalOS.ServiceDefaults/FiscalOS.ServiceDefaults.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net10.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/FiscalOS.ServiceDefaults/ServiceDefaultsExtensions.cs b/src/FiscalOS.ServiceDefaults/ServiceDefaultsExtensions.cs
new file mode 100644
index 0000000..c965e8b
--- /dev/null
+++ b/src/FiscalOS.ServiceDefaults/ServiceDefaultsExtensions.cs
@@ -0,0 +1,89 @@
+namespace FiscalOS.ServiceDefaults;
+
+public static class ServiceDefaultsExtensions
+{
+ private const string HealthEndpointPath = "/health";
+ private const string AlivenessEndpointPath = "/alive";
+
+ public static TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+ {
+ builder.ConfigureOpenTelemetry();
+
+ builder.AddDefaultHealthChecks();
+
+ builder.Services.AddServiceDiscovery();
+
+ builder.Services.ConfigureHttpClientDefaults(static http =>
+ {
+ http.AddStandardResilienceHandler();
+ http.AddServiceDiscovery();
+ });
+
+ return builder;
+ }
+
+ public static TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+ {
+ builder.Logging.AddOpenTelemetry(logging =>
+ {
+ logging.IncludeFormattedMessage = true;
+ logging.IncludeScopes = true;
+ });
+
+ builder.Services.AddOpenTelemetry()
+ .WithMetrics(metrics => metrics.AddAspNetCoreInstrumentation()
+ .AddHttpClientInstrumentation()
+ .AddRuntimeInstrumentation()
+ )
+ .WithTracing(tracing => tracing.AddSource(builder.Environment.ApplicationName)
+ .AddAspNetCoreInstrumentation(tracing =>
+ tracing.Filter = context =>
+ context.Request.Path.StartsWithSegments(HealthEndpointPath, StringComparison.InvariantCultureIgnoreCase) is false &&
+ context.Request.Path.StartsWithSegments(AlivenessEndpointPath, StringComparison.InvariantCultureIgnoreCase) is false
+ )
+ .AddHttpClientInstrumentation()
+ );
+
+ builder.AddOpenTelemetryExporters();
+
+ return builder;
+ }
+
+ public static TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+ {
+ builder.Services.AddHealthChecks()
+ .AddCheck("self", static () => HealthCheckResult.Healthy(), ["live"]);
+
+ return builder;
+ }
+
+ public static WebApplication MapDefaultEndpoints(this WebApplication app)
+ {
+ ArgumentNullException.ThrowIfNull(app);
+
+ if (app.Environment.IsDevelopment())
+ {
+ app.MapHealthChecks(HealthEndpointPath);
+
+ app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions
+ {
+ Predicate = static r => r.Tags.Contains("live")
+ });
+ }
+
+ return app;
+ }
+
+ private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+ {
+ var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+
+ if (useOtlpExporter)
+ {
+ builder.Services.AddOpenTelemetry().UseOtlpExporter();
+ }
+
+ return builder;
+ }
+
+}
\ No newline at end of file
diff --git a/src/FiscalOS.ServiceDefaults/Usings.cs b/src/FiscalOS.ServiceDefaults/Usings.cs
new file mode 100644
index 0000000..9f29898
--- /dev/null
+++ b/src/FiscalOS.ServiceDefaults/Usings.cs
@@ -0,0 +1,10 @@
+global using Microsoft.AspNetCore.Builder;
+global using Microsoft.AspNetCore.Diagnostics.HealthChecks;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Diagnostics.HealthChecks;
+global using Microsoft.Extensions.Hosting;
+global using Microsoft.Extensions.Logging;
+
+global using OpenTelemetry;
+global using OpenTelemetry.Metrics;
+global using OpenTelemetry.Trace;
\ No newline at end of file