using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using Microsoft.Extensions.DependencyInjection; using NLog; using Quadarax.Foundation.Core.Attributes; using Quadarax.Foundation.Core.Reflection; using Quadarax.Foundation.Core.Reflection.Extensions; using ILogger = NLog.ILogger; namespace Quadarax.Foundation.Core.Business.Injection { /// /// Register modules inside defined assemblies. Modules must be flagged by and /// public static class DiManager { #region *** Private fields *** private static IList _registeredAssemblies = new List(); private static ILogger _logger = LogManager.GetLogger(nameof(DiManager)); #endregion #region *** Public properties *** public static string[] RegisteredAssembliesNames => _registeredAssemblies.Select(x => x.GetName().ToString()).ToArray(); #endregion #region *** Public Operations *** /// /// Register all assemblies from current appdomain. /// public static void RegisterAssemblyFromThisAppdomain() { RegisterAssemblyFromThisAppdomain(null, null); } /// /// Register all assemblies from current appdomain by filtering options. /// /// /// public static void RegisterAssemblyFromThisAppdomain([AllowNull]IEnumerable includedStartsWith,[AllowNull] IEnumerable excludedStartsWith) { includedStartsWith ??= new List(); excludedStartsWith ??= new List(); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { var isRegister = includedStartsWith.Any() && includedStartsWith.Any(x => assembly.GetName().ToString().StartsWith(x)); isRegister = isRegister && !excludedStartsWith.Any(x => assembly.GetName().ToString().StartsWith(x)); if (isRegister) RegisterAssembly(assembly); } } /// /// Register an assembly to scan and find modules flagged by /// /// public static void RegisterAssembly([NotNull]Assembly assembly) { if (assembly == null) throw new ArgumentNullException(nameof(assembly)); if (_registeredAssemblies.Contains(assembly)) return; _registeredAssemblies.Add(assembly); var logMessage = $"DiManager register assembly: {assembly.GetName()}"; _logger.Debug(logMessage); Trace.WriteLine(logMessage,"DI"); } /// /// Scans registered assemblies and register them to /// /// Service definition collection. public static void ScanAndRegisterDependencyInjections([NotNull]IServiceCollection services) { int cntAssemblies = 0; int cntTypes = 0; int cntRegistrations = 0; foreach (var assembly in _registeredAssemblies) { cntAssemblies++; var logMessage = $"Scanning assembly '{assembly.GetName()}' ..."; _logger.Debug(logMessage); Trace.WriteLine(logMessage,"DI"); var types = assembly.GetTypesWithAttribute(true); foreach (var type in types) { cntTypes++; var attributes = AttributeQuery.FindAll(type); foreach (var attribute in attributes) { if (attribute==null) continue; switch (attribute.LifeCycleType) { case LifeCycleTypeEnum.Scoped: services.AddScoped(attribute.InterfaceTypeImplementing, type); break; case LifeCycleTypeEnum.Singleton: services.AddSingleton(attribute.InterfaceTypeImplementing, type); break; case LifeCycleTypeEnum.Transient: services.AddTransient(attribute.InterfaceTypeImplementing, type); break; default: throw new NotSupportedException($"Not supported registration for LifeCycleType = {attribute.LifeCycleType}"); } cntRegistrations++; logMessage = $"DI registered: Type={attribute.InterfaceTypeImplementing.FullName} for Type={type.Name} as LifeCycle={attribute.LifeCycleType}"; _logger.Info(logMessage); Trace.WriteLine(logMessage,"DI"); } } } var logMessage2 = $"DI registered. Assemblies={cntAssemblies}, Types={cntTypes}, Registrations={cntRegistrations}."; _logger.Info(logMessage2); Trace.WriteLine(logMessage2,"DI"); } #endregion } }