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.
125 lines
4.6 KiB
C#
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();
|
|
}
|
|
|