Den is the private cloud vault for your reminders, calendars and to-dos.
at main 170 lines 6.8 kB view raw
1using Microsoft.AspNetCore.Authorization; 2using Microsoft.AspNetCore.Builder; 3using Microsoft.AspNetCore.Diagnostics.HealthChecks; 4using Microsoft.Extensions.DependencyInjection; 5using Microsoft.Extensions.Diagnostics.HealthChecks; 6using Microsoft.Extensions.Logging; 7using Microsoft.Extensions.ServiceDiscovery; 8using Microsoft.OpenApi.Models; 9using OpenTelemetry; 10using OpenTelemetry.Metrics; 11using OpenTelemetry.Trace; 12 13#pragma warning disable IDE0130 // Namespace does not match folder structure 14namespace Microsoft.Extensions.Hosting; 15#pragma warning restore IDE0130 // Namespace does not match folder structure 16 17// Adds common Aspire services: service discovery, resilience, health checks, and OpenTelemetry. 18// This project should be referenced by each service project in your solution. 19// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults 20public static class Extensions 21{ 22 private const string HealthEndpointPath = "/healthz"; 23 private const string AlivenessEndpointPath = "/livez"; 24 25 public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder, bool isApi = true) where TBuilder : IHostApplicationBuilder 26 { 27 builder.ConfigureOpenTelemetry(); 28 29 builder.AddDefaultHealthChecks(); 30 31 builder.Services.AddServiceDiscovery(); 32 33 if (isApi) 34 { 35 builder.Services.AddOpenApi(options => 36 { 37 options.AddDocumentTransformer((document, context, cancellationToken) => 38 { 39 document.Components ??= new(); 40 document.Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>(); 41 document.Components.SecuritySchemes["Bearer"] = new() 42 { 43 Type = SecuritySchemeType.Http, 44 Scheme = "bearer", 45 BearerFormat = "JWT", 46 Description = "JWT Authorization header using the Bearer scheme" 47 }; 48 49 return Task.CompletedTask; 50 }); 51 52 options.AddOperationTransformer((operation, context, cancellationToken) => 53 { 54 var metadata = context.Description.ActionDescriptor.EndpointMetadata; 55 56 var hasAuthorize = metadata.OfType<AuthorizeAttribute>().Any(); 57 var hasAllowAnonymous = metadata.OfType<AllowAnonymousAttribute>().Any(); 58 59 if (hasAuthorize && !hasAllowAnonymous) 60 { 61 operation.Security = new List<OpenApiSecurityRequirement> 62 { 63 new() 64 { 65 [new OpenApiSecurityScheme 66 { 67 Reference = new OpenApiReference 68 { 69 Type = ReferenceType.SecurityScheme, 70 Id = "Bearer" 71 } 72 }] = Array.Empty<string>() 73 } 74 }; 75 } 76 77 return Task.CompletedTask; 78 }); 79 }); 80 } 81 82 builder.Services.ConfigureHttpClientDefaults(http => 83 { 84 // Turn on resilience by default 85 http.AddStandardResilienceHandler(); 86 87 // Turn on service discovery by default 88 http.AddServiceDiscovery(); 89 }); 90 91 builder.Services.Configure<ServiceDiscoveryOptions>(options => 92 options.AllowedSchemes = ["https"]); 93 94 return builder; 95 } 96 97 public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder 98 { 99 builder.Logging.AddOpenTelemetry(logging => 100 { 101 logging.IncludeFormattedMessage = true; 102 logging.IncludeScopes = true; 103 }); 104 105 builder.Services.AddOpenTelemetry() 106 .WithMetrics(metrics => 107 metrics.AddAspNetCoreInstrumentation() 108 .AddHttpClientInstrumentation() 109 .AddRuntimeInstrumentation() 110 ) 111 .WithTracing(tracing => 112 tracing.AddSource(builder.Environment.ApplicationName) 113 .AddAspNetCoreInstrumentation(tracing => 114 // Exclude health check requests from tracing 115 tracing.Filter = context => 116 !context.Request.Path.StartsWithSegments(HealthEndpointPath) 117 && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath) 118 ) 119 // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) 120 //.AddGrpcClientInstrumentation() 121 .AddHttpClientInstrumentation() 122 ); 123 124 builder.AddOpenTelemetryExporters(); 125 126 return builder; 127 } 128 129 private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder 130 { 131 var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); 132 133 if (useOtlpExporter) 134 { 135 builder.Services.AddOpenTelemetry().UseOtlpExporter(); 136 } 137 138 return builder; 139 } 140 141 public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder 142 { 143 builder.Services.AddHealthChecks() 144 // Add a default liveness check to ensure app is responsive 145 .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); 146 147 return builder; 148 } 149 150 public static WebApplication MapDefaultEndpoints(this WebApplication app) 151 { 152 // Adding health checks endpoints to applications in non-development environments has security implications. 153 // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. 154 if (app.Environment.IsDevelopment()) 155 { 156 app.MapOpenApi(); 157 158 // All health checks must pass for app to be considered ready to accept traffic after starting 159 app.MapHealthChecks(HealthEndpointPath); 160 161 // Only health checks tagged with the "live" tag must pass for app to be considered alive 162 app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions 163 { 164 Predicate = r => r.Tags.Contains("live") 165 }); 166 } 167 168 return app; 169 } 170}