【问题标题】:Masstransit error on setting up saga with dependency injection使用依赖注入设置 saga 时出现 Masstransit 错误
【发布时间】:2019-01-23 03:19:50
【问题描述】:

我正在尝试使用需要改装客户端的 masstransit 运行 saga,并且我希望将客户端依赖项注入到 saga 中。

我使用 MassTransit 5.2.3 和 MassTransit.Extensions.DependencyInjection 5.2.3 进行如下设置:

...
var serviceCollection = new ServiceCollection();
serviceCollection.AddRefitClient<IClient>(...).ConfigureHttpClient(...);
serviceCollection.AddMassTransit(c =>
{
    c.AddSaga<MySaga>();
});    
serviceCollection.AddScoped<MySaga>();
serviceCollection.AddSingleton<ISagaRepository<MySaga>, MessageSessionSagaRepository<MySaga>>(x => new MessageSessionSagaRepository<MySaga>());

var serviceProvider = serviceCollection.BuildServiceProvider();
var bus = Bus.Factory.CreateUsingAzureServiceBus(cfg =>
{
    var host = ...;
    ...
    cfg.ReceiveEndpoint(host, "MyQueue", e =>
    {   
        ... 
        e.Saga<MySaga>(serviceProvider);
    });
});

bus.Start();
...

传奇的代码是:

class MySaga :
    ISaga,
    InitiatedBy<IStep1>,
    Orchestrates<IStep2>
{
    private readonly IClient _client;

    public Guid CorrelationId { get; set; }

    public MySaga(IClient client)
    {
        _client = client;
    }

    public async Task Consume(ConsumeContext<IStep1> context) {...}
    public async Task Consume(ConsumeContext<IStep2> context) {...}
}

这会导致“无法为 MyNamespace.MySaga 创建 saga 连接器”异常,内部异常“ConfigurationException:saga MyNamespace.MySaga 必须具有默认构造函数和可写 CorrelationId 属性或具有单个 Guid 参数的构造函数分配 CorrelationId"

【问题讨论】:

  • Alexey 在构造函数上是对的,如果你需要在你的消费方法中使用服务,你可以使用 consumeContext.GetPayload().GetRequiredService(...) 来解决它们。由于您已经在使用 .Saga(serviceProvider) 重载,因此应该注册适当的范围提供程序。

标签: dependency-injection .net-core masstransit


【解决方案1】:

MassTransit 的 sagas 焦点已移至状态机 sagas,因此总体而言 Automatonymous sagas 是首选。对于“经典”的 sagas,错误消息中给出了要求。您可以使用Injection_Specs.cs中的代码

var refitClient = ...;

var serviceCollection = new ServiceCollection();
serviceCollection.AddMassTransit(c =>
{
    c.AddSaga<MySaga>();
});    
serviceCollection.AddScoped<MySaga>();
serviceCollection.AddSingleton<ISagaRepository<MySaga>, MessageSessionSagaRepository<MySaga>>(x => new MessageSessionSagaRepository<MySaga>());

var serviceProvider = serviceCollection.BuildServiceProvider();
var bus = Bus.Factory.CreateUsingAzureServiceBus(cfg =>
{
    var host = ...;
    ...
    cfg.ReceiveEndpoint(host, "MyQueue", e =>
    {   
        ... 
        e.Saga<MySaga>(serviceProvider, 
            x => x.UseExecute(ctx => ctx.Saga.Client = refitClient));
    });
});

bus.Start();

当然,您需要在 saga 类中拥有 Client 公共属性,并且您不会使用构造函数注入。您还需要错误消息告诉您的这两个构造函数:

class MySaga :
    ISaga,
    InitiatedBy<IStep1>,
    Orchestrates<IStep2>
{
    public IClient Client { get; set; }

    public Guid CorrelationId { get; set; }

    public MySaga()
    {
    }

    public MySaga(Guid correlationId)
    {
        CorrelationId = correlationId;
    }

    public async Task Consume(ConsumeContext<IStep1> context) {...}
    public async Task Consume(ConsumeContext<IStep2> context) {...}
}

设计考虑

我必须补充一点,MassTransit 中的 Saga 与流程管理器模式很接近。这意味着 sagas 除了编排逻辑之外不应该有任何逻辑,并且除了处理消息之外不应该做任何其他事情。因此,我不建议在 sagas 中使用诸如 REST API 客户端之类的东西。如果 saga 需要获取一些数据来决定消息路由,它应该使用消息来获取这些数据。

【讨论】:

    猜你喜欢
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多