Reputation: 117
I have a saga I'm trying to run with masstransit that requires a refit client, and i want to have the client dependency injected into the saga.
I'm using MassTransit 5.2.3 with MassTransit.Extensions.DependencyInjection 5.2.3 to setup as follows:
...
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();
...
the code for the saga is:
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) {...}
}
This causes a "Failed to create the saga connector for MyNamespace.MySaga" exception, with inner exception "ConfigurationException: The saga MyNamespace.MySaga must have either a default constructor and a writable CorrelationId property or a constructor with a single Guid argument to assign the CorrelationId"
Upvotes: 3
Views: 1168
Reputation: 19640
MassTransit focus for sagas had been moved to state machine sagas, so overall Automatonymous sagas are preferred. For the "classic" sagas, the requirement is given to you in the error message. You can use the code from the 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();
Of course, you will need to have the Client
public property in the saga class and you won't be using the constructor injection. You also need those two constructors that the error message is telling you to have:
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) {...}
}
Design consideration
One thing that I have to add is that the Saga in MassTransit is close to the Process Manager pattern. It means that sagas should not have any logic except the orchestration logic and should not do anything else except for handling messages. So, I won't recommend using things like REST API clients inside sagas. If the saga needs to get some data to make a decision about message routing, it should use messages to get that data.
Upvotes: 2