using DigitalData.Core.Abstraction.Application.Repository; using DigitalData.Core.Infrastructure.Factory; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; namespace DigitalData.Core.Infrastructure; public static class DependencyInjection { public static IServiceCollection AddDbRepository(this IServiceCollection services, Action options) { var cfg = new RepositoryConfiguration(); options.Invoke(cfg); // 1. FromAssembly cfg.RegsFromAssembly.InvokeAll(services); // 2. Entities to be able overwrite cfg.RegsEntity.InvokeAll(services); return services; } public class RepositoryConfiguration { // 1. register from assembly internal Queue> RegsFromAssembly = new(); // 2. register entities (can overwrite) internal Queue> RegsEntity = new(); internal RepositoryConfiguration() { } public void RegisterFromAssembly(Assembly assembly) where TDbContext : DbContext { void reg(IServiceCollection services) { // scan all types in the Assembly var entityTypes = assembly.GetTypes() .Where(t => t.IsClass && !t.IsAbstract && t.GetCustomAttribute() != null); foreach (var entityType in entityTypes) { #region Repository /// register repository // create generic DbRepository type var repositoryType = typeof(DbRepository<,>).MakeGenericType(typeof(TDbContext), entityType); var interfaceType = typeof(IRepository<>).MakeGenericType(entityType); // add into DI container as Scoped services.AddScoped(interfaceType, repositoryType); #endregion Repository #region DbSetFactory /// register DbSetFactory var addDbSetFactoryMethod = typeof(DependencyInjection) .GetMethod(nameof(AddDbSetFactory), BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); var genericMethod = addDbSetFactoryMethod!.MakeGenericMethod(typeof(TDbContext), entityType); genericMethod.Invoke(null, new [] { services }); #endregion DbSetFactory } } RegsFromAssembly.Enqueue(reg); } public void RegisterEntity() where TDbContext : DbContext where TEntity : class { static void reg(IServiceCollection services) => services.AddScoped, DbRepository>(); RegsEntity.Enqueue(reg); } } private static void InvokeAll(this Queue> queue, T services) { while (queue.Count > 0) queue.Dequeue().Invoke(services); } internal static IServiceCollection AddDbSetFactory(this IServiceCollection services, Func>? create = null) where TDbContext : DbContext where TEntity : class { create ??= ctx => ctx.Set(); services.AddSingleton(_ => new DbSetFactory(create)); return services; } }