CSharp.Template/YuanXuan.IM.Api/CollectionExtensions/BatchRegisterServiceCollect...

199 lines
8.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// 批量注册服务
/// </summary>
public static class BatchRegisterServiceCollectionExtension
{
/// <summary>
/// 批量注册带属性的服务和后台服务
/// </summary>
/// <param name="services"></param>
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);
}
/// <summary>
/// 通过 InjectAttribute 批量注册服务
/// </summary>
/// <param name="services"></param>
/// <param name="serviceLifetime"></param>
private static void RegisterServiceByAttribute(this IServiceCollection services, ServiceLifetime serviceLifetime, List<Assembly> allAssembly)
{
var types = allAssembly.SelectMany(t => t.GetTypes())
.Where(t => t.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0 &&
t.GetCustomAttribute<InjectAttribute>()?.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);
}
}
}
/// <summary>
/// 注册后台服务
/// </summary>
/// <param name="services"></param>
/// <param name="serviceLifetime"></param>
private static void RegisterBackgroundService(this IServiceCollection services, List<Assembly> allAssembly)
{
List<Type> 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);
}
}
/// <summary>
/// 判断是否为自定义接口过滤掉系统接口和常见的不适合DI的接口
/// </summary>
/// <param name="interfaceType">接口类型</param>
/// <returns></returns>
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);
}
/// <summary>
/// 从多个自定义接口中选择最合适的接口
/// </summary>
/// <param name="interfaces">接口列表</param>
/// <param name="implementationType">实现类型</param>
/// <returns></returns>
private static Type ChooseBestInterface(List<Type> 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();
}
/// <summary>
/// 获取全部 Assembly
/// </summary>
/// <returns></returns>
private static List<Assembly> GetAllAssembly()
{
var allAssemblies = new List<Assembly>();
var loadedAssemblies = new HashSet<string>();
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;
}
}
}