using Connected.Annotations; using Connected.Collections.Concurrent; using Connected.Configuration; using Connected.Entities.Caching; using Connected.Hosting.Workers; using Connected.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System.Reflection; namespace Connected.Instance; public static class StartupExtensions { internal static IServiceCollection AddMicroService(this IServiceCollection services, Assembly assembly) { foreach (var type in assembly.GetTypes()) { if (type.IsAbstract || !type.IsClass) continue; AddService(type, services, false); AddArgument(type, services, false); AddServiceOperation(type, services, false); AddEntityCache(type, services, false); AddMiddleware(type, services, false); AddDispatcher(type, services, false); AddDispatcherJob(type, services, false); AddHostedService(type, services, false); } return services; } public static void AddServiceOperation(Type type, IServiceCollection services) { AddServiceOperation(type, services, true); } private static void AddServiceOperation(Type type, IServiceCollection services, bool manual) { if (CanRegister(type, manual) && type.IsServiceOperation()) { services.AddTransient(type); RegisteredServices.AddApi(type); } } public static void AddService(Type type, IServiceCollection services) { AddService(type, services, true); } private static void AddService(Type type, IServiceCollection services, bool manual) { if (!CanRegister(type, manual)) return; if (type.GetInterface(typeof(IService).FullName) is null) return; var interfaces = type.GetInterfaces(); foreach (var i in interfaces) { if (i.GetCustomAttribute() is not null) { services.Add(ServiceDescriptor.Scoped(i, type)); RegisteredServices.AddApiService(type); } } } public static void AddArgument(Type type, IServiceCollection services) { AddArgument(type, services, true); } private static void AddArgument(Type type, IServiceCollection services, bool manual) { if (!CanRegister(type, manual) || type.GetInterface(typeof(IDto).FullName) is null) return; services.Add(ServiceDescriptor.Transient(type, type)); RegisteredServices.AddArgument(type); } public static void AddMiddleware(Type type, IServiceCollection services) { AddMiddleware(type, services, true); } public static void AddMiddleware(Type type, IServiceCollection services, bool manual) { if (!CanRegister(type, manual) || type.GetInterface(typeof(IMiddleware).FullName) is null) return; var att = type.GetCustomAttribute(); var scope = ServiceRegistrationScope.Scoped; if (att is not null) scope = att.Scope; switch (scope) { case ServiceRegistrationScope.Singleton: services.Add(ServiceDescriptor.Singleton(type, type)); break; case ServiceRegistrationScope.Scoped: services.Add(ServiceDescriptor.Scoped(type, type)); break; case ServiceRegistrationScope.Transient: services.Add(ServiceDescriptor.Transient(type, type)); break; } RegisteredServices.AddMiddleware(type); } public static void AddEntityCache(Type type, IServiceCollection services) { AddEntityCache(type, services, true); } private static void AddEntityCache(Type type, IServiceCollection services, bool manual) { if (!CanRegister(type, manual) || typeof(IEntityCacheClient<,>).FullName is not string fullName) return; if (type.GetInterface(fullName) is null) return; foreach (var itf in type.GetInterfaces()) { if (itf.GetInterface(fullName) is not null) { services.Add(ServiceDescriptor.Singleton(itf, type)); RegisteredServices.AddEntityCache(type); } } } public static void AddDispatcher(Type type, IServiceCollection services) { AddDispatcher(type, services, true); } private static void AddDispatcher(Type type, IServiceCollection services, bool manual) { if (!CanRegister(type, manual) || typeof(IDispatcher<,>).FullName is not string fullName) return; if (type.GetInterface(fullName) is null) return; services.AddTransient(type); } public static void AddDispatcherJob(Type type, IServiceCollection services) { AddDispatcherJob(type, services, true); } private static void AddDispatcherJob(Type type, IServiceCollection services, bool manual) { if (!CanRegister(type, manual) || typeof(IDispatcherJob<>).FullName is not string fullName) return; if (type.GetInterface(fullName) is null) return; services.AddTransient(type); } public static void AddHostedService(Type type, IServiceCollection services) { AddHostedService(type, services, true); } private static void AddHostedService(Type type, IServiceCollection services, bool manual) { if (!CanRegister(type, manual) || type.GetInterface(typeof(IWorker).FullName) is null) return; services.AddSingleton(typeof(IHostedService), type); } private static bool CanRegister(Type type, bool manual) { if (manual) return true; return type.GetCustomAttribute() is not ServiceRegistrationAttribute att || att.Mode == ServiceRegistrationMode.Auto; } }