Compare commits

...

5 Commits

Author SHA1 Message Date
22b494a262 refactor(di): unify Application and Infrastructure DI registrations under a central method
- Added central AddEnvelopeGenerator extension to aggregate existing DI setups
- Introduced EGConfiguration for modular service registration
- Standardized configuration pattern for Application and Infrastructure layers
- Simplified distributed cache and localization registration
2025-11-03 08:44:22 +01:00
209785dda5 refactor(DependencyInjection): created to handle DependencyInjection 2025-10-31 11:31:39 +01:00
44ea893f05 move memory-cache injection to Application-layer 2025-10-31 10:58:22 +01:00
b4aa7984aa chore(Application): Update your packages with vulnerabilities
- Added `SixLabors.ImageSharp` (v3.1.12) to main package references.
- Added `System.Formats.Asn1` for all target frameworks:
  - net7.0 → v8.0.2
  - net8.0, net9.0 → v9.0.10
2025-10-31 10:34:25 +01:00
7c5a505ad1 add serilog 2025-10-31 10:23:11 +01:00
15 changed files with 206 additions and 46 deletions

View File

@@ -58,6 +58,12 @@ public static class DependencyInjection
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
}); });
// Add memory cache
services.AddMemoryCache();
// Register mail services
services.AddScoped<IEnvelopeMailService, EnvelopeMailService>();
return services; return services;
} }
} }

View File

