Files
DigitalData.MessagingService/src/presentation/DigitalData.MessagingService.API/Program.cs
TekH 0d9d15032f Refactor email handling for multiple recipients
Refactored the `Email` and `OutgoingEmailEvent` classes to replace the `Recipient` property with a `Recipients` collection, enabling support for multiple recipients. Updated all related test cases, including `EmailSenderTests`, `EmailSenderUrlOverloadTests`, and `OutgoingEmailPublisherTests`, to reflect this change.

Moved the `EmailAccountDto` class and its references from the `DigitalData.MessagingService.Application.Common.Dtos` namespace to the `DigitalData.MessagingService.Publisher.Abstraction` namespace for better code organization. Updated `using` directives across affected files.

Removed unused `using` directives and updated the `Email` class's `ToEvent` method to map the new `Recipients` property. Adjusted test assertions to validate collections instead of single recipient strings.
2026-08-05 13:11:19 +02:00

125 lines
4.6 KiB
C#

using DigitalData.MessagingService.API.Middleware;
using DigitalData.MessagingService.Application;
using DigitalData.MessagingService.Infrastructure;
using Serilog;
using Serilog.Ui.Core.Extensions;
using Serilog.Ui.SqliteDataProvider.Extensions;
using Serilog.Ui.Web.Extensions;
// Build temporary configuration to read log directory early
var tempConfig = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
.AddJsonFile("appsettings.Secrets.json", optional: true, reloadOnChange: false)
.Build();
var logDirectoryRaw = tempConfig.GetValue<string>("Application:LogDirectory") ?? "logs";
// Always resolve to an absolute path so sink and UI provider point to the same file
var logDirectory = Path.IsPathRooted(logDirectoryRaw)
? logDirectoryRaw
: Path.Combine(AppContext.BaseDirectory, logDirectoryRaw);
Directory.CreateDirectory(logDirectory);
var sqliteDbPath = Path.Combine(logDirectory, "logs.db");
// Configure Serilog early (bootstrap + full pipeline)
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore", Serilog.Events.LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", Serilog.Events.LogEventLevel.Warning)
.MinimumLevel.Override("System", Serilog.Events.LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.File(
path: Path.Combine(logDirectory, "emailprofiler-.log"),
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 30,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.SQLite(sqliteDbPath, storeTimestampInUtc: true)
.CreateBootstrapLogger();
try
{
Log.Information("Starting MessagingService API");
var builder = WebApplication.CreateBuilder(args);
// Use Serilog for logging
builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
.WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.File(
path: Path.Combine(logDirectory, "emailprofiler-.log"),
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 30,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.SQLite(sqliteDbPath, storeTimestampInUtc: true));
// Add appsettings.Secrets.json for sensitive configuration (not committed to git)
builder.Configuration.AddJsonFile("appsettings.Secrets.json", optional: true, reloadOnChange: true);
// Register Application layer (MediatR, AutoMapper, FluentValidation)
builder.Services.AddApplicationServices(builder.Configuration);
// Register Infrastructure layer (RabbitMQ, Repositories, etc.)
builder.Services.AddInfrastructure(builder.Configuration);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Register Serilog.UI with SQLite provider for web log viewer
builder.Services.AddSerilogUi(options =>
{
options.UseSqliteServer(dbOpt =>
{
dbOpt.WithConnectionString($"Data Source={sqliteDbPath}");
dbOpt.WithTable("Logs");
});
});
var app = builder.Build();
// Add global exception handling middleware
app.UseMiddleware<ExceptionHandlingMiddleware>();
// Add Serilog request logging
app.UseSerilogRequestLogging();
// Configure Swagger — enabled in Development always, and in other environments based on appsettings
var swaggerEnabled = app.Environment.IsDevelopment()
|| app.Configuration.GetValue<bool>("Swagger:Enabled");
if (swaggerEnabled)
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
// Serve Serilog.UI log viewer at /serilog-ui
app.UseSerilogUi();
app.UseAuthorization();
app.MapControllers();
Log.Information("MessagingService API started successfully");
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "MessagingService API failed to start");
throw;
}
finally
{
Log.CloseAndFlush();
}