DependencyInjectionInstaller.cs 6.9 KB
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Rcs.Application;
using Rcs.Application.Services;
using Rcs.Application.Services.Protocol;
using Rcs.Application.Services.Sync;
using Rcs.Application.Shared;
using Rcs.Cyaninetech.Services;
using Rcs.Domain.Repositories;
using Rcs.Domain.Services;
using Rcs.Infrastructure.DB.Repositories;
using Rcs.Infrastructure.MessageBus.Handlers.Events;
using Rcs.Infrastructure.Services;
using Rcs.Infrastructure.Services.ParameterResolvers;
using Rcs.Infrastructure.Services.Protocol;
using Rcs.Infrastructure.Services.Sync;

namespace Rcs.Infrastructure.Installs
{
    /// <summary>
    /// 依赖注入安装器
    /// </summary>
    public static class DependencyInjectionInstaller
    {
        /// <summary>
        /// 安装依赖注入
        /// </summary>
        public static void InstallDependencyInjection(this WebApplicationBuilder builder)
        {
            // 注册有序的领域事件分发器(单例,避免反射性能问题,保证事件顺序)
            builder.Services.AddSingleton<IDomainEventDispatcher, OrderedDomainEventDispatcher>();

            // 注册仓储
            builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
            builder.Services.AddScoped<IRobotRepository, RobotRepository>();
            builder.Services.AddScoped<IMapRepository, MapRepository>();
            builder.Services.AddScoped<IMapNodeRepository, MapNodeRepository>();
            builder.Services.AddScoped<IMapEdgeRepository, MapEdgeRepository>();
            builder.Services.AddScoped<IMapResourceRepository, MapResourceRepository>();
            builder.Services.AddScoped<IMapFileRepository, MapFileRepository>();
            builder.Services.AddScoped<ITaskTemplateRepository, TaskTemplateRepository>();
            builder.Services.AddScoped<IActionConfigurationRepository, ActionConfigurationRepository>();
            builder.Services.AddScoped<IRobotTaskRepository, RobotTaskRepository>();
            builder.Services.AddScoped<IRobotSubTaskRepository, RobotSubTaskRepository>();
            builder.Services.AddScoped<IStorageAreaRepository, StorageAreaRepository>();
            builder.Services.AddScoped<IStorageLocationRepository, StorageLocationRepository>();

            // 注册服务
            builder.Services.AddScoped<IFileStorageService, FileStorageService>();

            // 注册后台任务调度服务
            // @author zzy
            builder.Services.AddSingleton<TaskDispatchBackgroundService>();
            builder.Services.AddSingleton<ITaskDispatchService>(sp => sp.GetRequiredService<TaskDispatchBackgroundService>());
            builder.Services.AddHostedService(sp => sp.GetRequiredService<TaskDispatchBackgroundService>());

            // 注册后台任务执行服务
            // @author zzy
            builder.Services.AddSingleton<TaskExecutionBackgroundService>();
            builder.Services.AddSingleton<ITaskExecutionService>(sp => sp.GetRequiredService<TaskExecutionBackgroundService>());
            builder.Services.AddHostedService(sp => sp.GetRequiredService<TaskExecutionBackgroundService>());

            // 注册数据同步服务 - 程序启动时将地图和机器人数据同步到Redis
            // @author zzy
            builder.Services.AddSingleton<DataSyncBackgroundService>();
            builder.Services.AddSingleton<IDataSyncService>(sp => sp.GetRequiredService<DataSyncBackgroundService>());
            builder.Services.AddSingleton<IHostedService>(sp => sp.GetRequiredService<DataSyncBackgroundService>());

            // 注册机器人缓存服务 - 负责机器人状态和位置的Redis缓存操作
            // @author zzy
            builder.Services.AddSingleton<IRobotCacheService, RobotCacheService>();

            // 注册地图缓存服务 - 负责地图数据的Redis缓存操作
            // @author zzy
            builder.Services.AddSingleton<IMapCacheService, MapCacheService>();

            // 注册协议服务 - 支持多协议类型的机器人通信
            // @author zzy
            builder.Services.AddScoped<IProtocolService, CustomProtocolService>();
            builder.Services.AddScoped<IProtocolService, Vda5050ProtocolService>();
            builder.Services.AddScoped<IProtocolServiceFactory, ProtocolServiceFactory>();

            // 注册机器人状态持久化服务 - 定时将Redis中的机器人状态同步到数据库
            // @author zzy
            builder.Services.AddHostedService<RobotStatePersistenceService>();

            // 注册通用定时同步服务
            // @author zzy
            builder.Services.AddScoped<ISyncProvider, MapResourceSyncProvider>();
            builder.Services.AddScoped<ISyncProvider, MapPointsSyncProvider>();
            builder.Services.AddHostedService<GenericSyncBackgroundService>();

            // 注册参数值解析器
            RegisterParameterResolvers(builder.Services);

            // 注册领域事件处理器
            RegisterDomainEventHandlers(builder.Services);
        }

        /// <summary>
        /// 注册参数值解析器
        /// @author zzy
        /// </summary>
        private static void RegisterParameterResolvers(IServiceCollection services)
        {
            // 注册所有解析器实现
            services.AddScoped<IParameterValueResolver, ConstantResolver>();
            services.AddScoped<IParameterValueResolver, TaskResolver>();
            services.AddScoped<IParameterValueResolver, RobotResolver>();
            services.AddScoped<IParameterValueResolver, NodeResolver>();
            services.AddScoped<IParameterValueResolver, EdgeResolver>();
            services.AddScoped<IParameterValueResolver, PathResolver>();
            services.AddScoped<IParameterValueResolver, ExpressionResolver>();

            // 注册解析器工厂
            services.AddScoped<IParameterValueResolverFactory, ParameterValueResolverFactory>();
        }

        /// <summary>
        /// 注册领域事件处理器
        /// 自动扫描 Rcs.Infrastructure.MessageBus.Handlers.Events 命名空间下所有以 DomainEventHandler 结尾的类
        /// @author zzy
        /// </summary>
        private static void RegisterDomainEventHandlers(IServiceCollection services)
        {
            const string handlerNamespace = "Rcs.Infrastructure.MessageBus.Handlers.Events";
            const string handlerSuffix = "DomainEventHandler";

            var handlerTypes = typeof(RobotCreatedDomainEventHandler).Assembly
                .GetTypes()
                .Where(t => t.IsClass
                    && !t.IsAbstract
                    && t.Namespace != null
                    && t.Namespace.StartsWith(handlerNamespace)
                    && t.Name.EndsWith(handlerSuffix));

            foreach (var handlerType in handlerTypes)
            {
                services.AddScoped(handlerType);
            }
        }
    }
}