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 DependencyInjection
{
///
/// 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 AddEGInfrastructureServices(this IServiceCollection services, Action options)
{
// configure custom options
options(new EGInfrastructureConfiguration(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(EnvelopeReceiver).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();
#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 EGInfrastructureConfiguration
{
private readonly IServiceCollection _services;
internal EGInfrastructureConfiguration(IServiceCollection services)
{
_services = services;
}
public void AddDbTriggerParams(IConfiguration configuration)
{
_services.Configure(configuration.GetSection(nameof(DbTriggerParams)));
}
public void AddDbTriggerParams(Action configureOptions)
{
_services.Configure(configureOptions);
}
public void AddDbContext(Action dbContextOptions)
{
_services.AddDbContext(dbContextOptions);
}
public void AddDbContext(Action dbContextOptions)
{
_services.AddDbContext(dbContextOptions);
}
#if NET
public void AddSQLExecutor(IConfiguration configuration)
{
_services.Configure(configuration);
_services.AddSingleton();
_services.AddSQLExecutor(configuration, null);
}
public void AddSQLExecutor(Action options)
{
_services.Configure(options);
_services.AddSingleton();
_services.AddSQLExecutor(null, options);
}
#endif
}
}
}