Compare commits

..

No commits in common. "86c9fdfcd7c19a24b3987ea211e4b5e79544b0cd" and "b5cd42b6fa00f7d8f9b6103a922a494b4f7417e1" have entirely different histories.

9 changed files with 66 additions and 145 deletions

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
@ -8,14 +8,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Quartz.AspNetCore" Version="3.15.1" />
<PackageReference Include="Quartzmon" Version="1.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<PackageReference Include="Quartz" Version="3.15.1" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.15.1" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
@ -27,11 +21,7 @@
<ProjectReference Include="..\EnvelopeGenerator.DependencyInjection\EnvelopeGenerator.DependencyInjection.csproj" />
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.Database.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@ -0,0 +1,19 @@
namespace EnvelopeGenerator.Finalizer.Models;
public class WorkerOptions
{
private double _intervalInMin = 1.0;
public double IntervalInMin {
get => _intervalInMin;
set
{
_intervalInMin = value;
IntervalInMillisecond = Min2Millisecond(value);
}
}
public int IntervalInMillisecond { get; private set; } = Min2Millisecond(1.0);
private static int Min2Millisecond(double min) => Convert.ToInt32(Math.Round(min * 60 * 1000));
}

View File

@ -1,4 +1,3 @@
using CommandDotNet.Execution;
using EnvelopeGenerator.Application.ThirdPartyModules.Queries;
using EnvelopeGenerator.DependencyInjection;
using EnvelopeGenerator.Finalizer;
@ -6,10 +5,7 @@ using EnvelopeGenerator.Finalizer.Models;
using EnvelopeGenerator.Infrastructure;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Quartz;
using Quartz.AspNetCore;
using Quartz.Impl;
using Quartzmon;
using Microsoft.Extensions.Options;
using Serilog;
// Load Serilog from appsettings.json
@ -23,59 +19,24 @@ try
{
Log.Information("Application is starting...");
var builder = WebApplication.CreateBuilder(args);
var builder = Host.CreateApplicationBuilder(args);
#region Logging
// add serilog
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 AQuartz
builder.Services.AddQuartz(q =>
{
var name = $"{typeof(Worker).FullName}";
var jobKey = new JobKey(name);
q.AddJob<Worker>(opts => opts.WithIdentity(jobKey));
var expression = config[nameof(Worker) + ":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 " +
$"'{nameof(Worker)}:CronExpression'.");
q.AddTrigger(opts => opts
.ForJob(jobKey)
.WithIdentity(name + "-trigger")
.WithCronSchedule(expression));
});
builder.Services.AddQuartzServer(options =>
{
options.WaitForJobsToComplete = true;
});
builder.Services.AddQuartzmon();
builder.Services.AddSingleton(provider =>
provider.GetRequiredService<ISchedulerFactory>().GetScheduler().Result
);
#region Worker
builder.Services.AddHostedService<Worker>();
builder.Services.Configure<WorkerOptions>(config.GetSection("Worker"));
#endregion
#region Add DB Context, EG Inf. and Services
@ -97,9 +58,8 @@ try
opt.AddDbContext((provider, options) =>
{
var logger = provider.GetRequiredService<ILogger<EGDbContext>>();
var useInMemoryDb = config.GetValue<bool>("UseInMemoryDb");
var dbCtxOpt = useInMemoryDb ? options.UseInMemoryDatabase("EGInMemoryDb") : options.UseSqlServer(connStr);
dbCtxOpt.LogTo(log => logger.LogInformation("{log}", log), LogLevel.Trace)
options.UseSqlServer(connStr)
.LogTo(log => logger.LogInformation("{log}", log), LogLevel.Trace)
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
});
@ -109,45 +69,24 @@ try
#endregion Add DB Context, EG Inf. and Services
builder.Services.AddOptions<GdPictureOptions>()
.Configure((GdPictureOptions opt, IServiceProvider sp) =>
{
var licenseKey = "GDPICTURE";
using var scope = sp.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
opt.License = config["GdPictureLicenseKey"]
?? mediator.ReadThirdPartyModuleLicenseAsync(licenseKey).GetAwaiter().GetResult()
.Configure((GdPictureOptions opt, IServiceProvider sp) =>
{
var licenseKey = "GDPICTURE";
using var scope = sp.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
opt.License = mediator.ReadThirdPartyModuleLicenseAsync(licenseKey).GetAwaiter().GetResult()
?? throw new InvalidOperationException($"License record not found for key: {licenseKey}");
});
});
var app = builder.Build();
var host = builder.Build();
#region Web API Middleware
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
var licence = host.Services.GetRequiredService<IOptions<GdPictureOptions>>().Value;
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseQuartzmon(new QuartzmonOptions()
{
Scheduler = app.Services.GetRequiredService<IScheduler>(),
VirtualPathRoot = "/quartz"
});
app.MapControllers();
#endregion
app.Run();
host.Run();
Log.Information("The worker was stopped.");
}
catch (Exception ex)
catch(Exception ex)
{
Log.Fatal(ex, "Worker could not be started!");
}

View File

