From 5b89d794caed0418901479cd87ee7c2420cd6fed Mon Sep 17 00:00:00 2001 From: Rok Rejc Date: Mon, 8 Jun 2026 14:24:00 +0200 Subject: [PATCH] Upgrade to top-level program.cs --- src/apps/Rsdo.Concordancer.Api/Program.cs | 178 +++++++++++++----- .../Properties/launchSettings.json | 52 +++-- src/apps/Rsdo.Concordancer.Api/Startup.cs | 154 --------------- .../Framework/VersionInfoTableMetadata.cs | 2 +- 4 files changed, 160 insertions(+), 226 deletions(-) delete mode 100644 src/apps/Rsdo.Concordancer.Api/Startup.cs diff --git a/src/apps/Rsdo.Concordancer.Api/Program.cs b/src/apps/Rsdo.Concordancer.Api/Program.cs index 507919a..54578a4 100644 --- a/src/apps/Rsdo.Concordancer.Api/Program.cs +++ b/src/apps/Rsdo.Concordancer.Api/Program.cs @@ -1,52 +1,146 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Reflection; +using System.Text.Json.Serialization; +using Autofac; using Autofac.Extensions.DependencyInjection; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; +using Hangfire; +using Hangfire.PostgreSql; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.OpenApi; +using Rsdo.Concordancer.Api.Controllers; +using Rsdo.Concordancer.Api.Framework; +using Rsdo.Concordancer.Core.Constants; +using Rsdo.Concordancer.Data.CompositionRoot; +using Rsdo.Concordancer.Infrastructure.CompositionRoot; +using Rsdo.Concordancer.ServiceModel.Shared; +using Rsdo.Concordancer.Services.CompositionRoot; +using Rsdo.Concordancer.Services.Framework.Cache; using Serilog; -namespace Rsdo.Concordancer.Api; - -public class Program -{ - public static int Main(string[] args) +var builder = WebApplication.CreateBuilder( + new WebApplicationOptions() { - // Read configuration file - var configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json") - .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true) - .Build(); + Args = args, + WebRootPath = "./WebApp/build", + }); - // Create logger - Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger(); +builder.Host.UseSerilog( + (context, _, loggerConfiguration) => + { + loggerConfiguration.ReadFrom.Configuration(context.Configuration); + }); - // Run application - try - { - Log.Information("Starting web host"); - CreateHostBuilder(args).Build().Run(); - return 0; - } - catch (Exception e) - { - Log.Fatal(e, "Host terminated unexpectedly"); - return 1; - } - finally - { - Log.CloseAndFlush(); - } - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .UseSerilog() - .UseServiceProviderFactory(new AutofacServiceProviderFactory()) - .ConfigureWebHostDefaults( - webBuilder => +builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); +builder.Host.ConfigureContainer( + containerBuilder => + { + containerBuilder.RegisterModule(new ServicesModule()); + containerBuilder.RegisterModule(new InfrastructureModule()); + containerBuilder.RegisterModule(new DataModule()); + containerBuilder.RegisterBuildCallback( + (c) => + { + var warmUps = c.Resolve>(); + foreach (var warmUp in warmUps) { - webBuilder.UseStartup(); - webBuilder.UseWebRoot("./WebApp/build"); - }); -} \ No newline at end of file + warmUp.WarmUp(); + } + }); + }); + +builder.Services.AddCors( + opt => + { + opt.AddPolicy( + "CorsPolicy", + policy => + { + policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); + }); + }); + +builder.Services.AddControllers() + .AddJsonOptions( + opts => + { + // Bind strings to enums + opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); + +builder.Services.AddSwaggerGen( + c => + { + c.SwaggerDoc( + ServiceApiInfo.ApiGroupConcordancer, + info: new OpenApiInfo() + { + Title = $"{ServiceApiInfo.ServiceName} Concordancer API", + Version = $"v{ServiceApiInfo.ServiceVersion.ToString(3)}", + }); + c.SwaggerDoc( + ServiceApiInfo.ApiGroupDashboard, + info: new OpenApiInfo() + { + Title = $"{ServiceApiInfo.ServiceName} Dashboard API", + Version = $"v{ServiceApiInfo.ServiceVersion.ToString(3)}", + }); + + // enable attribute annotations + c.EnableAnnotations(); + + // include code documentation to the swagger doc + foreach (var assembly in new[] { Assembly.GetExecutingAssembly(), typeof(ExecutionResult).Assembly }) + { + var xmlFile = $"{assembly.GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + c.IncludeXmlComments(xmlPath); + } + }); + +builder.Services.AddHangfire( + x => + { + // It would be better to use ConnectionStringProvider, but in this case + // we would have to build the container which would (at this point) double singletons. + // So we are duplicated code from ConnectionStringProvider + var connectionString = builder.Configuration[ConfigurationKey.Database.MasterConnectionString]; + x.UsePostgreSqlStorage( + options => + { + options.UseNpgsqlConnection(connectionString); + }); + x.UseMediator(); + }); + +builder.Services.AddHangfireServer(); +builder.Services.AddHttpClient(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); +} + +app.UseSwagger(); +app.UseSwaggerUI( + c => + { + c.SwaggerEndpoint($"{ServiceApiInfo.ApiGroupConcordancer}/swagger.json", $"{ServiceApiInfo.ServiceName} Concordancer API"); + c.SwaggerEndpoint($"{ServiceApiInfo.ApiGroupDashboard}/swagger.json", $"{ServiceApiInfo.ServiceName} Dashboard API"); + }); + +app.UseStaticFiles(); +app.UseRouting(); +app.UseCors("CorsPolicy"); +app.UseAuthorization(); + +app.MapControllers(); +app.MapHangfireDashboard("/hangfire"); +app.MapFallbackToFile("index.html"); + +app.Run(); \ No newline at end of file diff --git a/src/apps/Rsdo.Concordancer.Api/Properties/launchSettings.json b/src/apps/Rsdo.Concordancer.Api/Properties/launchSettings.json index 1312489..ba901d4 100644 --- a/src/apps/Rsdo.Concordancer.Api/Properties/launchSettings.json +++ b/src/apps/Rsdo.Concordancer.Api/Properties/launchSettings.json @@ -1,31 +1,25 @@ { - "$schema": "http://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:9184", - "sslPort": 44312 + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger/index.html", + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger/index.html", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "swagger", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Rsdo.Concordancer.Api": { - "commandName": "Project", - "dotnetRunMessages": "true", - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} +} \ No newline at end of file diff --git a/src/apps/Rsdo.Concordancer.Api/Startup.cs b/src/apps/Rsdo.Concordancer.Api/Startup.cs deleted file mode 100644 index 147e9c5..0000000 --- a/src/apps/Rsdo.Concordancer.Api/Startup.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text.Json.Serialization; -using Autofac; -using Hangfire; -using Hangfire.PostgreSql; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.OpenApi; -using Rsdo.Concordancer.Api.Controllers; -using Rsdo.Concordancer.Api.Framework; -using Rsdo.Concordancer.Core.Constants; -using Rsdo.Concordancer.Data.CompositionRoot; -using Rsdo.Concordancer.Infrastructure.CompositionRoot; -using Rsdo.Concordancer.ServiceModel.Shared; -using Rsdo.Concordancer.Services.CompositionRoot; -using Rsdo.Concordancer.Services.Framework.Cache; -using Swashbuckle.AspNetCore.SwaggerGen; - -namespace Rsdo.Concordancer.Api; - -public class Startup -{ - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddCors( - opt => - { - opt.AddPolicy( - "CorsPolicy", - policy => - { - policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); - }); - }); - services.AddControllers() - .AddJsonOptions( - opts => - { - // Bind strings to enums - opts.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); - }); - services.AddSwaggerGen( - c => - { - c.SwaggerDoc( - ServiceApiInfo.ApiGroupConcordancer, - info: new OpenApiInfo() - { - Title = $"{ServiceApiInfo.ServiceName} Concordancer API", - Version = $"v{ServiceApiInfo.ServiceVersion.ToString(3)}", - }); - c.SwaggerDoc( - ServiceApiInfo.ApiGroupDashboard, - info: new OpenApiInfo() - { - Title = $"{ServiceApiInfo.ServiceName} Dashboard API", - Version = $"v{ServiceApiInfo.ServiceVersion.ToString(3)}", - }); - - // enable attribute annotations - c.EnableAnnotations(); - - // include code documentation to the swagger doc - ConfigureSwaggerApiDoc(c, Assembly.GetExecutingAssembly(), typeof(ExecutionResult).Assembly); - }); - services.AddHangfire( - x => - { - // It would be better to use ConnectionStringProvider, but in this case - // we would have to build the container which would (at this point) double singletons. - // So we are duplicated code from ConnectionStringProvider - var connectionString = Configuration[ConfigurationKey.Database.MasterConnectionString]; - x.UsePostgreSqlStorage( - options => - { - options.UseNpgsqlConnection(connectionString); - }); - x.UseMediator(); - }); - services.AddHangfireServer(); - services.AddHttpClient(); - } - - public void ConfigureSwaggerApiDoc(SwaggerGenOptions options, params Assembly[] assemblies) - { - foreach (var assembly in assemblies) - { - var xmlFile = $"{assembly.GetName().Name}.xml"; - var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - options.IncludeXmlComments(xmlPath); - } - } - - public void ConfigureContainer(ContainerBuilder builder) - { - builder.RegisterModule(new ServicesModule()); - builder.RegisterModule(new InfrastructureModule()); - builder.RegisterModule(new DataModule()); - builder.RegisterBuildCallback( - (c) => - { - var warmUps = c.Resolve>(); - foreach (var warmUp in warmUps) - { - warmUp.WarmUp(); - } - }); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseSwagger(); - app.UseSwaggerUI( - c => - { - c.SwaggerEndpoint($"{ServiceApiInfo.ApiGroupConcordancer}/swagger.json", $"{ServiceApiInfo.ServiceName} Concordancer API"); - c.SwaggerEndpoint($"{ServiceApiInfo.ApiGroupDashboard}/swagger.json", $"{ServiceApiInfo.ServiceName} Dashboard API"); - }); - - app.UseStaticFiles(); - app.UseRouting(); - app.UseCors("CorsPolicy"); - app.UseAuthorization(); - - app.UseEndpoints( - endpoints => - { - endpoints.MapControllers(); - endpoints.MapHangfireDashboard("/hangfire"); - endpoints.MapFallbackToFile("index.html"); - }); - } -} \ No newline at end of file diff --git a/src/core/Rsdo.Concordancer.Data/Framework/VersionInfoTableMetadata.cs b/src/core/Rsdo.Concordancer.Data/Framework/VersionInfoTableMetadata.cs index ba3347d..1b225fd 100644 --- a/src/core/Rsdo.Concordancer.Data/Framework/VersionInfoTableMetadata.cs +++ b/src/core/Rsdo.Concordancer.Data/Framework/VersionInfoTableMetadata.cs @@ -14,7 +14,7 @@ public class VersionInfoTableMetadata : IVersionTableMetaData public string UniqueIndexName => "uc_version"; - public bool CreateWithPrimaryKey => true; + public bool CreateWithPrimaryKey => false; public object ApplicationContext { get; set; }