MassTransit: Adding Headers to Publish Pipeline - c#

I'm using MassTransit 3.2.4 and I'm trying to add some header information for to my published messages but the code to set the header never seems to run. I'm not sure why this doesn't work.
var bus = Bus.Factory.CreateUsingRabbitMq(config =>
{
var host = config.Host(new Uri("rabbitmq://localhost/"), h {});
config.ReceiveEndpoint(host, "TestPublisher", e =>
{
e.ConfigurePublish(x => x.UseSendExecute(context =>
context.Headers.Set("HeaderKey", "HeaderValue")
));
});
});
On the consumer end I'm trying to read the header
public Task Consume(ConsumeContext<IActionHappened> context)
{
var headerValue = context.Headers.Get("HeaderKey", "Default Value");
}
Do I need to add an interceptor or something else in order to set header information?

Figured it out after much guessing. Just had the ConfigurePublish in the wrong place
var bus = Bus.Factory.CreateUsingRabbitMq(config =>
{
var host = config.Host(new Uri("rabbitmq://localhost/"), h => {});
config.ConfigurePublish(x => x.UseSendExecute(context =>
{
context.Headers.Set("HeaderKey", "HeaderValue");
}));
}

Related

Consume method is not being called using MassTransit with Azure Service BusTopics in a .Net microservice application

I know that this is being asked a lot, but I already visited a lot of question and I'm in the dark at the moment.
I'm using 2 different apps, one is the producer and the other one is the consumer. The applications are using topic-subscription type.
Producer:
services.AddMassTransit(serviceCollectionConfigurator =>
{
serviceCollectionConfigurator.AddBus(registrationContext => Bus.Factory.CreateUsingAzureServiceBus(configurator =>
{
configurator.Host("connectionString");
configurator.Message<CreateEvent>(configTopology =>
{
configTopology.SetEntityName("topic1");
});
}
));
});
Consumer:
services.AddMassTransit(x =>
{
x.AddConsumer<CreateConsumer>(); //Consumer class
x.UsingAzureServiceBus((context, cfg) =>
{
cfg.Host("connectionString");
cfg.Message<CreateEvent>(configTopology =>
{
configTopology.SetEntityName("topic1");
});
cfg.SubscriptionEndpoint<CreateEvent>("subscription1", e =>
{
e.PrefetchCount = 100;
e.MaxConcurrentCalls = 100;
e.LockDuration = TimeSpan.FromMinutes(5);
e.MaxAutoRenewDuration = TimeSpan.FromMinutes(30);
e.UseMessageRetry(r => r.Intervals(100, 200, 500, 800, 1000));
e.UseInMemoryOutbox();
e.ConfigureConsumer<CreateConsumer>(context);
});
});
});
}
public class CreateConsumer: IConsumer<CreateEvent>
{
public Task Consume(ConsumeContext<CreateEvent> context)
{
//breakpoint here
}
}
One of the errors I spotted was the namespace of CreateEvent needs to be the same. When the producer publish the message I can't see the message being sent to azure, neither being received in the consumer.
I assume the problem can be located in both configurations but I have no clue. Any thoughts?
Edit: Forgot to mention I'm using masstransit v8, it seems by default they inject the hosted service to run the bus automatically.

Azure Service Bus for messaging and saga persistence

I'm trying to persist the states of my saga into the Session of the AzureService Bus Messages. As long as the State of the Sage is just in memory it works fine. But if I activate RequiresSession and use a MessageSessionSagaRepository, my sage isn't doing anything anymore.
services.AddMassTransit(x =>
{
x.AddBus(provider => Bus.Factory.CreateUsingAzureServiceBus(cfg =>
{
cfg.Host(ConnectionString);
cfg.ReceiveEndpoint(EnrichQueue, e =>
{
// works
//e.StateMachineSaga(new EnrichmentStateMachine(), new InMemorySagaRepository<EnrichmentState>());
// doesn't work
e.RequiresSession = true;
e.StateMachineSaga(new EnrichmentStateMachine(), MessageSessionSagaRepository.Create<EnrichmentState>());
});
}));
});
Did I miss something that I should have configured?
Your configuration is a bit mixed, I'd suggest cleaning it up to bring it up to date and make it consistent:
services.AddMassTransit(x =>
{
x.AddSagaStateMachine<EnrichmentStateMachine, EnrichmentState>()
.MessageSessionRepository();
x.UsingAzureServiceBus((context, cfg) =>
{
cfg.Host(ConnectionString);
cfg.ReceiveEndpoint(EnrichQueue, e =>
{
e.RequiresSession = true;
e.ConfigureSaga<EnrichmentState>(context);
});
}));
});
Messages sent/published to that endpoint require a SessionId, which is covered in the documentation.

