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