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
}
}