Migrated the legacy VB.NET Windows Service to a modern C# Worker Service targeting .NET Framework 4.6.2. Key changes include: - Added `Microsoft.Extensions.Hosting.WindowsServices`, `NLog`, and `Quartz` for logging and scheduling. - Introduced `LogConfigFactory` to bridge `ServiceConfig` and `LogConfig` for Quartz jobs. - Rewrote `Worker` to handle the full service lifecycle, including database connection, temp file management, and scheduler initialization. - Implemented `SchedulerFinishEnvelope` and `SchedulerEnvelopeTaskApi` for Quartz job scheduling. - Created `TempFiles` for service-level temp file management. - Configured `NLog` for file and console logging. - Updated `appsettings.json` for connection strings and service-specific configuration. - Replaced legacy `ProjectInstaller` with `AddWindowsService()` for SCM integration.
112 lines
4.1 KiB
C#
112 lines
4.1 KiB
C#
using DigitalData.Modules.Database;
|
||
using EnvelopeGenerator.Service.Schedulers;
|
||
using Microsoft.Extensions.Options;
|
||
|
||
namespace EnvelopeGenerator.Service;
|
||
|
||
public sealed class Worker : BackgroundService
|
||
{
|
||
private readonly ILogger<Worker> _logger;
|
||
private readonly ServiceConfig _config;
|
||
private readonly string _connectionString;
|
||
private readonly TempFiles _tempFiles;
|
||
private readonly SchedulerFinishEnvelope _schedulerFinishEnvelope;
|
||
private readonly SchedulerEnvelopeTaskApi _schedulerEnvelopeTaskApi;
|
||
|
||
public Worker(
|
||
ILogger<Worker> logger,
|
||
IOptions<ServiceConfig> config,
|
||
IConfiguration configuration,
|
||
TempFiles tempFiles,
|
||
SchedulerFinishEnvelope schedulerFinishEnvelope,
|
||
SchedulerEnvelopeTaskApi schedulerEnvelopeTaskApi)
|
||
{
|
||
_logger = logger;
|
||
_config = config.Value;
|
||
_connectionString = configuration.GetConnectionString("Default")
|
||
?? throw new InvalidOperationException("ConnectionStrings:Default is not configured.");
|
||
_tempFiles = tempFiles;
|
||
_schedulerFinishEnvelope = schedulerFinishEnvelope;
|
||
_schedulerEnvelopeTaskApi = schedulerEnvelopeTaskApi;
|
||
}
|
||
|
||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("EnvelopeGenerator.Service starting...");
|
||
|
||
// 1. Validate connection string
|
||
if (string.IsNullOrWhiteSpace(_connectionString))
|
||
throw new InvalidOperationException("Connection string is empty!");
|
||
|
||
// 2. Build LogConfig (required by CommonServices jobs via JobDataMap)
|
||
var logConfig = LogConfigFactory.Create(_config);
|
||
_logger.LogInformation("DEBUG = {Debug}", _config.Debug);
|
||
|
||
// 3. Connect to DB and load GDPicture license
|
||
_logger.LogDebug("Initializing Database...");
|
||
var database = new MSSQLServer(logConfig, _connectionString);
|
||
|
||
if (!database.DBInitialized)
|
||
throw new InvalidOperationException("Database connection could not be established!");
|
||
|
||
_logger.LogDebug("Database initialized.");
|
||
|
||
var licenseKey = database.GetScalarValue(
|
||
"SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE' AND ACTIVE = 1") as string;
|
||
|
||
if (string.IsNullOrWhiteSpace(licenseKey))
|
||
throw new InvalidOperationException("GDPicture license could not be loaded!");
|
||
|
||
_logger.LogDebug("GDPicture license loaded.");
|
||
|
||
// 4. Create service-level temp directory
|
||
_tempFiles.Create();
|
||
|
||
// 5. Start FinalizeDocument scheduler
|
||
_logger.LogDebug("Initializing schedulers...");
|
||
await _schedulerFinishEnvelope.Start(licenseKey!, logConfig);
|
||
|
||
// 6. Delay between schedulers (legacy behavior preserved)
|
||
await Task.Delay(2500, stoppingToken);
|
||
|
||
// 7. Start API envelope scheduler
|
||
await _schedulerEnvelopeTaskApi.Start(logConfig);
|
||
|
||
_logger.LogInformation("EnvelopeGenerator.Service started!");
|
||
|
||
// 8. Wait for cancellation (service runs until stopped)
|
||
await Task.Delay(Timeout.Infinite, stoppingToken);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
// Normal shutdown <20> not an error
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "EnvelopeGenerator.Service encountered a fatal error during startup.");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
public override async Task StopAsync(CancellationToken cancellationToken)
|
||
{
|
||
_logger.LogInformation("EnvelopeGenerator.Service stopping...");
|
||
|
||
try
|
||
{
|
||
await _schedulerFinishEnvelope.Stop();
|
||
await _schedulerEnvelopeTaskApi.Stop();
|
||
_tempFiles.CleanUp();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "Error during service shutdown.");
|
||
}
|
||
|
||
await base.StopAsync(cancellationToken);
|
||
_logger.LogInformation("EnvelopeGenerator.Service stopped!");
|
||
}
|
||
}
|