Migrate legacy VB.NET service to modern C# Worker
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.
This commit is contained in:
@@ -1,24 +1,111 @@
|
||||
namespace EnvelopeGenerator.Service
|
||||
using DigitalData.Modules.Database;
|
||||
using EnvelopeGenerator.Service.Schedulers;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace EnvelopeGenerator.Service;
|
||||
|
||||
public sealed class Worker : BackgroundService
|
||||
{
|
||||
public 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)
|
||||
{
|
||||
private readonly ILogger<Worker> _logger;
|
||||
_logger = logger;
|
||||
_config = config.Value;
|
||||
_connectionString = configuration.GetConnectionString("Default")
|
||||
?? throw new InvalidOperationException("ConnectionStrings:Default is not configured.");
|
||||
_tempFiles = tempFiles;
|
||||
_schedulerFinishEnvelope = schedulerFinishEnvelope;
|
||||
_schedulerEnvelopeTaskApi = schedulerEnvelopeTaskApi;
|
||||
}
|
||||
|
||||
public Worker(ILogger<Worker> logger)
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger = logger;
|
||||
_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);
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
if (_logger.IsEnabled(LogLevel.Information))
|
||||
{
|
||||
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
|
||||
}
|
||||
await Task.Delay(1000, stoppingToken);
|
||||
}
|
||||
// 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!");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user