This sample shows how to configure the NServiceBus pipeline to propagate tenant information to downstream endpoints automatically. The sample assumes that the tenant information is passed as a message header.
Code walk-through
Attaching tenant information to the messages
In most cases the best way to attach tenant information to messages is with a custom message header. The following code demonstrates how to set a custom tenant_id
header.
var options = new SendOptions();
options.SetHeader("tenant_id", tenantId);
await endpointInstance.Send(new PlaceOrder(), options);
Creating behaviors
Two behaviors are required to propagate the tenant information.
Retrieving and storing the tenant information
The first behavior is responsible for extracting the tenant information from the incoming message header and placing it in the pipeline execution context bag. This behavior executes as part of the message receive pipeline.
public class StoreTenantIdBehavior :
Behavior<IIncomingLogicalMessageContext>
{
public override Task Invoke(IIncomingLogicalMessageContext context, Func<Task> next)
{
if (context.MessageHeaders.TryGetValue("tenant_id", out var tenant))
{
context.Extensions.Set("TenantId", tenant);
}
return next();
}
}
Propagating the tenant information to the outgoing messages
The second behavior is responsible for attaching the tenant information header(s) to outgoing messages based on the pipeline context. This behavior executes as part of the message send pipeline.
public class PropagateTenantIdBehavior :
Behavior<IOutgoingLogicalMessageContext>
{
public override Task Invoke(IOutgoingLogicalMessageContext context, Func<Task> next)
{
if (context.Extensions.TryGet("TenantId", out string tenant))
{
context.Headers["tenant_id"] = tenant;
}
return next();
}
}
Registering the behaviors
The following code is needed to register the created behaviors in the pipeline.
var pipeline = endpointConfiguration.Pipeline;
pipeline.Register(new StoreTenantIdBehavior(), "Stores tenant ID in the session");
pipeline.Register(new PropagateTenantIdBehavior(), "Propagates tenant ID to outgoing messages");
Message handlers
The OrderPlaced
message handler in the Sales endpoint publishes an OrderAccepted
event.
class PlaceOrderHandler :
IHandleMessages<PlaceOrder>
{
static readonly ILog log = LogManager.GetLogger<PlaceOrderHandler>();
public Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
var tenant = context.MessageHeaders["tenant_id"];
log.Info($"Processing PlaceOrder message for tenant {tenant}");
return context.Publish(new OrderAccepted());
}
}
In addition to that, both the OrderAccepted
and OrderPlaced
message handlers log the tenant ID header value extracted from the incoming message.
Running the sample
Run the sample. Once running, in the Client console press any key to send messages. Note that the logged tenant ID is the same in both the Sales and Billing endpoints.