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