using MAX.Core.DependencyInjection; using MAX.Core.Interfaces; using MAX.Core.Logger; using MAX.Framework.Commons; using MAX.Framework.Dtos; using MAX.Framework.Interfaces; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Win32; using System.Configuration; using System.Diagnostics; using System.Reflection; using MAX.Plugins; namespace MAX.Framework.DependencyInjection { /// /// IOC 注册入口(由宿主 Program.cs 调用) /// public static class ServiceCollectionExtensions { private static readonly Type[] DependencyMarkers = [ typeof(ISingletonDependency), typeof(IScopedDependency), typeof(ITransientDependency), ]; /// /// 添加框架注册 /// public static IServiceCollection AddStore(this IHostApplicationBuilder host) { Debug.WriteLine("[Store] 开始注册应用服务"); RunDebugStep("Logger", "注册日志服务", () => host.AddLogger()); //host.Services.AddSingleton(NLogger.Instance);//注册log IEnumerable assemblies = StoreAppTypeFinder.Current.GetAssemblies(host.Configuration["Plugins:Path"]).ToArray(); foreach (var assembly in assemblies) Debug.WriteLine($"[Assembly] 已发现:{assembly.FullName}"); // 同一个类可能同时实现 IStartup 与 IModule,这里缓存实例,保证两个阶段拿到的是同一个对象 Dictionary instances = []; return AddStoreCore(host, assemblies, instances); } /// /// 注册应用服务的公共实现:宿主入口(builder.AddStoreHub())与 入口共用。 /// internal static IServiceCollection AddStoreCore( IHostApplicationBuilder host, IEnumerable assemblies, IDictionary instances) { RunDebugStep("DI", "注册依赖标记服务", () => RegisterDependencyMarkers(host.Services, assemblies)); RunDebugStep("Module", "注册全部模块", () => RunModules(host, assemblies, instances)); RunDebugStep("Plugin", "注册全部插件", () => RunPlugins(host, assemblies, instances)); RunDebugStep("Startup", "初始化并注册启动服务", () => RunStartups(host.Services, assemblies, instances)); RunDebugStep("MediatR", "按命令特性注册管道", () => host.Services.AddMediatRAttributedBehaviors(assemblies.ToArray())); Debug.WriteLine("[MVC] 开始注册控制器和全局过滤器"); var mvc = host.Services.AddControllers(options => { options.Filters.Add(); options.Filters.Add(); }).ConfigureApiBehaviorOptions(options => { options.InvalidModelStateResponseFactory = context => { // 取出所有校验错误信息,拼成一个字符串(或者只取第一个) var errors = context.ModelState .Where(e => e.Value?.Errors.Count > 0) .SelectMany(e => e.Value!.Errors.Select(err => err.ErrorMessage)) .ToList(); var msg = string.Join("; ", errors); var result = ApiResult.Fail(msg, ResultCode.ValidationError); return new ObjectResult(result) { StatusCode = 200 // 和其他接口保持一致,用Code表达失败,而不是HTTP 400 }; }; }); foreach (var assembly in assemblies) { mvc.AddApplicationPart(assembly); Debug.WriteLine($"[MVC] 已添加 ApplicationPart:{assembly.GetName().Name}"); } Debug.WriteLine($"[Store] 应用服务注册完成,共 {host.Services.Count} 个服务描述"); return host.Services; } /// /// 自动注册标记接口(ISingletonDependency / IScopedDependency / ITransientDependency)的实现类型 /// private static void RegisterDependencyMarkers(IServiceCollection services, IEnumerable assemblies) { foreach (Type type in GetConcreteTypes(assemblies)) { Type? marker = DependencyMarkers.FirstOrDefault(m => m.IsAssignableFrom(type)); if (marker is null) { continue; } ServiceLifetime lifetime = marker == typeof(ISingletonDependency) ? ServiceLifetime.Singleton : marker == typeof(IScopedDependency) ? ServiceLifetime.Scoped : ServiceLifetime.Transient; // 注册为自身 services.Add(new ServiceDescriptor(type, type, lifetime)); Debug.WriteLine($"[DI] 注册自身:{type.FullName},Lifetime={lifetime}"); // 注册为实现的接口(排除标记接口与系统接口) foreach (Type iface in type.GetInterfaces()) { if (DependencyMarkers.Contains(iface) || IsSystemInterface(iface)) { continue; } services.Add(new ServiceDescriptor(iface, type, lifetime)); Debug.WriteLine($"[DI] 注册接口:{iface.FullName} -> {type.FullName},Lifetime={lifetime}"); } } } private static IEnumerable Startups = []; /// /// 发现所有 实现,按 降序执行 /// private static void RunStartups(IServiceCollection services, IEnumerable assemblies, IDictionary instances) { IServiceRegistrar registrar = new ServiceRegistrarProxy(services); Startups = CreateInstances(assemblies, instances).Where(s => s is not IPlugin).OrderByDescending(s => s.Priority); foreach (IStartup startup in Startups) { RunDebugStep("Startup", $"初始化 {startup.GetType().FullName},Priority={startup.Priority}", startup.Initialize); RunDebugStep("Startup", $"注册服务 {startup.GetType().FullName}", () => startup.Register(registrar)); } } private static IEnumerable Modules = []; /// /// 执行所有模块的服务注册阶段() /// private static void RunModules(IHostApplicationBuilder host, IEnumerable assemblies, IDictionary instances) { Modules = CreateInstances(assemblies, instances).Where(m => m is not IPlugin).OrderByDescending(s => s.Priority); foreach (IModule module in Modules) { try { RunDebugStep("Module", $"注册 {module.GetType().FullName},Priority={module.Priority}", () => module.AddModule(host)); } catch (Exception ex) { // 带上模块名,避免只看到一个没有上下文的异常 throw new InvalidOperationException($"模块 {module.GetType().FullName} 的 AddModule 执行失败:{ex.Message}", ex); } } } /// /// 反射创建(或复用)所有实现 的具体类型实例 /// private static IEnumerable CreateInstances(IEnumerable assemblies, IDictionary instances) where T : class { foreach (Type type in GetConcreteTypes(assemblies).Where(t => typeof(T).IsAssignableFrom(t))) { if (!instances.TryGetValue(type, out object? instance)) { instance = Activator.CreateInstance(type, true) ?? throw new InvalidOperationException($"无法创建 {type.FullName} 的实例(需要有参数量为 0 的构造函数)。"); instances[type] = instance; Debug.WriteLine($"[Instance] 已创建:{type.FullName}"); } else { Debug.WriteLine($"[Instance] 复用实例:{type.FullName}"); } yield return (T)instance; } } private static IEnumerable GetConcreteTypes(IEnumerable assemblies) { return assemblies .SelectMany(SafeGetTypes) .Where(t => t.IsClass && !t.IsAbstract && !t.IsGenericTypeDefinition); } private static IEnumerable SafeGetTypes(Assembly assembly) { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { Debug.WriteLine($"[Assembly] 部分类型加载失败:{assembly.FullName}"); foreach (var error in ex.LoaderExceptions) Debug.WriteLine($"[Assembly] 类型加载错误:{error?.Message}"); return ex.Types.OfType(); } } /// /// 应用程序集(模块、Startup 都从这里发现) /// internal static IEnumerable GetApplicationAssemblies() { // 使用 AppTypeFinder:扫描应用输出目录 + 已加载程序集, return StoreAppTypeFinder.Current.GetAssemblies(); } private sealed class PluginRuntime : IDisposable { public List<(IPlugin Plugin, PluginContext Context)> Entries { get; } = []; public void Dispose() { foreach (var entry in Entries) entry.Context.Dispose(); } } private static void RunPlugins(IHostApplicationBuilder host, IEnumerable assemblies, IDictionary instances) { var runtime = new PluginRuntime(); var ids = new HashSet(StringComparer.OrdinalIgnoreCase); try { foreach (var plugin in CreateInstances(assemblies, instances).OrderByDescending(p => p.Priority)) { if (plugin is IModule || plugin is IStartup) throw new InvalidOperationException($"插件 {plugin.GetType().FullName} 不能同时实现 IModule/IStartup。"); if (string.IsNullOrWhiteSpace(plugin.Id) || !ids.Add(plugin.Id)) throw new InvalidOperationException($"插件标识为空或重复:{plugin.Id}"); try { var directory = Path.GetDirectoryName(plugin.GetType().Assembly.Location)!; Debug.WriteLine($"[Plugin] 加载独立配置:{plugin.Id},目录={directory},环境={host.Environment.EnvironmentName}"); var context = new PluginContext(plugin.Id, directory, host.Environment); runtime.Entries.Add((plugin, context)); host.Services.AddKeyedSingleton(plugin.Id, (provider, _) => { // 只要上下文被解析,就让容器持有并管理全部插件配置的释放。 provider.GetRequiredService(); return context; }); var typedContext = typeof(PluginContext<>).MakeGenericType(plugin.GetType()); host.Services.AddSingleton(typedContext, provider => // 复用键名注册,确保仅解析泛型上下文时也由容器管理配置的释放。 Activator.CreateInstance(typedContext, provider.GetRequiredKeyedService(plugin.Id))!); RunDebugStep("Plugin", $"注册 {plugin.Id} ({plugin.GetType().FullName}),Priority={plugin.Priority}", () => plugin.ConfigureServices(host.Services, context)); } catch (Exception ex) { Debug.WriteLine($"[Plugin] 注册失败:{plugin.Id},{ex.Message}"); throw new InvalidOperationException($"插件 {plugin.Id} ({plugin.GetType().Assembly.Location}) 注册失败:{ex.Message}", ex); } } host.Services.AddSingleton(_ => runtime); } catch { runtime.Dispose(); throw; } } private static bool IsSystemInterface(Type type) { return type.Namespace is null || type.Namespace.StartsWith("System", StringComparison.Ordinal) || type.Namespace.StartsWith("Microsoft", StringComparison.Ordinal); } private static void RunDebugStep(string category, string description, Action action) { Debug.WriteLine($"[{category}] 开始:{description}"); try { action(); Debug.WriteLine($"[{category}] 完成:{description}"); } catch (Exception ex) { Debug.WriteLine($"[{category}] 失败:{description},{ex.Message}"); throw; } } public static IApplicationBuilder UseStore(this IApplicationBuilder app) { Debug.WriteLine("[Store] 开始装配应用管道"); RunDebugStep("Middleware", "注册统一状态码中间件", () => app.UseMiddleware()); foreach (var (plugin, context) in app.ApplicationServices.GetRequiredService().Entries) { try { RunDebugStep("Plugin", $"装配管道 {plugin.Id}", () => plugin.Configure(app, context)); } catch (Exception ex) { throw new InvalidOperationException($"插件 {plugin.Id} 管道装配失败:{ex.Message}", ex); } } foreach (IStartup startup in Startups) { RunDebugStep("Startup", $"执行启动回调 {startup.GetType().FullName}", () => startup.Start((app as IHost).Services)); } foreach (IModule module in Modules) { RunDebugStep("Module", $"装配管道 {module.GetType().FullName}", () => module.UseModule(app)); } Debug.WriteLine("[Store] 应用管道装配完成"); return app; } } }