using Masuit.Tools; using Microsoft.Extensions.DependencyModel; using Serilog; using System.Reflection; using System.Runtime.Loader; using YuanXuan.IM.Common.Attributes; namespace YuanXuan.IM.Api.CollectionExtensions { /// /// 批量注册服务 /// public static class BatchRegisterServiceCollectionExtension { /// /// 批量注册带属性的服务和后台服务 /// /// public static void BatchRegisterServices(this IServiceCollection services) { var allAssembly = GetAllAssembly(); services.RegisterServiceByAttribute(ServiceLifetime.Singleton, allAssembly); services.RegisterServiceByAttribute(ServiceLifetime.Scoped, allAssembly); services.RegisterServiceByAttribute(ServiceLifetime.Transient, allAssembly); services.RegisterBackgroundService(allAssembly); } /// /// 通过 InjectAttribute 批量注册服务 /// /// /// private static void RegisterServiceByAttribute(this IServiceCollection services, ServiceLifetime serviceLifetime, List allAssembly) { var types = allAssembly.SelectMany(t => t.GetTypes()) .Where(t => t.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0 && t.GetCustomAttribute()?.Lifetime == serviceLifetime && t.IsClass && !t.IsAbstract).ToList(); foreach (var type in types) { var baseInterfaces = type.BaseType?.GetInterfaces(); Type? typeInterface = null; // 获取所有接口,然后过滤掉系统接口和常见的不适合DI的接口 var allInterfaces = type.GetInterfaces(); var filteredInterfaces = allInterfaces.Where(IsCustomInterface).ToList(); // 如果没有自定义接口,则使用直接注入 if (filteredInterfaces.Count == 0) { //服务非继承自接口的直接注入 switch (serviceLifetime) { case ServiceLifetime.Singleton: services.AddSingleton(type); break; case ServiceLifetime.Scoped: services.AddScoped(type); break; case ServiceLifetime.Transient: services.AddTransient(type); break; } Log.Information("直接注入服务: {TypeName} (生命周期: {Lifetime})", type.Name, serviceLifetime); } else { // 如果有多个自定义接口,选择最合适的接口 typeInterface = ChooseBestInterface(filteredInterfaces, type); //服务继承自接口的和接口一起注入 switch (serviceLifetime) { case ServiceLifetime.Singleton: services.AddSingleton(typeInterface, type); break; case ServiceLifetime.Scoped: services.AddScoped(typeInterface, type); break; case ServiceLifetime.Transient: services.AddTransient(typeInterface, type); break; } Log.Information("接口注入服务: {TypeName} -> {InterfaceName} (生命周期: {Lifetime})", type.Name, typeInterface.Name, serviceLifetime); } } } /// /// 注册后台服务 /// /// /// private static void RegisterBackgroundService(this IServiceCollection services, List allAssembly) { List types = allAssembly.SelectMany(t => t.GetTypes()).Where(t => typeof(BackgroundService).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract).ToList(); foreach (var type in types) { services.AddSingleton(typeof(IHostedService), type); } } /// /// 判断是否为自定义接口(过滤掉系统接口和常见的不适合DI的接口) /// /// 接口类型 /// private static bool IsCustomInterface(Type interfaceType) { // 系统命名空间的接口(不适合DI) var systemNamespaces = new[] { "System", "Microsoft", "Windows", "IDisposable", "IComparable", "IEquatable", "IEnumerable", "ICollection", "IList", "IAsyncEnumerable", "IAsyncDisposable" }; // 如果接口名称包含系统命名空间或常见系统接口名称,则过滤掉 if (systemNamespaces.Any(ns => interfaceType.Namespace?.StartsWith(ns) == true || interfaceType.Name.StartsWith(ns))) { return false; } // 检查接口是否有自定义项目的命名空间 var customNamespaces = new[] { "LearningOfficer.OA", "LearningOfficer" }; // 如果接口有自定义项目的命名空间,则认为是自定义接口 return customNamespaces.Any(ns => interfaceType.Namespace?.StartsWith(ns) == true); } /// /// 从多个自定义接口中选择最合适的接口 /// /// 接口列表 /// 实现类型 /// private static Type ChooseBestInterface(List interfaces, Type implementationType) { // 如果只有一个接口,直接返回 if (interfaces.Count == 1) return interfaces[0]; // 优先选择名称匹配的接口(例如:MyService -> IMyService) var serviceName = implementationType.Name; var preferredInterface = interfaces.FirstOrDefault(i => i.Name == "I" + serviceName || i.Name == serviceName.Replace("Service", "").Replace("Impl", "") + "Service"); if (preferredInterface != null) return preferredInterface; // 按接口名称排序,选择最合适的 return interfaces .OrderBy(i => i.Name.StartsWith("I") ? 0 : 1) // 优先选择 I 开头的接口 .ThenBy(i => i.Name.Length) // 选择名称较短的接口 .First(); } /// /// 获取全部 Assembly /// /// private static List GetAllAssembly() { var allAssemblies = new List(); var loadedAssemblies = new HashSet(); var dependencyContext = DependencyContext.Default; var libraries = dependencyContext.RuntimeLibraries .Where(lib => !lib.Serviceable && lib.Type != "package") .ToList(); foreach (var library in libraries) { try { var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(library.Name)); if (loadedAssemblies.Add(assembly.FullName)) { allAssemblies.Add(assembly); } } catch (Exception) { Log.Fatal("加载程序集失败:{0}", library.Name); // Log or handle the exception if necessary } } return allAssemblies; } } }