using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using DataConnection; using DataConnection.EF; using DataConnection.Interfaces; using DataConnection.EF.DatabaseDiscovery; using DataConnection.Enums; using DataConnection.CredentialManagement; using CredentialManager; using Data_Coupler.Services; using Data_Coupler.BackgroundServices; using CredentialManager.Services; using System; using System.Threading.Tasks; // Registra il provider di encoding per ExcelDataReader (necessario per file .xls) System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); var builder = WebApplication.CreateBuilder(args); // Configurazione per Windows Service builder.Host.UseWindowsService(options => { options.ServiceName = "DataCouplerService"; }); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddWindowsService(); // Register Authentication Service builder.Services.AddSingleton(); // Configurazione logging per Windows Service if (OperatingSystem.IsWindows()) { builder.Logging.AddEventLog(); } #region Database Directory Path management string dbPath = string.Empty; try { if (OperatingSystem.IsWindows()) { // Per servizi Windows, usa una cartella con permessi appropriati var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); if (string.IsNullOrEmpty(appDataPath)) { // Fallback per servizi Windows appDataPath = @"C:\ProgramData"; } dbPath = Path.Combine(appDataPath, "Data_Coupler", "credentials.db"); } else if (OperatingSystem.IsLinux()) { dbPath = "/var/lib/Data_Coupler/credentials.db"; } else if (OperatingSystem.IsMacOS()) { dbPath = "/Library/Application Support/Data_Coupler/credentials.db"; } var dbDirectory = Path.GetDirectoryName(dbPath); if (!Directory.Exists(dbDirectory)) { Directory.CreateDirectory(dbDirectory!); // Per Windows, assicurati che la cartella abbia i permessi corretti if (OperatingSystem.IsWindows() && !string.IsNullOrEmpty(dbDirectory)) { var directoryInfo = new DirectoryInfo(dbDirectory); // Imposta permessi per consentire l'accesso al servizio } } Console.WriteLine($"Database path: {dbPath}"); } catch (Exception ex) { Console.WriteLine($"Errore nella configurazione del percorso database: {ex.Message}"); throw; } #endregion #region OLD DB PATH // // Add CredentialManager services // var contentRoot = builder.Environment.ContentRootPath; // var dataPath = Path.Combine(contentRoot, "wwwroot", "data"); // Directory.CreateDirectory(dataPath); // Assicurati che la directory esista // var dbPath = Path.Combine(dataPath, "credentials.db"); #endregion builder.Services.AddDataConnectionCredentialManagement($"Data Source={dbPath}"); // Register IHttpClientFactory builder.Services.AddHttpClient(); // Register Data Connection Factory builder.Services.AddScoped(); // Register Association Service (Pre-Discovery) builder.Services.AddScoped(); // Register Backup Service builder.Services.AddScoped(); // Register Schedule Services builder.Services.AddScoped(); // Register Data Transfer Service builder.Services.AddScoped(); // Register Scheduled Profile Execution Service builder.Services.AddScoped(); // Register Background Services (solo uno per evitare duplicazioni) builder.Services.AddHostedService(); // Configurazione URL e timeout per servizio Windows var urls = builder.Configuration.GetValue("Urls") ?? "http://*:7550"; builder.WebHost.UseUrls(urls); // Configurazione timeout per servizio Windows builder.WebHost.ConfigureKestrel(serverOptions => { serverOptions.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(10); serverOptions.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(5); }); var app = builder.Build(); // Initialize database con timeout e retry using (var scope = app.Services.CreateScope()) { var logger = scope.ServiceProvider.GetRequiredService>(); try { logger.LogInformation("Inizializzazione database in corso... Path: {DbPath}", dbPath); var dbInitializer = scope.ServiceProvider.GetRequiredService(); // Inizializzazione con timeout di 60 secondi var initTask = dbInitializer.InitializeAsync(); var timeoutTask = Task.Delay(TimeSpan.FromSeconds(60)); var completedTask = await Task.WhenAny(initTask, timeoutTask); if (completedTask == timeoutTask) { logger.LogError("Timeout durante l'inizializzazione del database (60 secondi)"); throw new TimeoutException("Timeout durante l'inizializzazione del database"); } await initTask; // Attendi il completamento per eventuali eccezioni logger.LogInformation("Database inizializzato con successo."); } catch (Exception ex) { logger.LogError(ex, "Errore durante l'inizializzazione del database: {Message}. Path: {DbPath}", ex.Message, dbPath); // Per servizi Windows, log su Event Log if (OperatingSystem.IsWindows()) { try { using var eventLog = new System.Diagnostics.EventLog("Application"); eventLog.Source = "DataCouplerService"; eventLog.WriteEntry($"Errore inizializzazione database: {ex.Message}", System.Diagnostics.EventLogEntryType.Error); } catch { // Ignora errori di scrittura EventLog } } throw; // Rilancia l'eccezione per non far partire l'app con un database non funzionante } } // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // 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.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); app.Run();