You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core洋葱架构应用业务层事件触发后处理程序不执行如何解决

问题根因

核心原因是你注册的ElasticLogger服务从未被DI容器实例化:订阅逻辑Subscribe()仅在ElasticLogger的构造函数中执行,由于整个请求链路中没有任何代码主动注入/获取ElasticLogger实例,该类永远不会被创建,事件绑定操作从未执行,自然业务逻辑层触发事件时没有对应的处理程序响应。

快速修复方案(保留现有事件实现模式)

如果你不想调整现有实现逻辑,可以通过以下两种方式解决:

  • 方案1:显式触发Scoped实例初始化(适配请求级生命周期)
    自定义中间件在每次请求启动时主动从Scoped容器获取ElasticLogger实例,触发构造函数完成订阅:
    // 自定义中间件
    public class EventSubscriberMiddleware
    {
        private readonly RequestDelegate _next;
        public EventSubscriberMiddleware(RequestDelegate next) => _next = next;
        
        public async Task InvokeAsync(HttpContext context)
        {
            // 主动获取实例触发订阅逻辑
            context.RequestServices.GetRequiredService<ElasticLogger>();
            await _next(context);
        }
    }
    
    // Startup.Configure中注册中间件,放在路由匹配之前
    app.UseMiddleware<EventSubscriberMiddleware>();
    
  • 方案2:调整为单例生命周期(仅适合无状态服务场景)
    如果你的LiveStreamBusinessLogic本身是无状态的,可以将两个服务都注册为单例,应用启动时主动初始化订阅:
    // Startup.ConfigureServices中修改注册逻辑
    services.AddSingleton<ILiveStreamBusinessLogic, LiveStreamBusinessLogic>();
    services.AddSingleton<ElasticLogger>();
    
    // 容器构建完成后主动获取实例完成订阅
    var provider = services.BuildServiceProvider();
    provider.GetRequiredService<ElasticLogger>();
    
    注意:单例模式需要自行处理线程安全问题,且无法注入Scoped生命周期的服务
更适配洋葱架构的推荐实现模式

当前自定义事件的模式耦合度高,扩展能力弱,更推荐使用领域事件+MediatR中介者模式,完全符合洋葱架构的依赖倒置规则:

  1. 首先在Domain层定义领域事件基础结构:
    // Domain层,无任何外部依赖
    public interface IDomainEvent
    {
        DateTime OccuredAt { get; }
    }
    
    public class LiveStreamAccessedEvent : IDomainEvent
    {
        public DateTime OccuredAt { get; } = DateTime.UtcNow;
        // 按需扩展需要传递的事件参数
    }
    
  2. 引入NuGet包MediatR和MediatR.Extensions.Microsoft.DependencyInjection
  3. 业务逻辑层通过IMediator发布事件:
    public class LiveStreamBusinessLogic : ILiveStreamBusinessLogic
    {
        private readonly IMediator _mediator;
        public LiveStreamBusinessLogic(IMediator mediator) => _mediator = mediator;
    
        public async Task<IBusinessLogicResult<PagedList<LiveStreamForShowDto>>> GetAllLiveStreamAsync(LiveStreamParameters liveStreamParameters)
        {
            // 原有业务逻辑
            await _mediator.Publish(new LiveStreamAccessedEvent());
            return new BusinessLogicResult<PagedList<LiveStreamForShowDto>>
                {Success = true, Result = livesListForTransferPaged};
        }
    }
    
  4. 基础设施层实现事件处理程序:
    // Infrastructure层
    public class LiveStreamElasticLogHandler : INotificationHandler<LiveStreamAccessedEvent>
    {
        private readonly ILoggerManager _loggerManager;
        public LiveStreamElasticLogHandler(ILoggerManager loggerManager) => _loggerManager = loggerManager;
    
        public async Task Handle(LiveStreamAccessedEvent notification, CancellationToken cancellationToken)
        {
            _loggerManager.LogInfo(Serialize(notification).ToString());
            await Task.CompletedTask;
        }
    }
    
  5. 服务注册:
    // Startup.ConfigureServices中注册MediatR,自动扫描所有事件处理程序
    services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(
        typeof(LiveStreamAccessedEvent).Assembly, // Domain层程序集
        typeof(LiveStreamElasticLogHandler).Assembly // Infrastructure层程序集
    ));
    // 原有业务逻辑服务、基础设施服务注册逻辑保持不变
    

该模式的优势:

  • 完全解耦事件发布方和订阅方,业务逻辑层不需要感知任何订阅逻辑的存在
  • 支持多订阅者,后续需要新增事件处理逻辑(比如更新缓存、发送告警)不需要修改业务层代码
  • 自动适配DI生命周期,无需手动管理实例创建和订阅绑定,不会出现当前的订阅失效问题

内容的提问来源于stack exchange,提问作者happykratos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 23:27:01