@@ -25,19 +25,23 @@
<PackageReference Include="Otp.NET" Version="1.4.0" /> <PackageReference Include="Otp.NET" Version="1.4.0" />
<PackageReference Include="QRCoder" Version="1.6.0" /> <PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="QRCoder-ImageSharp" Version="0.10.0" /> <PackageReference Include="QRCoder-ImageSharp" Version="0.10.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageReference Include="UserManager" Version="1.1.3" /> <PackageReference Include="UserManager" Version="1.1.3" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="System.Formats.Asn1" Version="8.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
<PackageReference Include="System.Formats.Asn1" Version="9.0.10" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
<PackageReference Include="System.Formats.Asn1" Version="9.0.10" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -32,7 +32,7 @@ Public Class frmFinalizePDF
#Disable Warning BC40000 ' Type or member is obsolete #Disable Warning BC40000 ' Type or member is obsolete
Factory.Shared _ Factory.Shared _
.BehaveOnPostBuild(PostBuildBehavior.Ignore) _ .BehaveOnPostBuild(PostBuildBehavior.Ignore) _
.AddEnvelopeGeneratorInfrastructureServices( .AddEGInfrastructureServices(
Sub(opt) Sub(opt)
opt.AddDbTriggerParams( opt.AddDbTriggerParams(
Sub(triggers) Sub(triggers)

View File

@@ -72,7 +72,7 @@ Namespace Jobs
#Disable Warning BC40000 ' Type or member is obsolete #Disable Warning BC40000 ' Type or member is obsolete
Factory.Shared _ Factory.Shared _
.BehaveOnPostBuild(PostBuildBehavior.Ignore) _ .BehaveOnPostBuild(PostBuildBehavior.Ignore) _
.AddEnvelopeGeneratorInfrastructureServices( .AddEGInfrastructureServices(
Sub(opt) Sub(opt)
opt.AddDbTriggerParams( opt.AddDbTriggerParams(
Sub(triggers) Sub(triggers)

View File

@@ -0,0 +1,70 @@
using DigitalData.EmailProfilerDispatcher;
using DigitalData.UserManager.DependencyInjection;
using EnvelopeGenerator.Application;
using EnvelopeGenerator.Infrastructure;
using Microsoft.Extensions.Caching.SqlServer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using static EnvelopeGenerator.Infrastructure.DependencyInjection;
namespace EnvelopeGenerator.DependencyInjection;
public static class DependencyInjection
{
public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services, IConfiguration config, Action<EGConfiguration> options, Action<SqlServerCacheOptions> distributedCacheOptions)
{
var egConfig = new EGConfiguration();
options.Invoke(egConfig);
egConfig.RegisterAll(services);
// Add envelope generator services
#pragma warning disable CS0618
services.AddUserManager<EGDbContext>();
#pragma warning restore CS0618
services.AddDispatcher<EGDbContext>();
return services;
}
public record EGConfiguration
{
internal readonly Queue<Action<IServiceCollection>> ServiceRegs = new();
internal void RegisterAll(IServiceCollection services)
{
while (ServiceRegs.Count > 0)
ServiceRegs.Dequeue().Invoke(services);
}
public EGConfiguration AddLocalization()
{
ServiceRegs.Enqueue(s => s.AddLocalization());
return this;
}
public EGConfiguration AddDistributedSqlServerCache(Action<SqlServerCacheOptions> setupAction)
{
ServiceRegs.Enqueue(s => s.AddDistributedSqlServerCache(setupAction));
return this;
}
public EGConfiguration AddInfrastructure(Action<EGInfrastructureConfiguration> options)
{
#pragma warning disable CS0618
ServiceRegs.Enqueue(s => s.AddEGInfrastructureServices(options));
#pragma warning restore CS0618
return this;
}
public IConfiguration Configuration
{
set
{
#pragma warning disable CS0618
ServiceRegs.Enqueue(s => s.AddEnvelopeGeneratorServices(value));
#pragma warning restore CS0618
}
}
}
}

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.10" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
</ItemGroup>
</Project>

View File

@@ -10,6 +10,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.10" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.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" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -2,36 +2,62 @@ using EnvelopeGenerator.Application;
using EnvelopeGenerator.Finalizer; using EnvelopeGenerator.Finalizer;
using EnvelopeGenerator.Infrastructure; using EnvelopeGenerator.Infrastructure;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Serilog;
var builder = Host.CreateApplicationBuilder(args); // Load Serilog from appsettings.json
var config = builder.Configuration; Log.Logger = new LoggerConfiguration()
builder.Services.AddHostedService<Worker>(); .ReadFrom.Configuration(new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build())
.CreateLogger();
#region Add DB Context, EG Inf. and Services try
var cnnStrName = "Default"; {
var connStr = config.GetConnectionString(cnnStrName) var builder = Host.CreateApplicationBuilder(args);
?? throw new InvalidOperationException($"Connection string '{cnnStrName}' is missing in the application configuration.");
#pragma warning disable CS0618 // Type or member is obsolete // add serilog
builder.Services.AddEnvelopeGeneratorInfrastructureServices( builder.Logging.ClearProviders();
opt => builder.Logging.AddSerilog();
{
opt.AddDbTriggerParams(config); var config = builder.Configuration;
opt.AddDbContext((provider, options) => builder.Services.AddHostedService<Worker>();
#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.");
#pragma warning disable CS0618 // Type or member is obsolete
builder.Services.AddEGInfrastructureServices(
opt =>
{ {
var logger = provider.GetRequiredService<ILogger<EGDbContext>>(); opt.AddDbTriggerParams(config);
options.UseSqlServer(connStr) opt.AddDbContext((provider, options) =>
.LogTo(log => logger.LogInformation("{log}", log), Microsoft.Extensions.Logging.LogLevel.Trace) {
.EnableSensitiveDataLogging() var logger = provider.GetRequiredService<ILogger<EGDbContext>>();
.EnableDetailedErrors(); options.UseSqlServer(connStr)
.LogTo(log => logger.LogInformation("{log}", log), Microsoft.Extensions.Logging.LogLevel.Trace)
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
});
}); });
}); #pragma warning restore CS0618 // Type or member is obsolete
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
builder.Services.AddEnvelopeGeneratorServices(config); builder.Services.AddEnvelopeGeneratorServices(config);
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
#endregion Add DB Context, EG Inf. and Services #endregion Add DB Context, EG Inf. and Services
var host = builder.Build(); var host = builder.Build();
host.Run(); host.Run();
Log.Information("The worker was stopped.");
}
catch(Exception ex)
{
Log.Fatal(ex, "Worker could not be started!");
}
finally
{
Log.CloseAndFlush();
}

View File

@@ -4,5 +4,37 @@
"Default": "Information", "Default": "Information",
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
},
"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;"
},
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "Logs/log-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
} }
} }

View File

@@ -185,7 +185,7 @@ try
// Envelope generator serives // Envelope generator serives
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
builder.Services builder.Services
.AddEnvelopeGeneratorInfrastructureServices(opt => .AddEGInfrastructureServices(opt =>
{ {
opt.AddDbTriggerParams(config); opt.AddDbTriggerParams(config);
opt.AddDbContext((provider, options) => opt.AddDbContext((provider, options) =>

View File

@@ -38,10 +38,10 @@ namespace EnvelopeGenerator.Infrastructure
/// will be created per HTTP request (or per scope) within the dependency injection container. /// will be created per HTTP request (or per scope) within the dependency injection container.
/// </remarks> /// </remarks>
[Obsolete("Use IRepository")] [Obsolete("Use IRepository")]
public static IServiceCollection AddEnvelopeGeneratorInfrastructureServices(this IServiceCollection services, Action<Config> options) public static IServiceCollection AddEGInfrastructureServices(this IServiceCollection services, Action<EGInfrastructureConfiguration> options)
{ {
// configure custom options // configure custom options
options(new Config(services)); options(new EGInfrastructureConfiguration(services));
#if NET #if NET
services.TryAddScoped<IConfigRepository, ConfigRepository>(); services.TryAddScoped<IConfigRepository, ConfigRepository>();
services.TryAddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>(); services.TryAddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
@@ -160,11 +160,11 @@ namespace EnvelopeGenerator.Infrastructure
} }
#endif #endif
public class Config public class EGInfrastructureConfiguration
{ {
private readonly IServiceCollection _services; private readonly IServiceCollection _services;
internal Config(IServiceCollection services) internal EGInfrastructureConfiguration(IServiceCollection services)
{ {
_services = services; _services = services;
} }

View File

@@ -525,7 +525,7 @@ namespace EnvelopeGenerator.Infrastructure.Migrations
}); });
}); });
modelBuilder.Entity("EnvelopeGenerator.Domain.Entities.Config", b => modelBuilder.Entity("EnvelopeGenerator.Domain.Entities.EGInfrastructureConfiguration", b =>
{ {
b.Property<string>("ExportPath") b.Property<string>("ExportPath")
.HasColumnType("nvarchar(256)") .HasColumnType("nvarchar(256)")

View File

@@ -522,7 +522,7 @@ namespace EnvelopeGenerator.Infrastructure.Migrations
}); });
}); });
modelBuilder.Entity("EnvelopeGenerator.Domain.Entities.Config", b => modelBuilder.Entity("EnvelopeGenerator.Domain.Entities.EGInfrastructureConfiguration", b =>
{ {
b.Property<string>("ExportPath") b.Property<string>("ExportPath")
.HasColumnType("nvarchar(256)") .HasColumnType("nvarchar(256)")

View File

@@ -1,4 +1,3 @@
using EnvelopeGenerator.Application.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NLog; using NLog;
using Quartz; using Quartz;
@@ -16,7 +15,6 @@ using EnvelopeGenerator.Web.Sanitizers;
using EnvelopeGenerator.Web.Models.Annotation; using EnvelopeGenerator.Web.Models.Annotation;
using DigitalData.UserManager.DependencyInjection; using DigitalData.UserManager.DependencyInjection;
using EnvelopeGenerator.Web.Middleware; using EnvelopeGenerator.Web.Middleware;
using EnvelopeGenerator.Application.Common.Interfaces.Services;
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Info("Logging initialized!"); logger.Info("Logging initialized!");
@@ -103,7 +101,7 @@ try
// Add envelope generator services // Add envelope generator services
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
builder.Services.AddEnvelopeGeneratorInfrastructureServices( builder.Services.AddEGInfrastructureServices(
opt => opt =>
{ {
opt.AddDbTriggerParams(config); opt.AddDbTriggerParams(config);
@@ -186,15 +184,8 @@ try
builder.Services.Configure<Cultures>(config.GetSection("Cultures")); builder.Services.Configure<Cultures>(config.GetSection("Cultures"));
builder.Services.AddSingleton(sp => sp.GetRequiredService<IOptions<Cultures>>().Value); builder.Services.AddSingleton(sp => sp.GetRequiredService<IOptions<Cultures>>().Value);
// Register mail services
#pragma warning disable CS0618 // Type or member is obsolete
builder.Services.AddScoped<IEnvelopeMailService, EnvelopeMailService>();
#pragma warning restore CS0618 // Type or member is obsolete
builder.Services.AddDispatcher<EGDbContext>(); builder.Services.AddDispatcher<EGDbContext>();
builder.Services.AddMemoryCache();
builder.ConfigureBySection<CustomImages>(); builder.ConfigureBySection<CustomImages>();
builder.ConfigureBySection<AnnotationParams>(); builder.ConfigureBySection<AnnotationParams>();

View File

@@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.PdfEditor
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Finalizer", "EnvelopeGenerator.Finalizer\EnvelopeGenerator.Finalizer.csproj", "{49E6A4C0-C2FC-4A34-9821-245AF050CA26}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Finalizer", "EnvelopeGenerator.Finalizer\EnvelopeGenerator.Finalizer.csproj", "{49E6A4C0-C2FC-4A34-9821-245AF050CA26}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.DependencyInjection", "EnvelopeGenerator.DependencyInjection\EnvelopeGenerator.DependencyInjection.csproj", "{B97DE7DD-3190-4A84-85E9-E57AD735BE61}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -97,6 +99,10 @@ Global
{49E6A4C0-C2FC-4A34-9821-245AF050CA26}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{49E6A4C0-C2FC-4A34-9821-245AF050CA26}.Release|Any CPU.Build.0 = 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
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -118,6 +124,7 @@ Global
{6D56C01F-D6CB-4D8A-BD3D-4FD34326998C} = {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} {211619F5-AE25-4BA5-A552-BACAFE0632D3} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
{49E6A4C0-C2FC-4A34-9821-245AF050CA26} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB} {49E6A4C0-C2FC-4A34-9821-245AF050CA26} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
{B97DE7DD-3190-4A84-85E9-E57AD735BE61} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {73E60370-756D-45AD-A19A-C40A02DACCC7} SolutionGuid = {73E60370-756D-45AD-A19A-C40A02DACCC7}