using Fake.AspNetCore; using Fake.AspNetCore.Auditing; using Fake.AspNetCore.Authentication; using Fake.AspNetCore.ExceptionHandling; using Fake.AspNetCore.Newtonsoft; using Fake.AspNetCore.Swagger; using Fake.Autofac; using Fake.FeiShu; using Fake.Json; using Fake.Messaging.Dashboard; using Fake.Modularity; using Fake.Security.Claims; using Fake.Serilog; using FluentValidation.AspNetCore; using Hangfire; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Mvc.Authorization; using OpenTelemetry.Resources; using OpenTelemetry.Trace; using TrackCenter.Application; using TrackCenter.Application.Hangfire; using TrackCenter.Repository; using TrackCenter.Repository.Otel; using TrackCenter.Repository.Otel.Options; using TrackCenter.Application.Filters; namespace TrackCenter.Api; [DependsOn(typeof(FakeAutofacModule))] [DependsOn(typeof(FakeAspNetCoreModule))] [DependsOn(typeof(TrackCenterApplicationModule))] [DependsOn(typeof(TrackCenterRepositoryModule))] [DependsOn(typeof(FakeMessagingDashboardModule))] [DependsOn(typeof(FakeSerilogModule))] public class TrackCenterApiModule : FakeModule { private const string DefaultCorsPolicyName = "default"; public override void PreConfigureServices(ServiceConfigurationContext context) { FakeClaimTypes.UserId = "mapId"; } public override void ConfigureServices(ServiceConfigurationContext context) { var services = context.Services; var configuration = context.Services.GetConfiguration(); services.Configure(options => { options.ApplicationServices2Controller(); }); // 配置签名验证选项 services.Configure(configuration.GetSection("SignatureValidation")); // 全局授权配置:所有接口默认需要授权 services.AddMvc(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); // 添加签名验证过滤器 options.Filters.Add(); }).AddNewtonsoftJson(); //Json格式化全局处理 services.Configure(options => { options.InputDateTimeFormats.Add("yyyy-MM-dd HH:mm:ss"); options.LongToString = true; }); context.Services.AddFakeNewtonsoft(); services.AddFakeSwaggerGen(addSecurity:true) .AddFakeAspNetCoreAuditing() .AddFeiShuNotification(); services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters(); var otelOptions = new OTelOptions() { EnableAspNetCore = true, EnableHttpClient = true, EnableSql = true }; configuration.GetSection("OTel").Bind(otelOptions); ActivityHelper.InitActivitySource(otelOptions); services.AddOpenTelemetry() .ConfigureResource(resource => resource.AddService(otelOptions.ServiceName)) .WithTracing(tracing => { switch (otelOptions.SamplerType) { case SamplerType.AlwaysOn: tracing.SetSampler(new AlwaysOnSampler()); break; case SamplerType.AlwaysOff: tracing.SetSampler(new AlwaysOffSampler()); break; case SamplerType.ParentBasedSampler: { Sampler childSampler = otelOptions.ChildBasedSampler switch { SamplerType.AlwaysOn => new AlwaysOnSampler(), SamplerType.AlwaysOff => new AlwaysOffSampler(), SamplerType.TraceIdRatio => new TraceIdRatioBasedSampler(otelOptions.SamplerProbability), _ => new AlwaysOnSampler(), }; tracing.SetSampler(new ParentBasedSampler(childSampler)); } break; case SamplerType.TraceIdRatio: tracing.SetSampler(new TraceIdRatioBasedSampler(otelOptions.SamplerProbability)); break; default: tracing.SetSampler(new AlwaysOnSampler()); break; } tracing.AddSource(otelOptions.ServiceName); }); services.AddCors(options => { options.AddPolicy(DefaultCorsPolicyName, builder => { builder.WithOrigins(configuration.GetSection("App:CorsOrigins").Get() ?? []) .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); services.AddFakeJwtAuthentication(); // 添加授权服务 services.AddAuthorization(); services.Configure(options => { // 反向代理场景下恢复客户端真实来源信息,供 Swagger、鉴权和重定向等中间件使用 options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost; options.KnownNetworks.Clear(); options.KnownProxies.Clear(); }); } public override void ConfigureApplication(ApplicationConfigureContext context) { var app = context.GetWebApplication(); var configuration = context.GetConfiguration(); // 必须在读取 Scheme/Host/PathBase 的中间件之前执行,否则 Swagger 会生成错误的请求地址 app.UseForwardedHeaders(); app.Use(async (httpContext, next) => { httpContext.Request.EnableBuffering(); await next.Invoke(); }); // 虚拟路由-网关适配 app.UsePathBase(app.Configuration["ASPNETCORE_PATHBASE"]); app.UseFakeExceptionHandling(); app.MapControllers(); // Configure the HTTP request pipeline. app.UseFakeSwagger(); app.UseRouting(); app.UseCors(DefaultCorsPolicyName); app.UseHangfireDashboard("/hangfire", new DashboardOptions { DisplayStorageConnectionString = false, IgnoreAntiforgeryToken = true, // 「返回站点」链接;PathBase 已由 UsePathBase 处理,勿再设 PrefixPath,否则会变成 /track/track/hangfire/... AppPath = configuration["ASPNETCORE_PATHBASE"], DashboardTitle = "轨迹预警任务", Authorization = [new AnonymousHangfireAuthorizationFilter()] }); // 必须在 UsePathBase 之后:完整对外路径为 {PathBase}/eventbus app.UseFakeMessagingDashboard(); app.Services.GetRequiredService().Send("Application started"); } }