using EnvelopeGenerator.Application.Contracts.Repositories;
using EnvelopeGenerator.Infrastructure.Repositories;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.EntityFrameworkCore;
using DigitalData.Core.Infrastructure;
using EnvelopeGenerator.Domain.Entities;
using DigitalData.Core.Infrastructure.AutoMapper;
using EnvelopeGenerator.Application.Contracts.SQLExecutor;
using Microsoft.Extensions.Configuration;
using EnvelopeGenerator.Infrastructure.Executor;
using Dapper;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using DigitalData.UserManager.Domain.Entities;
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.
///
public static IServiceCollection AddEnvelopeGeneratorInfrastructureServices(this IServiceCollection services,
Action? dbContextOptions = null,
IConfiguration? sqlExecutorConfiguration = null,
Action? sqlExecutorConfigureOptions = null)
{
if(dbContextOptions is not null)
services.AddDbContext(dbContextOptions);
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
services.AddDbRepository(context => context.Configs).UseAutoMapper();
services.AddDbRepository(context => context.DocumentReceiverElements).UseAutoMapper();
services.AddDbRepository(context => context.EnvelopeDocument).UseAutoMapper();
services.AddDbRepository(context => context.DocumentStatus).UseAutoMapper();
services.AddDbRepository(context => context.EmailTemplate).UseAutoMapper();
services.AddDbRepository(context => context.Envelopes).UseAutoMapper();
services.AddDbRepository(context => context.EnvelopeCertificates).UseAutoMapper();
services.AddDbRepository(context => context.EnvelopeHistories).UseAutoMapper();
services.AddDbRepository(context => context.EnvelopeReceivers).UseAutoMapper();
services.AddDbRepository(context => context.EnvelopeTypes).UseAutoMapper();
services.AddDbRepository(context => context.Receivers).UseAutoMapper();
services.AddDbRepository(context => context.UserReceivers).UseAutoMapper();
services.AddDbRepository(context => context.EnvelopeReceiverReadOnlys).UseAutoMapper();
services.AddSQLExecutor();
services.AddSQLExecutor();
services.AddSQLExecutor();
services.AddSQLExecutor();
services.AddSQLExecutor();
SetDapperTypeMap();
SetDapperTypeMap();
SetDapperTypeMap();
SetDapperTypeMap();
SetDapperTypeMap();
SetDapperTypeMap();
if (sqlExecutorConfiguration is not null || sqlExecutorConfigureOptions is not null)
services.AddSQLExecutor(sqlExecutorConfiguration, sqlExecutorConfigureOptions);
return services;
}
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;
}
}