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

在MassTransit中配置请求响应时遭遇依赖注入异常

依赖注入排查:无法解析MassTransit IRequestClient

问题描述

在Token微服务中基于MassTransit配置请求/响应模式,调用User微服务获取响应时,启动阶段触发System.AggregateException,核心异常信息为:

激活TokenService时无法解析MassTransit.IRequestClient`1[Dodis.Domain.Core.Messages.Requests.GetUserRequest]服务

相关代码

Token微服务依赖容器代码

public static void RegisterServices(IServiceCollection services, string MicroService, IConfiguration configuration)
{
    //services.AddTransient<ITokenService, TokenService>();
    var tokenSettings = new TokenSettings();
    configuration.Bind("Token", tokenSettings);

    services.Configure<TokenSettings>(configuration.GetSection("Token"));
    #region MassTransit
    try
    {
        services.AddMassTransit(config =>
        {
            config.SetKebabCaseEndpointNameFormatter();
            config.AddRequestClient<GetUserRequest>();

            config.UsingRabbitMq((context, configurator) =>
            {
                configurator.Host("localhost", "/", h =>
                {
                    h.Username("guest");
                    h.Password("guest");
                });
                configurator.ConfigureEndpoints(context);
            });
        });
    }
    catch (Exception ex) 
    {
        throw new Exception(ex.Message, ex);
    }
    #endregion
    try
    {
        services.AddScoped<ITokenService>(sp =>
        {
            var tokenFactory = sp.GetRequiredService<ITokenFactory>();
            var tokenRepository = sp.GetRequiredService<ITokenRepository>();
            var requestClient = sp.GetRequiredService<IRequestClient<GetUserRequest>>();

            return new TokenService(tokenFactory, tokenRepository, requestClient);
        });
    }
    catch (Exception ex) 
    {
        throw new Exception(ex.Message, ex);
    }
    services.AddDbContext<TokenDbContext>(options =>
    {
        options.UseSqlServer(hiding this);
    });
    services.AddScoped<ITokenRepository, TokenRepository>();
}

TokenService代码

public class TokenService : ITokenService
{
    private readonly ITokenFactory _tokenFactory;
    private readonly ITokenRepository _repository;
    private readonly IRequestClient<GetUserRequest> _client;

    public TokenService(ITokenFactory tokenFactory, ITokenRepository repository, IRequestClient<GetUserRequest> client)
    {
        _tokenFactory = tokenFactory;
        _repository = repository;
        _client = client;
    }

    public async Task<AccessResult> CreateToken(TokenRequest model)
    {
        var existingToken = await _repository.GetTokenByUserIdAndProvider(model.UserId, "Dodis", "Access_Token");

        if (existingToken != null)
        {
            existingToken.Value = await _tokenFactory.CreateToken(new TokenRequest
            {
                UserId = model.UserId,
                RoleName = model.RoleName,
            });
            existingToken.ExpireDate = DateTime.UtcNow.AddMinutes(20160);

            await _repository.UpdateToken(existingToken);
            var response = await _client.GetResponse<GetUserResponse>(new GetUserRequest { Id = model.UserId });
            // ... 剩余代码
        }
        // ... 剩余代码
    }
}

User微服务依赖容器代码

public static void RegisterServices(IServiceCollection services, string MicroService, IConfiguration? configuration = null)
{
    //Mediatr
    services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));

    // MassTransit
    try
    {
        services.AddMassTransit(config =>
        {
            //// Add the request client
            //config.AddRequestClient<GetUserRequest>();
            config.SetKebabCaseEndpointNameFormatter();
            config.AddConsumer<GetUserConsumer>();

            config.UsingRabbitMq((context, configurator) =>
            {
                configurator.Host("rabbitmq://localhost", h =>
                {
                    h.Username("guest");
                    h.Password("guest");
                });
                configurator.ConfigureEndpoints(context);
            });
        });
    }
    catch (Exception ex) 
    {
        throw new Exception(ex.Message, ex);
    }
}

排查原因及解决方案

1. 缺少MassTransit宿主服务注册

问题:Token微服务仅调用了services.AddMassTransit(...)配置总线,但未注册MassTransit的宿主服务,导致总线(IBus)未完成初始化,而IRequestClient<GetUserRequest>依赖正常运行的总线实例,因此无法被容器解析。

解决方案:在Token微服务的MassTransit配置代码块后,添加宿主服务注册:

services.AddMassTransitHostedService();

修改后的MassTransit配置部分:

try
{
    services.AddMassTransit(config =>
    {
        config.SetKebabCaseEndpointNameFormatter();
        config.AddRequestClient<GetUserRequest>();

        config.UsingRabbitMq((context, configurator) =>
        {
            configurator.Host("localhost", "/", h =>
            {
                h.Username("guest");
                h.Password("guest");
            });
            configurator.ConfigureEndpoints(context);
        });
    });
    // 添加宿主服务注册
    services.AddMassTransitHostedService();
}
catch (Exception ex) 
{
    throw new Exception(ex.Message, ex);
}

2. 缺失ITokenFactory的依赖注册

问题:Token微服务的容器配置中未注册ITokenFactory的实现类,但TokenService的构造函数和ITokenService的工厂注册逻辑都依赖该服务,这会触发额外的解析异常,被包含在AggregateException中。

解决方案:添加ITokenFactory的服务注册,例如:

// 在注册ITokenService之前添加
services.AddScoped<ITokenFactory, TokenFactory>();

3. 服务注册顺序优化(可选)

虽然依赖注入容器在请求阶段才会解析服务,注册顺序不影响功能,但为了代码可读性和维护性,建议先注册所有基础依赖服务(如数据库上下文、ITokenRepository、ITokenFactory),再注册依赖它们的ITokenService。

调整后的注册顺序示例:

// 1. 配置TokenSettings
var tokenSettings = new TokenSettings();
configuration.Bind("Token", tokenSettings);
services.Configure<TokenSettings>(configuration.GetSection("Token"));

// 2. 注册数据库上下文
services.AddDbContext<TokenDbContext>(options =>
{
    options.UseSqlServer(hiding this);
});

// 3. 注册基础依赖服务
services.AddScoped<ITokenRepository, TokenRepository>();
services.AddScoped<ITokenFactory, TokenFactory>();

// 4. 配置MassTransit及宿主服务
services.AddMassTransit(config =>
{
    // ... 现有配置
});
services.AddMassTransitHostedService();

// 5. 注册ITokenService
services.AddScoped<ITokenService>(sp =>
{
    // ... 现有代码
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:44:53