using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.EntityFrameworkCore; using DigitalData.Core.Infrastructure; using EnvelopeGenerator.Domain.Entities; using Microsoft.Extensions.Configuration; using Dapper; using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; using DigitalData.UserManager.Domain.Entities; #if NET using CommandDotNet.Execution; using EnvelopeGenerator.Infrastructure.Repositories; using EnvelopeGenerator.Infrastructure.Executor; using EnvelopeGenerator.Application.Common.Interfaces.Repositories; using EnvelopeGenerator.Application.Common.Interfaces.SQLExecutor; using DigitalData.EmailProfilerDispatcher.Abstraction.Entities; #elif NETFRAMEWORK using System; #endif namespace EnvelopeGenerator.Infrastructure { public static class DIExtensions { /// /// Registers the required repositories for the Envelope Generator service to the given . /// This method adds the repositories for various envelope-related entities, such as configuration, document receivers, envelopes, and users, /// as scoped services to the dependency injection container. Optionally, it can also configure the /// with the provided database context options if specified. /// /// The to which the services are added. /// An optional action to configure the for the . /// If not provided, the will not be configured. /// The updated with the added repository services. /// /// This method ensures that the repositories are registered as scoped services, meaning that a new instance of each repository /// will be created per HTTP request (or per scope) within the dependency injection container. /// [Obsolete("Use IRepository")] public static IServiceCollection AddEnvelopeGeneratorInfrastructureServices(this IServiceCollection services, Action options #if NET , IConfiguration? sqlExecutorConfiguration = null, Action? sqlExecutorConfigureOptions = null #endif ) { // configure custom options options(new Config(services)); #if NET services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); #endif services.AddDbRepository(opt => { // scan EnvelopeGenerator opt.RegisterFromAssembly(typeof(Config).Assembly); // scan UserManager opt.RegisterFromAssembly(typeof(User).Assembly); #if NET // scan EmailProfilerDispatcher opt.RegisterFromAssembly(typeof(EmailOut).Assembly); #endif }); #if NET services.AddSQLExecutor(); services.AddSQLExecutor(); services.AddSQLExecutor(); services.AddSQLExecutor(); services.AddSQLExecutor(); SetDapperTypeMap(); SetDapperTypeMap(); SetDapperTypeMap(); SetDapperTypeMap(); SetDapperTypeMap(); SetDapperTypeMap(); services.AddScoped(); services.AddScoped(); services.AddScoped(); if (sqlExecutorConfiguration is not null || sqlExecutorConfigureOptions is not null) services.AddSQLExecutor(sqlExecutorConfiguration, sqlExecutorConfigureOptions); #endif return services; } #if NET public static IServiceCollection AddSQLExecutor(this IServiceCollection services, IConfiguration? configuration = null, Action? configureOptions = null) { if (configuration is not null && configureOptions is not null) throw new InvalidOperationException("Cannot use both 'configuration' and 'configureOptions'. Only one should be provided."); if (configuration is not null) services.Configure(configuration); if (configureOptions is not null) services.Configure(configureOptions); return services.AddSingleton(); } private static void SetDapperTypeMap() { Dapper.SqlMapper.SetTypeMap(typeof(TModel), new CustomPropertyTypeMap( typeof(TModel), (type, columnName) => { return type.GetProperties().FirstOrDefault(prop => { var attr = prop.GetCustomAttribute(); return attr != null && string.Equals(attr.Name, columnName, StringComparison.OrdinalIgnoreCase) || string.Equals(prop.Name, columnName, StringComparison.OrdinalIgnoreCase); })!; } )); } public static IServiceCollection AddSQLExecutor(this IServiceCollection services, IConfiguration? configuration = null, Action? configureOptions = null) where T : class { if (configuration is not null && configureOptions is not null) throw new InvalidOperationException("Cannot use both 'configuration' and 'configureOptions'. Only one should be provided."); if (configuration is not null) services.Configure(configuration); services.AddScoped, SQLExecutor>(); var interfaceType = typeof(ISQL<>); var targetGenericType = interfaceType.MakeGenericType(typeof(T)); var implementations = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => { try { return a.GetTypes(); } catch { return Array.Empty(); } }) .Where(t => t is { IsClass: true, IsAbstract: false } && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType && i.GenericTypeArguments[0] == typeof(T) ) ); foreach (var impl in implementations) { services.AddSingleton(impl); } return services; } #endif public class Config { private readonly IServiceCollection _services; internal Config(IServiceCollection services) { _services = services; } public void ConfigureDbTriggerParams(IConfiguration configuration) { _services.Configure(configuration.GetSection(nameof(DbTriggerParams))); } public void ConfigureDbTriggerParams(Action configureOptions) { _services.Configure(configureOptions); } public void AddDbContext(Action dbContextOptions) { _services.AddDbContext(dbContextOptions); } public void AddDbContext(Action dbContextOptions) { _services.AddDbContext(dbContextOptions); } } } }