@ -1,41 +1,12 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:17119",
"sslPort": 44321
}
},
"profiles": {
"http": {
"EnvelopeGenerator.Finalizer": {
"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"
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}
}

View File

@ -1,26 +1,30 @@
using EnvelopeGenerator.Finalizer.Models;
using Microsoft.Extensions.Options;
using Quartz;
namespace EnvelopeGenerator.Finalizer
{
public class Worker : IJob
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
private readonly WorkerOptions _options;
public Worker(ILogger<Worker> logger, IOptions<WorkerOptions> workerOptions)
{
_logger = logger;
_options = workerOptions.Value;
}
public Task Execute(IJobExecutionContext context)
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
if (_logger.IsEnabled(LogLevel.Information))
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
if (_logger.IsEnabled(LogLevel.Information))
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
}
await Task.Delay(_options.IntervalInMillisecond, stoppingToken);
}
return Task.CompletedTask;
}
}
}
}

View File

@ -17,6 +17,5 @@
"EnvelopeReceiverReadOnly": [ "TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD" ],
"Receiver": [],
"EmailTemplate": [ "TBSIG_EMAIL_TEMPLATE_AFT_UPD" ]
},
"UseInMemoryDb": true
}
}

View File

@ -1,5 +1,5 @@
{
"Worker": {
"CronExpression": "* * * * * ?"
"IntervalInMin": 0.01666666666
}
}

View File

@ -1,3 +1,2 @@
{
"GdPictureLicenseKey": "kG1Qf9PwmqgR8aDmIW2zI_ebj48RzqAJegRxcystEmkbTGQqfkNBdFOXIb6C_A00Ra8zZkrHdfjqzOPXK7kgkF2YDhvrqKfqh4WDug2vOt0qO31IommzkANSuLjZ4zmraoubyEVd25rE3veQ2h_j7tGIoH_LyIHmy24GaXsxdG0yCzIBMdiLbMMMDwcPY-809KeZ83Grv76OVhFvcbBWyYc251vou1N-kGg5_ZlHDgfWoY85gTLRxafjD3KS_i9ARW4BMiy36y8n7UP2jN8kGRnW_04ubpFtfjJqvtsrP_J9D0x7bqV8xtVtT5JI6dpKsVTiMgDCrIcoFSo5gCC1fw9oUopX4TDCkBQttO4-WHBlOeq9dG5Yb0otonVmJKaQA2tP6sMR-lZDs3ql_WI9t91yPWgpssrJUxSHDd27_LMTH_owJIqkF3NOJd9mYQuAv22oNKFYbH8e41pVKb8cT33Y9CgcQ_sy6YDA5PTuIRi67mjKge_nD9rd0IN213Ir9M_EFWqg9e4haWzIdHXQUo0md70kVhPX4UIH_BKJnxEEnFfoFRNMh77bB0N4jkcBEHPl-ghOERv8dOztf4vCnNpzzWvcLD2cqWIm6THy8XGGq9h4hp8aEreRleSMwv9QQAC7mjLwhQ1rBYkpUHlpTjhTLnMwHknl6HH0Z6zzmsgkRKVyfquv94Pd7QbQfZrRka0ss_48pf9p8hAywEn81Q=="
}

View File

@ -37,9 +37,9 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EnvelopeGenerator.Form", "E
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.PdfEditor", "EnvelopeGenerator.PdfEditor\EnvelopeGenerator.PdfEditor.csproj", "{211619F5-AE25-4BA5-A552-BACAFE0632D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.DependencyInjection", "EnvelopeGenerator.DependencyInjection\EnvelopeGenerator.DependencyInjection.csproj", "{B97DE7DD-3190-4A84-85E9-E57AD735BE61}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Finalizer", "EnvelopeGenerator.Finalizer\EnvelopeGenerator.Finalizer.csproj", "{49E6A4C0-C2FC-4A34-9821-245AF050CA26}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Finalizer", "EnvelopeGenerator.Finalizer\EnvelopeGenerator.Finalizer.csproj", "{C4970E6C-DB2E-48C5-B3C5-2AF589405ED9}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.DependencyInjection", "EnvelopeGenerator.DependencyInjection\EnvelopeGenerator.DependencyInjection.csproj", "{B97DE7DD-3190-4A84-85E9-E57AD735BE61}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -95,14 +95,14 @@ Global
{211619F5-AE25-4BA5-A552-BACAFE0632D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{211619F5-AE25-4BA5-A552-BACAFE0632D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{211619F5-AE25-4BA5-A552-BACAFE0632D3}.Release|Any CPU.Build.0 = Release|Any CPU
{49E6A4C0-C2FC-4A34-9821-245AF050CA26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{49E6A4C0-C2FC-4A34-9821-245AF050CA26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{49E6A4C0-C2FC-4A34-9821-245AF050CA26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{49E6A4C0-C2FC-4A34-9821-245AF050CA26}.Release|Any CPU.Build.0 = Release|Any CPU
{B97DE7DD-3190-4A84-85E9-E57AD735BE61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B97DE7DD-3190-4A84-85E9-E57AD735BE61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B97DE7DD-3190-4A84-85E9-E57AD735BE61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B97DE7DD-3190-4A84-85E9-E57AD735BE61}.Release|Any CPU.Build.0 = Release|Any CPU
{C4970E6C-DB2E-48C5-B3C5-2AF589405ED9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -123,8 +123,8 @@ Global
{A9F9B431-BB9B-49B8-9E2C-0703634A653A} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{6D56C01F-D6CB-4D8A-BD3D-4FD34326998C} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{211619F5-AE25-4BA5-A552-BACAFE0632D3} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
{49E6A4C0-C2FC-4A34-9821-245AF050CA26} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{B97DE7DD-3190-4A84-85E9-E57AD735BE61} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{C4970E6C-DB2E-48C5-B3C5-2AF589405ED9} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {73E60370-756D-45AD-A19A-C40A02DACCC7}