Files
SomniaGuestLog/src/Somnia.GuestLog/Program.cs
T
Daniel-Garmig dcd5bb2aad Deploy configuration
- Added tasks for publishing as container image.
- Improvements for deployment: Db migrations on startup, reverse-proxy forward headers, and DataProtect management.
- Added deploy example using docker-compose.
2026-09-09 17:50:27 +02:00

169 lines
6.4 KiB
C#

using FluentStorage;
using FluentValidation;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Localization;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using MudBlazor.Services;
using Serilog;
using Serilog.Extensions.Logging;
using Somnia.GuestLog;
using Somnia.GuestLog.Components;
using Somnia.GuestLog.Infrastructure;
using Somnia.GuestLog.Models.Configuration;
using Somnia.GuestLog.Models.DTOs;
using Somnia.GuestLog.Services;
using Somnia.GuestLog.Services.AddressQuery;
using Somnia.GuestLog.Services.Entity;
using Somnia.GuestLog.Services.SpainCodigoMunicipio;
using Somnia.GuestLog.Services.StayExport;
using Somnia.GuestLog.Utils;
using Somnia.GuestLog.Validators;
var builder = WebApplication.CreateBuilder(args);
//Load config files.
builder.Configuration.AddJsonFile("Config/log_Config.json", optional: false, reloadOnChange: false);
builder.Configuration.AddEnvironmentVariables("SOMNIA_");
//Create and configure Logger (Serilog)
var serilog = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.CreateLogger();
builder.Services.AddSerilog(serilog);
var logger = new SerilogLoggerFactory(serilog).CreateLogger<Program>();
logger.LogInformation("\n\n\n -------------- Starting {appName} {appVersion} --------------", AppSettings.AppName, AppSettings.AppVersion);
if (!builder.Environment.IsDevelopment())
{
string dataProtectionPath = builder.Configuration.GetValue<string>("DataProtectionDir", defaultValue: "/SomniaGuestLog/dataprotection");
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(dataProtectionPath))
.SetApplicationName("SomniaGuestLog");
}
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
});
var connectionStringGuestLog = builder.Configuration.GetConnectionString("DbSomniaGuestLog")
?? throw new InvalidOperationException("Connection string 'DbSomniaGuestLog' not found.");
builder.Services.AddDbContextFactory<GuestLogContext>(options =>
{
options.UseNpgsql(connectionStringGuestLog)
.UseLazyLoadingProxies()
.ConfigureWarnings(w => w.Log((CoreEventId.NavigationLazyLoading, LogLevel.Warning)));
// The following options help with debugging, but should
// be changed or removed for production.
if (builder.Environment.IsDevelopment())
{
options.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
});
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
// Add MudBlazor services
builder.Services.AddMudServices(c =>
{
c.SnackbarConfiguration.PositionClass = MudBlazor.Defaults.Classes.Position.TopCenter;
c.SnackbarConfiguration.ShowTransitionDuration = 300;
c.SnackbarConfiguration.HideTransitionDuration = 500;
c.SnackbarConfiguration.VisibleStateDuration = 10000;
});
// Add components services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddLocalization();
builder.Services.AddHttpClient();
// Add Validation Services
builder.Services.AddSingleton<IValidator<GuestDocumentDTO>, GuestDocumentDTOValidator>();
builder.Services.AddSingleton<IValidator<GuestDocIdDTO>, GuestDocIdDTOValidator>();
builder.Services.AddSingleton<IValidator<StayEntryDTO>, StayEntryDTOValidator>();
builder.Services.AddSingleton<IValidator<StayExportParamsDTO>, StayExportParamsDTOValidator>();
// Add Entity Services
builder.Services.AddSingleton<IGuestDocumentEntityService, GuestDocumentEntityService>();
builder.Services.AddSingleton<IStayEntryEntityService, StayEntryEntityService>();
builder.Services.AddSingleton<IStayExportFileEntityService, StayExportFileEntityService>();
// Add Services
builder.Services.AddSingleton<IDataListService, StaticDataListService>();
builder.Services.AddScoped<IUserMessageService, UserMessageService>();
builder.Services.AddSingleton<ILocalizerService, LocalizerService>();
builder.Services.AddSingleton<IStayExportService, StayExportService>();
builder.Services.AddSingleton<ISpainCodigoMunicipioService, SpainCodigoMunicipioCatastroService>();
// Add Factories (and it's services)
builder.Services.AddFactoryDI<IAddressQueryFactory, ConfigFileAddressQueryFactory>();
builder.Services.AddFactoryDI<IStayExportFormatProviderFactory, StayExportFormatProviderFactory>();
// Add Options config
builder.Services.AddOptions<AddressQueryConfig>()
.Bind(builder.Configuration.GetSection(AddressQueryConfig.SectionName));
builder.Services.AddOptions<StayExportConfig>()
.Bind(builder.Configuration.GetSection(StayExportConfig.SectionName));
builder.Services.AddOptions<StayExportSpainParteViajerosConfig>()
.Bind(builder.Configuration.GetSection(StayExportSpainParteViajerosConfig.SectionName));
var app = builder.Build();
app.UseForwardedHeaders();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
app.UseHttpsRedirection();
app.UseAntiforgery();
string[] supportedCultures = ["en-US", "es-ES"];
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
localizationOptions.RequestCultureProviders = [
new QueryStringRequestCultureProvider(),
new CookieRequestCultureProvider()
];
app.UseRequestLocalization(localizationOptions);
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
//Activate S3 storage.
AwsS3Storage.Use();
//Run database migrations
bool runMigrationsOnStartup = builder.Configuration.GetValue<bool>("RunDatabaseMigrationOnStartup", defaultValue: true);
if (runMigrationsOnStartup)
{
logger.LogInformation("Running database migrations...");
using var scope = app.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<GuestLogContext>();
await db.Database.MigrateAsync();
logger.LogInformation("Database migrations OK");
}
app.Run();