diff --git a/EnvelopeGenerator.Application/EnvelopeReceivers/Queries/ReadEnvelopeReceiverSecretQuery.cs b/EnvelopeGenerator.Application/EnvelopeReceivers/Queries/ReadEnvelopeReceiverSecretQuery.cs
new file mode 100644
index 00000000..e9fd1c20
--- /dev/null
+++ b/EnvelopeGenerator.Application/EnvelopeReceivers/Queries/ReadEnvelopeReceiverSecretQuery.cs
@@ -0,0 +1,127 @@
+using AutoMapper;
+using DigitalData.Core.Abstraction.Application.Repository;
+using EnvelopeGenerator.Application.Envelopes.Queries;
+using EnvelopeGenerator.Application.Receivers.Queries;
+using MediatR;
+using EnvelopeGenerator.Domain.Entities;
+using Microsoft.EntityFrameworkCore;
+using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
+using EnvelopeGenerator.Application.Common.Query;
+using EnvelopeGenerator.Application.Common.Extensions;
+
+namespace EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
+
+///
+/// Represents a query for reading an envelope receiver including sensitive fields
+/// (access code, phone number) that are excluded from the standard .
+///
+///
+/// Returns a single matched by UUID and receiver signature.
+/// Equivalent to the legacy ReadWithSecretByUuidSignatureAsync service method.
+///
+public record ReadEnvelopeReceiverSecretQuery
+ : EnvelopeReceiverQueryBase,
+ IRequest;
+
+///
+/// Extension methods for dispatching via .
+///
+public static class ReadEnvelopeReceiverSecretQueryExtensions
+{
+ ///
+ /// Sends a using the composite key (uuid::signature).
+ ///
+ /// The mediator instance.
+ /// Composite key in the format uuid::signature.
+ /// Cancellation token.
+ /// The matching , or null if not found.
+ public static Task ReadEnvelopeReceiverSecretAsync(
+ this IMediator mediator,
+ string key,
+ CancellationToken cancel = default)
+ => mediator.Send(new ReadEnvelopeReceiverSecretQuery { Key = key }, cancel);
+
+ ///
+ /// Sends a using UUID and receiver signature.
+ ///
+ /// The mediator instance.
+ /// Envelope UUID.
+ /// Receiver signature.
+ /// Cancellation token.
+ /// The matching , or null if not found.
+ public static Task ReadEnvelopeReceiverSecretAsync(
+ this IMediator mediator,
+ string uuid,
+ string signature,
+ CancellationToken cancel = default)
+ {
+ var q = new ReadEnvelopeReceiverSecretQuery();
+ q.Envelope.Uuid = uuid;
+ q.Receiver.Signature = signature;
+ return mediator.Send(q, cancel);
+ }
+
+ ///
+ /// Handles and returns a
+ /// containing sensitive fields.
+ ///
+ public class ReadEnvelopeReceiverSecretQueryHandler
+ : IRequestHandler
+ {
+ private readonly IRepository _repo;
+ private readonly IRepository _rcvRepo;
+ private readonly IMapper _mapper;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// Repository for .
+ /// Repository for .
+ /// AutoMapper instance.
+ public ReadEnvelopeReceiverSecretQueryHandler(
+ IRepository envelopeReceiver,
+ IRepository rcvRepo,
+ IMapper mapper)
+ {
+ _repo = envelopeReceiver;
+ _rcvRepo = rcvRepo;
+ _mapper = mapper;
+ }
+
+ ///
+ /// Handles the query and returns the matching .
+ ///
+ /// The query containing filter criteria.
+ /// Cancellation token.
+ ///
+ /// The matched , or null if no record is found.
+ ///
+ public async Task Handle(
+ ReadEnvelopeReceiverSecretQuery request,
+ CancellationToken cancel)
+ {
+ var q = _repo.Query.Where(request, notnull: false);
+
+ var envRcvs = await q
+ .Include(er => er.Envelope).ThenInclude(e => e!.Documents!).ThenInclude(d => d.Elements)
+ .Include(er => er.Envelope).ThenInclude(e => e!.Histories)
+ .Include(er => er.Envelope).ThenInclude(e => e!.User)
+ .Include(er => er.Receiver)
+ .ToListAsync(cancel);
+
+ if (request.Receiver.HasAnyCriteria && envRcvs.Count != 0)
+ {
+ var receiver = await _rcvRepo.Query.Where(request.Receiver).FirstAsync(cancel);
+
+ foreach (var item in envRcvs)
+ item.Envelope?.Documents?.FirstOrDefault()?.Elements?.RemoveAll(s => s.ReceiverId != receiver.Id);
+ }
+
+ var envRcv = envRcvs.FirstOrDefault();
+ if (envRcv is null)
+ return null;
+
+ return _mapper.Map(envRcv);
+ }
+ }
+}
diff --git a/EnvelopeGenerator.DependencyInjection/DependencyInjection.cs b/EnvelopeGenerator.DependencyInjection/DependencyInjection.cs
new file mode 100644
index 00000000..8bbbc853
--- /dev/null
+++ b/EnvelopeGenerator.DependencyInjection/DependencyInjection.cs
@@ -0,0 +1,145 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using EnvelopeGenerator.Application;
+using EnvelopeGenerator.Application.Common.Interfaces.Services;
+using EnvelopeGenerator.Application.Services;
+using EnvelopeGenerator.Infrastructure;
+using DigitalData.EmailProfilerDispatcher;
+using DigitalData.UserManager.DependencyInjection;
+
+namespace EnvelopeGenerator.DependencyInjection;
+
+///
+/// Controls which optional services are registered by .
+/// All flags default to true. Set a flag to false if the consuming project
+/// already registers that service itself or simply does not need it.
+///
+public sealed class EnvelopeGeneratorOptions
+{
+ /// Calls AddHttpContextAccessor(). Default: true.
+ public bool AddHttpContextAccessor { get; set; } = true;
+
+ ///
+ /// Calls AddDistributedSqlServerCache() with the supplied .
+ /// Requires to be configured. Default: true.
+ ///
+ public bool AddDistributedSqlServerCache { get; set; } = true;
+
+ ///
+ /// Options for the distributed SQL Server cache.
+ /// Required when is true.
+ ///
+ public SqlCacheOptions? SqlCacheOptions { get; set; }
+
+ /// Calls AddDispatcher<TDbContext>(). Default: true.
+ public bool AddDispatcher { get; set; } = true;
+
+ /// Calls AddMemoryCache(). Default: true.
+ public bool AddMemoryCache { get; set; } = true;
+
+ /// Calls AddUserManager<TDbContext>(). Default: true.
+ public bool AddUserManager { get; set; } = true;
+}
+
+/// Options for AddDistributedSqlServerCache.
+public sealed class SqlCacheOptions
+{
+ /// SQL Server connection string.
+ public string ConnectionString { get; set; } = string.Empty;
+
+ /// Schema name. Default: dbo.
+ public string SchemaName { get; set; } = "dbo";
+
+ /// Table name. Default: TBDD_CACHE.
+ public string TableName { get; set; } = "TBDD_CACHE";
+}
+
+///
+/// Extension methods for registering EnvelopeGenerator services into an .
+/// Use as the single entry-point for projects that need both the
+/// application layer (MediatR, AutoMapper, CRUD services, configuration sections) and the infrastructure
+/// layer (repositories, DbContext, SQL executors).
+/// For projects that do not need a database (e.g. lightweight API gateways or unit-test hosts), use
+/// to register only the application layer.
+///
+public static class DependencyInjection
+{
+ ///
+ /// Registers the full EnvelopeGenerator stack using as the DbContext type.
+ ///
+ public static IServiceCollection AddEnvelopeGenerator(
+ this IServiceCollection services,
+ IConfiguration configuration,
+ Action? infrastructureOptions = null,
+ Action? options = null)
+ {
+ var opt = new EnvelopeGeneratorOptions();
+ options?.Invoke(opt);
+
+#pragma warning disable CS0618
+ // Application layer: CRUD services, MediatR, AutoMapper, configuration sections.
+ services.AddEnvelopeGeneratorServices(configuration);
+
+ // Infrastructure layer: repositories, DbContext, Dapper type maps, SQL executors.
+ services.AddEnvelopeGeneratorInfrastructureServices(cfg =>
+ {
+ infrastructureOptions?.Invoke(cfg);
+ });
+#pragma warning restore CS0618
+
+ if (opt.AddHttpContextAccessor)
+ services.AddHttpContextAccessor();
+
+ if (opt.AddDistributedSqlServerCache && opt.SqlCacheOptions is { } cacheOpts)
+ services.AddDistributedSqlServerCache(o =>
+ {
+ o.ConnectionString = cacheOpts.ConnectionString;
+ o.SchemaName = cacheOpts.SchemaName;
+ o.TableName = cacheOpts.TableName;
+ });
+
+ if (opt.AddDispatcher)
+ services.AddDispatcher();
+
+ if (opt.AddMemoryCache)
+ services.AddMemoryCache();
+
+#pragma warning disable CS0618
+ if (opt.AddUserManager)
+ services.AddUserManager();
+#pragma warning restore CS0618
+
+ return services;
+ }
+
+ ///
+ /// Registers only the application layer services (MediatR handlers, AutoMapper profiles,
+ /// CRUD services, configuration sections) without any infrastructure / database dependencies.
+ ///
+ /// Service collection to register services into.
+ /// Application configuration used to bind application-level option sections.
+ /// The updated .
+#pragma warning disable CS0618
+ public static IServiceCollection AddEnvelopeGeneratorCore(
+ this IServiceCollection services,
+ IConfiguration configuration)
+ {
+ services.AddEnvelopeGeneratorServices(configuration);
+ return services;
+ }
+#pragma warning restore CS0618
+
+ ///
+ /// Registers as the scoped
+ /// implementation.
+ ///
+ /// Service collection to register services into.
+ /// The updated .
+#pragma warning disable CS0618
+ public static IServiceCollection AddEnvelopeMailService(this IServiceCollection services)
+ {
+ services.AddScoped();
+ return services;
+ }
+#pragma warning restore CS0618
+}
diff --git a/EnvelopeGenerator.DependencyInjection/EnvelopeGenerator.DependencyInjection.csproj b/EnvelopeGenerator.DependencyInjection/EnvelopeGenerator.DependencyInjection.csproj
new file mode 100644
index 00000000..a504ed13
--- /dev/null
+++ b/EnvelopeGenerator.DependencyInjection/EnvelopeGenerator.DependencyInjection.csproj
@@ -0,0 +1,176 @@
+
+
+
+ net7.0;net8.0;net9.0
+ enable
+ enable
+
+
+ EnvelopeGenerator
+ Digital Data GmbH
+ Digital Data GmbH
+ EnvelopeGenerator
+
+ Envelope Generator ist eine Bibliothek zur Verwaltung und Verarbeitung digitaler Umschläge (Envelopes).
+ Dieses Paket enthält die Dependency-Injection-Erweiterungsmethoden und bündelt die Application-
+ sowie Infrastructure-Schicht in einer einzigen NuGet-Referenz.
+
+ Copyright 2024 Digital Data GmbH
+ http://git.dd:3000/AppStd/EnvelopeGenerator.git
+ digital data envelope generator di dependency injection
+ false
+ 1.2.0.3
+ 1.2.0.3
+ 1.2.0.3
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+
+
+ all
+
+
+ all
+
+
+
+
+
+
+ <_DepDlls Include="
..\EnvelopeGenerator.Application\bin\$(Configuration)\%(ProjectReference.TargetFramework)\EnvelopeGenerator.Application.dll;
..\EnvelopeGenerator.Domain\bin\$(Configuration)\%(ProjectReference.TargetFramework)\EnvelopeGenerator.Domain.dll;
..\EnvelopeGenerator.Infrastructure\bin\$(Configuration)\%(ProjectReference.TargetFramework)\EnvelopeGenerator.Infrastructure.dll" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs
index e8068bd2..4fc4f10c 100644
--- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs
+++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs
@@ -438,4 +438,10 @@ public class EnvelopeController : ViewControllerBase
return this.ViewDocumentNotFound();
}
}
+
+ [HttpGet("EnvelopeReceiverWithSecretByMediatr")]
+ public async Task EnvelopeReceiverWithSecretByMediatr([FromQuery] ReadEnvelopeReceiverSecretQuery q, CancellationToken cancel)
+ {
+ return await _mediator.Send(q, cancel) is EnvelopeReceiverSecretDto dto ? Ok(dto) : NotFound();
+ }
}
\ No newline at end of file
diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj
index 6c0e5d59..d0071918 100644
--- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj
+++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj
@@ -2175,6 +2175,7 @@
+
diff --git a/EnvelopeGenerator.Web/Program.cs b/EnvelopeGenerator.Web/Program.cs
index 4e158971..f25a9888 100644
--- a/EnvelopeGenerator.Web/Program.cs
+++ b/EnvelopeGenerator.Web/Program.cs
@@ -1,4 +1,3 @@
-using EnvelopeGenerator.Application.Services;
using Microsoft.EntityFrameworkCore;
using NLog;
using Quartz;
@@ -9,14 +8,12 @@ using EnvelopeGenerator.Web.Models;
using System.Text.Encodings.Web;
using Ganss.Xss;
using Microsoft.Extensions.Options;
-using EnvelopeGenerator.Application;
using DigitalData.EmailProfilerDispatcher;
using EnvelopeGenerator.Infrastructure;
using EnvelopeGenerator.Web.Sanitizers;
using EnvelopeGenerator.Web.Models.Annotation;
-using DigitalData.UserManager.DependencyInjection;
using EnvelopeGenerator.Web.Middleware;
-using EnvelopeGenerator.Application.Common.Interfaces.Services;
+using EnvelopeGenerator.DependencyInjection;
using EnvelopeGenerator.Web;
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
@@ -57,8 +54,6 @@ try
});
});
- builder.Services.AddHttpContextAccessor();
-
builder.ConfigureBySection();
// Add controllers and razor views
@@ -95,17 +90,9 @@ try
var connStr = config.GetConnectionString(cnnStrName)
?? throw new InvalidOperationException($"Connection string '{cnnStrName}' is missing in the application configuration.");
- builder.Services.AddDistributedSqlServerCache(options =>
- {
- options.ConnectionString = connStr;
- options.SchemaName = "dbo";
- options.TableName = "TBDD_CACHE";
- });
-
// Add envelope generator services
-#pragma warning disable CS0618 // Type or member is obsolete
- builder.Services.AddEnvelopeGeneratorInfrastructureServices(
- opt =>
+ builder.Services.AddEnvelopeGenerator(config,
+ infrastructureOptions: opt =>
{
opt.AddDbTriggerParams(config);
opt.AddDbContext((provider, options) =>
@@ -116,12 +103,16 @@ try
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
});
+ },
+ options: opt =>
+ {
+ opt.SqlCacheOptions = new()
+ {
+ ConnectionString = connStr,
+ SchemaName = "dbo",
+ TableName = "TBDD_CACHE"
+ };
});
-#pragma warning restore CS0618 // Type or member is obsolete
-
-#pragma warning disable CS0618 // Type or member is obsolete
- builder.Services.AddEnvelopeGeneratorServices(config);
-#pragma warning restore CS0618 // Type or member is obsolete
builder.Services.Configure(options =>
{
@@ -169,22 +160,12 @@ try
builder.Services.AddSingleton(sp => sp.GetRequiredService>().Value);
// Register mail services
-#pragma warning disable CS0618 // Type or member is obsolete
- builder.Services.AddScoped();
-#pragma warning restore CS0618 // Type or member is obsolete
-
- builder.Services.AddDispatcher();
-
- builder.Services.AddMemoryCache();
+ builder.Services.AddEnvelopeMailService();
builder.ConfigureBySection();
builder.ConfigureBySection();
-#pragma warning disable CS0618 // Type or member is obsolete
- builder.Services.AddUserManager();
-#pragma warning restore CS0618 // Type or member is obsolete
-
var app = builder.Build();
app.UseMiddleware();
diff --git a/EnvelopeGenerator.Web/wwwroot/js/util.min.js b/EnvelopeGenerator.Web/wwwroot/js/util.min.js
index 3f35065e..61eb8277 100644
--- a/EnvelopeGenerator.Web/wwwroot/js/util.min.js
+++ b/EnvelopeGenerator.Web/wwwroot/js/util.min.js
@@ -1 +1 @@
-function detailedCurrentDate(){return new Intl.DateTimeFormat(getCurrentCulture(),{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"shortOffset"}).format()}function findNearest(e,t,o,n){const r=n.reduce(((n,r)=>{const i=Math.sqrt((t(e)-t(r))**2+(o(e)-o(r))**2);return i("undefined"!=typeof localized&&localized.culture)?localized.culture:navigator.language||"en-US";const B64ToBuff=e=>new Uint8Array(Array.from(atob(e),e=>e.charCodeAt(0))).buffer;const getLocaleDateString=e=>new Date().toLocaleDateString(getCurrentCulture());
\ No newline at end of file
+function detailedCurrentDate(){return new Intl.DateTimeFormat(getCurrentCulture(),{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"shortOffset"}).format()}function findNearest(n,t,i,r){const u=r=>Math.sqrt((t(n)-t(r))**2+(i(n)-i(r))**2);return r.reduce((n,t)=>{const i=u(t);return itypeof localized!="undefined"&&localized.culture?localized.culture:navigator.language||"en-US",B64ToBuff=n=>new Uint8Array(Array.from(atob(n),n=>n.charCodeAt(0))).buffer,getLocaleDateString=()=>(new Date).toLocaleDateString(getCurrentCulture());
\ No newline at end of file
diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln
index a99a93c8..35d850e3 100644
--- a/EnvelopeGenerator.sln
+++ b/EnvelopeGenerator.sln
@@ -87,10 +87,6 @@ Global
{EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.Build.0 = Release|Any CPU
- {FB2D306B-1042-4A70-31ED-F991A1599371}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FB2D306B-1042-4A70-31ED-F991A1599371}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FB2D306B-1042-4A70-31ED-F991A1599371}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FB2D306B-1042-4A70-31ED-F991A1599371}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -110,7 +106,6 @@ Global
{211619F5-AE25-4BA5-A552-BACAFE0632D3} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
{224C4845-1CDE-22B7-F3A9-1FF9297F70E8} = {0CBC2432-A561-4440-89BC-671B66A24146}
{EC768913-6270-14F4-1DD3-69C87A659462} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
- {FB2D306B-1042-4A70-31ED-F991A1599371} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {73E60370-756D-45AD-A19A-C40A02DACCC7}