Files
DocumentService/DocumentService.API/Program.cs
TekH 5e7652ef88 Refactor and rename to DocumentService
Renamed namespaces and projects from DocumentOperator to DocumentService, updating all references accordingly. Refactored PdfSignatureAppearanceDto and related enums to use properties with init accessors for improved clarity. Removed and re-added IPkcs11SelfTestStatusProvider with updated namespace. Simplified dependency injection by removing DocumentOperatorApplication registration. Updated appsettings.json with a specific AssetsRootPath. Incremented version numbers in project files for a new release. Introduced PdfSignatureClient and IPdfSignatureClient for PDF digital-signing operations. Updated project files to use newer Microsoft.Extensions package versions. Removed all DocumentOperator references, completing the transition to DocumentService. Added new DTOs and enums for PDF signature options and appearance.
2026-10-25 18:49:08 +01:00

149 lines
5.2 KiB
C#

using Serilog;
using Serilog.Ui.Core.Extensions;
using Serilog.Ui.SqliteDataProvider.Extensions;
using Serilog.Ui.Web.Extensions;
using Scalar.AspNetCore;
using DocumentService.Infrastructure.Configuration;
using DocumentService.Application;
using DocumentService.Application.Common.Configuration;
using DocumentService.Infrastructure;
using DocumentService.Infrastructure.Crypt.DependencyInjection;
using DocumentService.API.Middleware;
using DocumentService.API.Configuration;
var builder = WebApplication.CreateBuilder(args);
// ========================================
// 1. Serilog Configuration
// ========================================
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.Enrich.WithProperty("Application", "DocumentService")
.CreateLogger();
builder.Host.UseSerilog();
Log.Information("Starting DocumentService API...");
try
{
// ========================================
// 2. Options Pattern Configuration
// ========================================
builder.Services.Configure<DocumentServiceSettings>(
builder.Configuration.GetSection(DocumentServiceSettings.SectionName));
builder.Services.Configure<ZugferdSettings>(
builder.Configuration.GetSection("ZugferdSettings"));
builder.Services.Configure<RedisSettings>(
builder.Configuration.GetSection(RedisSettings.SectionName));
builder.Services.Configure<ApiKeySettings>(
builder.Configuration.GetSection(ApiKeySettings.SectionName));
builder.Services.Configure<SwaggerSettings>(
builder.Configuration.GetSection(SwaggerSettings.SectionName));
// ========================================
// 3. Services (Clean Architecture Layers)
// ========================================
builder.Services.AddApplication(builder.Configuration); // Application Layer (MediatR, FluentValidation, Behaviors)
builder.Services.AddInfrastructure(); // Infrastructure Layer (DevExpress, Services)
builder.Services.AddCryptInfrastructure(builder.Configuration); // PKCS#11 PDF signing (DevExpress)
builder.Services.AddControllers(); // Controllers (Controller-based API)
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerDocumentation(builder.Configuration);
// ========================================
// 4. Serilog.UI Configuration
// ========================================
var logDirectory = builder.Configuration.GetValue<string>("Application:LogDirectory")
?? throw new InvalidOperationException("Application:LogDirectory not found in configuration.");
var sqliteDbPath = Path.Combine(logDirectory, "logs.db");
builder.Services.AddSerilogUi(logUIOpt =>
{
logUIOpt.UseSqliteServer(dbOpt =>
{
dbOpt.WithConnectionString($"Data Source={sqliteDbPath}");
dbOpt.WithTable("Logs");
});
});
// ========================================
// 5. Build App
// ========================================
var app = builder.Build();
// ========================================
// 5. Middleware Pipeline (Order matters!)
// ========================================
// Exception Handling FIRST (catches all exceptions from subsequent middleware)
app.UseMiddleware<ExceptionHandlingMiddleware>();
// ========================================
// Swagger/OpenAPI (Conditional based on settings)
// ========================================
var swaggerSettings = builder.Configuration.GetSection(SwaggerSettings.SectionName).Get<SwaggerSettings>()
?? new SwaggerSettings();
if (app.Environment.IsDevelopment() || swaggerSettings.EnableInProduction)
{
app.UseSwagger();
// Swagger UI (classic)
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint($"/swagger/{swaggerSettings.Version}/swagger.json",
$"{swaggerSettings.Title} {swaggerSettings.Version}");
options.RoutePrefix = "swagger"; // /swagger
});
// Scalar UI (modern alternative)
app.MapScalarApiReference(options =>
{
options
.WithTitle(swaggerSettings.Title)
.WithTheme(ScalarTheme.DeepSpace)
.WithDefaultHttpClient(ScalarTarget.CSharp, ScalarClient.HttpClient);
});
}
app.UseSerilogRequestLogging(); // Log HTTP Requests
app.UseHttpsRedirection();
// ========================================
// 6. Serilog.UI Dashboard
// ========================================
app.UseSerilogUi(); // Accessible at /serilog-ui
// ========================================
// 7. Endpoints (Controller-based API)
// ========================================
app.MapControllers(); // Maps all [ApiController] controllers
Log.Information("DocumentService API started successfully");
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application startup failed");
throw;
}
finally
{
Log.CloseAndFlush();
}
// Make Program class accessible for Integration Tests
/// <summary>
/// Entry point class for the DocumentService API.
/// Made partial and public for integration test access.
/// </summary>
public partial class Program { }