From 8a48bf6b515ebc844a421ea874015ad421a45e9e Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 12 Nov 2025 10:17:37 +0100 Subject: [PATCH] feat(EnvelopeGenerator.Finalizer.Win): Create to process window-oriented services --- .../EnvelopeGenerator.Finalizer.Win.csproj | 44 ++++++ EnvelopeGenerator.Finalizer.Win/Extensions.cs | 35 +++++ .../Job/CreateReportJob.cs | 28 ++++ EnvelopeGenerator.Finalizer.Win/Program.cs | 128 ++++++++++++++++++ .../Properties/launchSettings.json | 41 ++++++ .../appsettings.Database.json | 22 +++ .../appsettings.Development.json | 9 ++ .../appsettings.Job.json | 8 ++ .../appsettings.Logging.json | 81 +++++++++++ .../appsettings.PdfBurner.json | 14 ++ .../appsettings.json | 3 + EnvelopeGenerator.sln | 7 + 12 files changed, 420 insertions(+) create mode 100644 EnvelopeGenerator.Finalizer.Win/EnvelopeGenerator.Finalizer.Win.csproj create mode 100644 EnvelopeGenerator.Finalizer.Win/Extensions.cs create mode 100644 EnvelopeGenerator.Finalizer.Win/Job/CreateReportJob.cs create mode 100644 EnvelopeGenerator.Finalizer.Win/Program.cs create mode 100644 EnvelopeGenerator.Finalizer.Win/Properties/launchSettings.json create mode 100644 EnvelopeGenerator.Finalizer.Win/appsettings.Database.json create mode 100644 EnvelopeGenerator.Finalizer.Win/appsettings.Development.json create mode 100644 EnvelopeGenerator.Finalizer.Win/appsettings.Job.json create mode 100644 EnvelopeGenerator.Finalizer.Win/appsettings.Logging.json create mode 100644 EnvelopeGenerator.Finalizer.Win/appsettings.PdfBurner.json create mode 100644 EnvelopeGenerator.Finalizer.Win/appsettings.json diff --git a/EnvelopeGenerator.Finalizer.Win/EnvelopeGenerator.Finalizer.Win.csproj b/EnvelopeGenerator.Finalizer.Win/EnvelopeGenerator.Finalizer.Win.csproj new file mode 100644 index 00000000..cf43df87 --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/EnvelopeGenerator.Finalizer.Win.csproj @@ -0,0 +1,44 @@ + + + + net8.0-windows + enable + enable + dotnet-EnvelopeGenerator.Finalizer.Win-6d5cc618-4159-4ff2-b600-8a15fbfa8099 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + diff --git a/EnvelopeGenerator.Finalizer.Win/Extensions.cs b/EnvelopeGenerator.Finalizer.Win/Extensions.cs new file mode 100644 index 00000000..5c0af349 --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/Extensions.cs @@ -0,0 +1,35 @@ +using EnvelopeGenerator.Finalizer.Job; +using Quartz; + +namespace EnvelopeGenerator.Finalizer; + +public static class Extensions +{ + public static IServiceCollectionQuartzConfigurator ScheduleJobDefault(this IServiceCollectionQuartzConfigurator q, + string croneEpression) + where TJob : IJob + { + var name = $"{typeof(TJob).FullName}"; + var jobKey = new JobKey(name); + + return q.ScheduleJob(trigger => trigger + .WithIdentity(name + "-trigger") + .WithCronSchedule(croneEpression), + job => job.WithIdentity(jobKey) + ); + } + + public static IServiceCollectionQuartzConfigurator ScheduleJobDefault(this IServiceCollectionQuartzConfigurator q, + IConfiguration configuration) + where TJob : IJob + { + var expression = configuration[$"{typeof(TJob).Name}:CronExpression"]; + if (string.IsNullOrWhiteSpace(expression)) + throw new InvalidOperationException( + "Cron expression for the Worker job is not configured. " + + "Please provide a valid cron schedule in the configuration under " + + $"'{typeof(TJob).FullName}:CronExpression'."); + + return q.ScheduleJobDefault(expression); + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/Job/CreateReportJob.cs b/EnvelopeGenerator.Finalizer.Win/Job/CreateReportJob.cs new file mode 100644 index 00000000..69328a7c --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/Job/CreateReportJob.cs @@ -0,0 +1,28 @@ +using EnvelopeGenerator.Application.Common.Configurations; +using MediatR; +using Microsoft.Extensions.Options; +using Quartz; + +namespace EnvelopeGenerator.Finalizer.Job +{ + public class CreateReportJob : IJob + { + private readonly ILogger _logger; + + private readonly IMediator _mediator; + + private readonly PDFBurnerParams _options; + + public CreateReportJob(ILogger logger, IMediator mediator, IOptions options) + { + _logger = logger; + _mediator = mediator; + _options = options.Value; + } + + public Task Execute(IJobExecutionContext context) + { + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/Program.cs b/EnvelopeGenerator.Finalizer.Win/Program.cs new file mode 100644 index 00000000..e88b0199 --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/Program.cs @@ -0,0 +1,128 @@ +using EnvelopeGenerator.DependencyInjection; +using EnvelopeGenerator.Finalizer; +using EnvelopeGenerator.Finalizer.Job; +using EnvelopeGenerator.Infrastructure; +using Microsoft.EntityFrameworkCore; +using Quartz; +using Quartz.AspNetCore; +using Quartzmon; +using Serilog; + +// Load Serilog from appsettings.json +Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(new ConfigurationBuilder() + .AddJsonFile("appsettings.Logging.json", optional: false, reloadOnChange: true) + .Build()) + .CreateLogger(); + +try +{ + Log.Information("Application is starting..."); + + var builder = WebApplication.CreateBuilder(args); + + #region Logging + builder.Logging.ClearProviders(); + builder.Logging.AddSerilog(); + #endregion + + #region Configuration + var config = builder.Configuration; + Directory + .GetFiles(builder.Environment.ContentRootPath, "appsettings.*.json", SearchOption.TopDirectoryOnly) + .Where(file => Path.GetFileName(file) != $"appsettings.Development.json") + .Where(file => Path.GetFileName(file) != $"appsettings.migration.json") + .ToList() + .ForEach(file => config.AddJsonFile(file, true, true)); + #endregion + + #region Web API Services + builder.Services.AddControllers(); + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + #endregion + + #region Quartz + builder.Services.AddQuartz(q => + { + q.ScheduleJobDefault(config); + }); + + builder.Services.AddQuartzServer(options => + { + options.WaitForJobsToComplete = true; + }); + + builder.Services.AddQuartzmon(); + + builder.Services.AddSingleton(provider => + provider.GetRequiredService().GetScheduler().Result + ); + #endregion + + #region Add DB Context, EG Inf. and Services + var cnnStrName = "Default"; + var connStr = config.GetConnectionString(cnnStrName) + ?? throw new InvalidOperationException($"Connection string '{cnnStrName}' is missing in the application configuration."); + + builder.Services.AddEnvelopeGenerator(egOptions => egOptions + .AddLocalization() + .AddDistributedSqlServerCache(options => + { + options.ConnectionString = connStr; + options.SchemaName = "dbo"; + options.TableName = "TBDD_CACHE"; + }) + .AddInfrastructure(opt => + { + opt.AddDbTriggerParams(config); + opt.AddDbContext((provider, options) => + { + var logger = provider.GetRequiredService>(); + var useInMemoryDb = config.GetValue("UseInMemoryDb"); + var dbCtxOpt = useInMemoryDb ? options.UseInMemoryDatabase("EGInMemoryDb") : options.UseSqlServer(connStr); + dbCtxOpt.LogTo(log => logger.LogInformation("{log}", log), LogLevel.Trace) + .EnableSensitiveDataLogging() + .EnableDetailedErrors(); + }); + }) + .AddServices(config, true) + ); + #endregion Add DB Context, EG Inf. and Services + + var app = builder.Build(); + + #region Web API Middleware + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + app.UseHttpsRedirection(); + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseQuartzmon(new QuartzmonOptions() + { + Scheduler = app.Services.GetRequiredService(), + VirtualPathRoot = "/quartz" + }); + + app.MapControllers(); + #endregion + + app.Run(); + + Log.Information("The worker was stopped."); +} +catch (Exception ex) +{ + Log.Fatal(ex, "Worker could not be started!"); +} +finally +{ + Log.CloseAndFlush(); +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/Properties/launchSettings.json b/EnvelopeGenerator.Finalizer.Win/Properties/launchSettings.json new file mode 100644 index 00000000..2e144339 --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:17119", + "sslPort": 44321 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5010", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "quartz", + "applicationUrl": "https://localhost:7141;http://localhost:5010", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": false, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/appsettings.Database.json b/EnvelopeGenerator.Finalizer.Win/appsettings.Database.json new file mode 100644 index 00000000..1c7059a7 --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/appsettings.Database.json @@ -0,0 +1,22 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "UseDbMigration": false, + "ConnectionStrings": { + "Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;", + "DbMigrationTest": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM_DATA_MIGR_TEST;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;" + }, + "DbTriggerParams": { + "Envelope": [ "TBSIG_ENVELOPE_AFT_INS" ], + "History": [ "TBSIG_ENVELOPE_HISTORY_AFT_INS" ], + "EmailOut": [ "TBEMLP_EMAIL_OUT_AFT_INS", "TBEMLP_EMAIL_OUT_AFT_UPD" ], + "EnvelopeReceiverReadOnly": [ "TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD" ], + "Receiver": [], + "EmailTemplate": [ "TBSIG_EMAIL_TEMPLATE_AFT_UPD" ] + }, + "UseInMemoryDb": false +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/appsettings.Development.json b/EnvelopeGenerator.Finalizer.Win/appsettings.Development.json new file mode 100644 index 00000000..7589f277 --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "Debug": true +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/appsettings.Job.json b/EnvelopeGenerator.Finalizer.Win/appsettings.Job.json new file mode 100644 index 00000000..45e1fd34 --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/appsettings.Job.json @@ -0,0 +1,8 @@ +{ + "FinishEnvelopeJob": { + "CronExpression": "* * * * * ?" + }, + "EnvelopeTaskApiJob": { + "CronExpression": "* * * * * ?" + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/appsettings.Logging.json b/EnvelopeGenerator.Finalizer.Win/appsettings.Logging.json new file mode 100644 index 00000000..2909cf07 --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/appsettings.Logging.json @@ -0,0 +1,81 @@ +{ + "Serilog": { + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], + "MinimumLevel": { + "Default": "Verbose", + "Override": { + "Microsoft": "Warning", + "System": "Warning" + } + }, + "WriteTo": [ + { + "Name": "Console", + "Args": { + "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "E:/LogFiles/Digital Data/signFlow.Finalizer/log.Verbose-.txt", + "rollingInterval": "Day", + "restrictedToMinimumLevel": "Verbose", + "retainedFileCountLimit": 30, + "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "E:/LogFiles/Digital Data/signFlow.Finalizer/log.Debug-.txt", + "rollingInterval": "Day", + "restrictedToMinimumLevel": "Debug", + "retainedFileCountLimit": 30, + "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "E:/LogFiles/Digital Data/signFlow.Finalizer/log.Info-.txt", + "rollingInterval": "Day", + "restrictedToMinimumLevel": "Information", + "retainedFileCountLimit": 30, + "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "E:/LogFiles/Digital Data/signFlow.Finalizer/log.Warning-.txt", + "rollingInterval": "Day", + "restrictedToMinimumLevel": "Warning", + "retainedFileCountLimit": 30, + "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "E:/LogFiles/Digital Data/signFlow.Finalizer/log.Error-.txt", + "rollingInterval": "Day", + "restrictedToMinimumLevel": "Error", + "retainedFileCountLimit": 30, + "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "E:/LogFiles/Digital Data/signFlow.Finalizer/log.Fatal-.txt", + "rollingInterval": "Day", + "restrictedToMinimumLevel": "Fatal", + "retainedFileCountLimit": 30, + "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" + } + } + ], + "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ] + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/appsettings.PdfBurner.json b/EnvelopeGenerator.Finalizer.Win/appsettings.PdfBurner.json new file mode 100644 index 00000000..3f0309cb --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/appsettings.PdfBurner.json @@ -0,0 +1,14 @@ +{ + "IgnoredLabels": { + "Label": [ + "Date", + "Datum", + "ZIP", + "PLZ", + "Place", + "Ort", + "Position", + "Stellung" + ] + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Finalizer.Win/appsettings.json b/EnvelopeGenerator.Finalizer.Win/appsettings.json new file mode 100644 index 00000000..68e67add --- /dev/null +++ b/EnvelopeGenerator.Finalizer.Win/appsettings.json @@ -0,0 +1,3 @@ +{ + "GdPictureLicenseKey": "kG1Qf9PwmqgR8aDmIW2zI_ebj48RzqAJegRxcystEmkbTGQqfkNBdFOXIb6C_A00Ra8zZkrHdfjqzOPXK7kgkF2YDhvrqKfqh4WDug2vOt0qO31IommzkANSuLjZ4zmraoubyEVd25rE3veQ2h_j7tGIoH_LyIHmy24GaXsxdG0yCzIBMdiLbMMMDwcPY-809KeZ83Grv76OVhFvcbBWyYc251vou1N-kGg5_ZlHDgfWoY85gTLRxafjD3KS_i9ARW4BMiy36y8n7UP2jN8kGRnW_04ubpFtfjJqvtsrP_J9D0x7bqV8xtVtT5JI6dpKsVTiMgDCrIcoFSo5gCC1fw9oUopX4TDCkBQttO4-WHBlOeq9dG5Yb0otonVmJKaQA2tP6sMR-lZDs3ql_WI9t91yPWgpssrJUxSHDd27_LMTH_owJIqkF3NOJd9mYQuAv22oNKFYbH8e41pVKb8cT33Y9CgcQ_sy6YDA5PTuIRi67mjKge_nD9rd0IN213Ir9M_EFWqg9e4haWzIdHXQUo0md70kVhPX4UIH_BKJnxEEnFfoFRNMh77bB0N4jkcBEHPl-ghOERv8dOztf4vCnNpzzWvcLD2cqWIm6THy8XGGq9h4hp8aEreRleSMwv9QQAC7mjLwhQ1rBYkpUHlpTjhTLnMwHknl6HH0Z6zzmsgkRKVyfquv94Pd7QbQfZrRka0ss_48pf9p8hAywEn81Q==" +} \ No newline at end of file diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln index 5f7e6228..de6117b4 100644 --- a/EnvelopeGenerator.sln +++ b/EnvelopeGenerator.sln @@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Dependenc EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Finalizer", "EnvelopeGenerator.Finalizer\EnvelopeGenerator.Finalizer.csproj", "{C4970E6C-DB2E-48C5-B3C5-2AF589405ED9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Finalizer.Win", "EnvelopeGenerator.Finalizer.Win\EnvelopeGenerator.Finalizer.Win.csproj", "{F4844CA5-8747-F32F-E938-45859A2AA422}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -103,6 +105,10 @@ Global {C4970E6C-DB2E-48C5-B3C5-2AF589405ED9}.Debug|Any CPU.Build.0 = Debug|Any CPU {C4970E6C-DB2E-48C5-B3C5-2AF589405ED9}.Release|Any CPU.ActiveCfg = Release|Any CPU {C4970E6C-DB2E-48C5-B3C5-2AF589405ED9}.Release|Any CPU.Build.0 = Release|Any CPU + {F4844CA5-8747-F32F-E938-45859A2AA422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F4844CA5-8747-F32F-E938-45859A2AA422}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F4844CA5-8747-F32F-E938-45859A2AA422}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F4844CA5-8747-F32F-E938-45859A2AA422}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -125,6 +131,7 @@ Global {211619F5-AE25-4BA5-A552-BACAFE0632D3} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB} {B97DE7DD-3190-4A84-85E9-E57AD735BE61} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB} {C4970E6C-DB2E-48C5-B3C5-2AF589405ED9} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB} + {F4844CA5-8747-F32F-E938-45859A2AA422} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {73E60370-756D-45AD-A19A-C40A02DACCC7}