How can I add publish message configuration on a running IBusControl

I'm using MassTransit with RabbitMqTransport.
Assume I have run IBusControl using:
var control = Bus.Factory.CreateUsingRabbitMq(c =>
{
var host = confgurator.Host(config.BuildHostUri(), h =>
{
...
});
...
});
await control.StartAsync();
Later I connected new endpoint to this running instance, using:
host.ConnectReceiveEndpoint(Configuration.QueueName, this.ConfigureEndpoint);
Is there a way to configure Publish/Send for new Message types at this moment also? By "configure Publish/Send" I mean using methods like existing on IRabbitMqBusFactoryConfigurator:
confgurator.Send<MessageContract>(_ =>
{
_.UseRoutingKeyFormatter(__ => Configuration.QueueName);
});
confgurator.Message<MessageContract>(x => x.SetEntityName(nameof(MessageContract)));
confgurator.Publish<MessageContract>(_ =>
{
...
}
As per Chris Patterson comment, configuring Publish/Send for message type can only be done during configuration, prior to starting the bus.

There is any way to access headers of published event in masstransit saga?

Is there any way to access headers in saga when I published event like this ?
await busControl.Publish<IOrderCreated>(new
{
OrderId = dto.Id
}, context =>
{
context.Headers.Set(LogConstansts.Common.OperationId,Guid.Parse(values.Single()).ToString());
context.Headers.Set(LogConstansts.QueueMessageHeaderNames.Publisher, Request.RequestUri.AbsoluteUri);
});
and then in saga
Initially(
When(OrderCreated)
.Then(context =>
{
//get headers somehow?
context.Instance.OrderId = context.Data.OrderId;
})
Yes, you can access it by fetching the consume context payload from the behaviour context:
Initially(
When(OrderCreated)
.Then(context =>
{
ConsumeContext<IOrderCreated> c;
if (context.TryGetPayload(out c))
{
c.Headers.Get<string>("myheader");
// do something
}
context.Instance.OrderId = context.Data.OrderId;
})

Disable round-robin message consumption on MassTransit

I have created a basic demo pub/sub application which works on localhost with MassTransit.
What I want to achieve is to publish a message and all the subscribers should receive the message.
At the moment, in my environment I start one publisher app and two subscriber apps. But when I publish a message the subscribers receive the message in turns.
My pub/sub code:
Publish:
var bus = Bus.Factory.CreateUsingRabbitMq(config =>
{
config.Host(new Uri("rabbitmq://localhost/"), h => { });
config.ExchangeType = ExchangeType.Fanout;
});
var busHandle = bus.Start();
bus.Publish<SomethingHappened>(message);
Subscribers use this code:
var bus = Bus.Factory.CreateUsingRabbitMq(config =>
{
var host = config.Host(new Uri("rabbitmq://localhost/"), h => { });
config.ReceiveEndpoint(host, "MassTransitExample_Queue", e => e.Consumer<SomethingHappenedConsumer>());
});
var busHandle = bus.Start();
Console.ReadKey();
busHandle.Stop();
When reading the article below I found that the queue name must be unique
https://www.maldworth.com/2015/10/27/masstransit-send-vs-publish/
When building your bus and registering an endpoint like so:
sbc.ReceiveEndpoint(...), one has to be sure that the queueName
parameter is unique.
So my subscribers code looks like this now:
var bus = Bus.Factory.CreateUsingRabbitMq(config =>
{
var host = config.Host(new Uri("rabbitmq://localhost/"), h => { });
config.ReceiveEndpoint(host, "MTExQueue_" + Guid.NewGuid().ToString(), e => e.Consumer<SomethingHappenedConsumer>());
});
var busHandle = bus.Start();
Console.ReadKey();
busHandle.Stop();

Categories