From 27e7677db6686ede5bc086d0c2d13f65df8a6faa Mon Sep 17 00:00:00 2001 From: Bruno Garcia Date: Sat, 10 Feb 2024 18:29:15 -0500 Subject: [PATCH] merge startup and program --- src/NuGetTrends.Web/Program.cs | 234 +++++++++++++++++++++++---------- src/NuGetTrends.Web/Startup.cs | 127 ------------------ 2 files changed, 168 insertions(+), 193 deletions(-) delete mode 100644 src/NuGetTrends.Web/Startup.cs diff --git a/src/NuGetTrends.Web/Program.cs b/src/NuGetTrends.Web/Program.cs index 76f1d160..11193e0f 100644 --- a/src/NuGetTrends.Web/Program.cs +++ b/src/NuGetTrends.Web/Program.cs @@ -1,81 +1,183 @@ +using System.Reflection; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.OpenApi.Models; +using NuGetTrends.Data; using Serilog; +using Shortr; +using Shortr.Npgsql; +using Swashbuckle.AspNetCore.SwaggerUI; using SystemEnvironment = System.Environment; -using Sentry; -namespace NuGetTrends.Web; +const string Production = nameof(Production); +var environment = SystemEnvironment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? Production; -public static class Program +if (environment != Production) { - private const string Production = nameof(Production); - private static readonly string Environment - = SystemEnvironment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? Production; - - public static IConfiguration Configuration { get; private set; } = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{Environment}.json", optional: true) - .AddEnvironmentVariables() - .Build(); - - public static int Main(string[] args) - { - if (Environment != Production) - { - Serilog.Debugging.SelfLog.Enable(Console.Error); - } + Serilog.Debugging.SelfLog.Enable(Console.Error); +} + +var configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile($"appsettings.{environment}.json", optional: true) + .AddEnvironmentVariables() + .Build(); - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(Configuration) - .CreateLogger(); +Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(configuration) + .CreateLogger(); - try +try +{ + Log.Information("Starting."); + + var builder = WebApplication.CreateBuilder(args); + builder.Host.UseSerilog(); + builder.WebHost.UseConfiguration(configuration) + .UseSentry(o => { - Log.Information("Starting."); + o.SetBeforeSend(e => + { + if (e.Message?.Formatted is { } msg && msg.Contains( + "An error occurred using the connection to database '\"nugettrends\"' on server")) + { + e.Fingerprint = new[] { msg }; + } + + return e; + }); + o.CaptureFailedRequests = true; + o.TracesSampler = context => context.CustomSamplingContext.TryGetValue("__HttpPath", out var path) + && path is "/t" + ? 0 // tunneling JS events + : 1.0; + o.AddExceptionFilterForType(); + if (environment != Production) + { + o.EnableSpotlight = true; + } + }); - CreateHostBuilder(args).Build().Run(); + builder.Services.AddSentryTunneling(); // Add Sentry Tunneling to avoid ad-blockers. + builder.Services.AddControllers(); + builder.Services.AddHttpClient(); - return 0; - } - catch (Exception ex) + // In production, the Angular files will be served from this directory + builder.Services.AddSpaStaticFiles(c => c.RootPath = "Portal/dist"); + + if (environment != Production) + { + // keep cors during development so we can still run the spa on Angular default port (4200) + builder.Services.AddCors(options => + { + options.AddPolicy("AllowAll", + builder => + { + builder + .AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader() + .SetPreflightMaxAge(TimeSpan.FromDays(1)); + }); + }); + } + + builder.Services.AddDbContext(options => + { + var connString = configuration.GetNuGetTrendsConnectionString(); + options.UseNpgsql(connString); + if (environment != Production) + { + options.EnableSensitiveDataLogging(); + } + }); + + builder.Services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo {Title = "NuGet Trends", Version = "v1"}); + var xmlFile = Assembly.GetExecutingAssembly().GetName().Name + ".xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + c.IncludeXmlComments(xmlPath); + }); + + builder.Services.AddShortr(); + if (environment == Production) + { + builder.Services.Replace(ServiceDescriptor.Singleton()); + builder.Services.AddSingleton(_ => new NpgsqlShortrOptions + { + ConnectionString = configuration.GetNuGetTrendsConnectionString() + }); + } + + var app = builder.Build(); + + app.Use(async (context, next) => { + context.Response.OnStarting(() => { + // Sentry Browser Profiling + // https://docs.sentry.io/platforms/javascript/profiling/ + context.Response.Headers.Append("Document-Policy", "js-profiling"); + return Task.CompletedTask; + }); + await next(); + }); + + app.UseStaticFiles(); + if (!app.Environment.IsDevelopment()) + { + app.UseSpaStaticFiles(); + } + + app.UseRouting(); + app.UseSentryTracing(); + + if (app.Environment.IsDevelopment()) + { + app.UseCors("AllowAll"); + app.UseSwaggerUI(c => { - Log.Fatal(ex, "Host terminated unexpectedly"); - return 1; - } - finally + c.SwaggerEndpoint("/swagger/v1/swagger.json", "NuGet Trends"); + c.DocumentTitle = "NuGet Trends API"; + c.DocExpansion(DocExpansion.None); + }); + } + + // Proxy Sentry events from the frontend to sentry.io + // https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option + // https://docs.sentry.io/platforms/dotnet/guides/aspnetcore/#tunnel + app.UseSentryTunneling("/t"); + + app.UseSwagger(); +#pragma warning disable ASP0014 // Suggest using top level route registrations + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); +#pragma warning restore ASP0014 + + app.UseSpa(spa => + { + spa.Options.SourcePath = "Portal"; + if (app.Environment.IsDevelopment()) { - Log.CloseAndFlush(); + // use the external angular CLI server instead + spa.UseProxyToSpaDevelopmentServer("http://localhost:4200"); } - } + }); - private static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .UseSerilog() - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder - .UseConfiguration(Configuration) - .UseSentry(o => - { - o.SetBeforeSend(e => - { - if (e.Message?.Formatted is {} msg && msg.Contains( - "An error occurred using the connection to database '\"nugettrends\"' on server")) - { - e.Fingerprint = new []{msg}; - } - return e; - }); - o.CaptureFailedRequests = true; - o.TracesSampler = context => context.CustomSamplingContext.TryGetValue("__HttpPath", out var path) - && path is "/t" - ? 0 // tunneling JS events - : 1.0; - o.AddExceptionFilterForType(); - if (Environment != Production) - { - o.EnableSpotlight = true; - } - }) - .UseStartup(); - }); + app.UseShortr(); + + app.Run(); + + return 0; +} +catch (Exception ex) +{ + Log.Fatal(ex, "Host terminated unexpectedly"); + return 1; +} +finally +{ + Log.CloseAndFlush(); } diff --git a/src/NuGetTrends.Web/Startup.cs b/src/NuGetTrends.Web/Startup.cs deleted file mode 100644 index 2523bd6b..00000000 --- a/src/NuGetTrends.Web/Startup.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Reflection; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection.Extensions; -using NuGetTrends.Data; -using Swashbuckle.AspNetCore.SwaggerUI; -using Microsoft.OpenApi.Models; -using Shortr; -using Shortr.Npgsql; - -namespace NuGetTrends.Web; - -public class Startup(IConfiguration configuration, IWebHostEnvironment hostingEnvironment) -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddSentryTunneling(); // Add Sentry Tunneling to avoid ad-blockers. - services.AddControllers(); - services.AddHttpClient(); - - // In production, the Angular files will be served from this directory - services.AddSpaStaticFiles(c => - { - c.RootPath = "Portal/dist"; - }); - - if (hostingEnvironment.IsDevelopment()) - { - // keep cors during development so we can still run the spa on Angular default port (4200) - services.AddCors(options => - { - options.AddPolicy("AllowAll", - builder => - { - builder - .AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader() - .SetPreflightMaxAge(TimeSpan.FromDays(1)); - }); - }); - } - - services.AddDbContext(options => - { - var connString = configuration.GetNuGetTrendsConnectionString(); - options.UseNpgsql(connString); - if (hostingEnvironment.IsDevelopment()) - { - options.EnableSensitiveDataLogging(); - } - }); - - services.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new OpenApiInfo {Title = "NuGet Trends", Version = "v1"}); - var xmlFile = Assembly.GetExecutingAssembly().GetName().Name + ".xml"; - var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); - }); - - services.AddShortr(); - if (!hostingEnvironment.IsDevelopment()) - { - services.Replace(ServiceDescriptor.Singleton()); - services.AddSingleton(_ => new NpgsqlShortrOptions - { - ConnectionString = configuration.GetNuGetTrendsConnectionString() - }); - } - } - - public void Configure(IApplicationBuilder app) - { - app.Use(async (context, next) => { - context.Response.OnStarting(() => { - // Sentry Browser Profiling - // https://docs.sentry.io/platforms/javascript/profiling/ - context.Response.Headers.Append("Document-Policy", "js-profiling"); - return Task.CompletedTask; - }); - await next(); - }); - - app.UseStaticFiles(); - if (!hostingEnvironment.IsDevelopment()) - { - app.UseSpaStaticFiles(); - } - - app.UseRouting(); - app.UseSentryTracing(); - - if (hostingEnvironment.IsDevelopment()) - { - app.UseCors("AllowAll"); - app.UseSwaggerUI(c => - { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "NuGet Trends"); - c.DocumentTitle = "NuGet Trends API"; - c.DocExpansion(DocExpansion.None); - }); - } - - // Proxy Sentry events from the frontend to sentry.io - // https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option - // https://docs.sentry.io/platforms/dotnet/guides/aspnetcore/#tunnel - app.UseSentryTunneling("/t"); - - app.UseSwagger(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - - app.UseSpa(spa => - { - spa.Options.SourcePath = "Portal"; - if (hostingEnvironment.IsDevelopment()) - { - // use the external angular CLI server instead - spa.UseProxyToSpaDevelopmentServer("http://localhost:4200"); - } - }); - - app.UseShortr(); - } -}