using Asp.Versioning; using FluentValidation; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.Options; using Vegasco.WebApi.Authentication; using Vegasco.WebApi.Persistence; namespace Vegasco.WebApi.Common; public static class DependencyInjectionExtensions { /// /// Adds all the WebApi related services to the Dependency Injection container. /// /// public static void AddWebApiServices(this IHostApplicationBuilder builder) { builder.Services .AddMiscellaneousServices() .AddCustomOpenApi() .AddApiVersioning() .AddAuthenticationAndAuthorization(builder.Environment); builder.AddDbContext(); } private static IServiceCollection AddMiscellaneousServices(this IServiceCollection services) { services.AddResponseCompression(); services.AddValidatorsFromAssemblies( [ typeof(IWebApiMarker).Assembly ], ServiceLifetime.Singleton); services.AddHealthChecks(); services.AddHttpContextAccessor(); services.AddHostedService(); return services; } private static IServiceCollection AddCustomOpenApi(this IServiceCollection services) { services.AddEndpointsApiExplorer(); services.AddOpenApi(o => { o.CreateSchemaReferenceId = jsonTypeInfo => { if (string.IsNullOrEmpty(jsonTypeInfo.Type.FullName)) { return jsonTypeInfo.Type.Name; } string? fullClassName = jsonTypeInfo.Type.FullName; if (!string.IsNullOrEmpty(jsonTypeInfo.Type.Namespace)) { fullClassName = fullClassName .Replace(jsonTypeInfo.Type.Namespace, "") .TrimStart('.'); } fullClassName = fullClassName.Replace('+', '_'); return fullClassName; }; }); return services; } private static IServiceCollection AddApiVersioning(this IServiceCollection services) { services.AddApiVersioning(o => { o.DefaultApiVersion = new ApiVersion(1); o.ApiVersionReader = new UrlSegmentApiVersionReader(); o.ReportApiVersions = true; }) .AddApiExplorer(o => { o.GroupNameFormat = "'v'V"; o.SubstituteApiVersionInUrl = true; }); return services; } private static IServiceCollection AddAuthenticationAndAuthorization(this IServiceCollection services, IHostEnvironment environment) { services.AddOptions() .BindConfiguration(JwtOptions.SectionName) .ValidateFluently() .ValidateOnStart(); var jwtOptions = services.BuildServiceProvider().GetRequiredService>(); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o => { o.MetadataAddress = jwtOptions.Value.MetadataUrl; o.TokenValidationParameters.ValidAudience = jwtOptions.Value.ValidAudience; o.TokenValidationParameters.ValidateAudience = true; if (!string.IsNullOrWhiteSpace(jwtOptions.Value.NameClaimType)) { o.TokenValidationParameters.NameClaimType = jwtOptions.Value.NameClaimType; } o.RequireHttpsMetadata = !jwtOptions.Value.AllowHttpMetadataUrl && !environment.IsDevelopment(); }); services.AddAuthorizationBuilder() .AddPolicy(Constants.Authorization.RequireAuthenticatedUserPolicy, p => p .RequireAuthenticatedUser() .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)); services.AddScoped(); return services; } private static IHostApplicationBuilder AddDbContext(this IHostApplicationBuilder builder) { builder.AddNpgsqlDbContext(Server.AppHost.Shared.Constants.Database.Name); return builder; } }