# NServiceBus
NServiceBus is a commercial .NET messaging and workflow solution.
# Interoperability
WARNING
This package was built using a black box, clean room approach based on observed message formats within the message broker. As such, there may be edge cases and situations which are not handled by this package. Extensive testing is recommended to ensure all message properties are being properly interpreted.
MassTransit has limited message exchange support with NServiceBus, tested with the formats and configurations listed below.
# Supported Serialization Formats
- JSON (Newtonsoft)
- XML
# Header Support
MassTransit delivers messages to consumers using ConsumeContext<TMessage>
, which includes various header properties. From looking at the transport message format, headers are serialized outside of the message body. To support access to these headers in MassTransit, the transport headers are mapped as shown.
Property | Header Used | Out | Notes |
---|---|---|---|
ContentType | NServiceBus.ContentType | Y | |
ConversationId | NServiceBus.ConversationId | Y | |
CorrelationId | NServiceBus.CorrelationId | Y | |
MessageId | NServiceBus.MessageId | Y | |
SourceAddress | NServiceBus.OriginatingEndpoint | Y | formatted as queue:name |
ResponseAddress | NServiceBus.ReplyToAddress | Y | formatted as queue:name |
SentTime | NServiceBus.TimeSent | Y | |
Host.MachineName | NServiceBus.OriginatingMachine | Y | |
Host.MassTransitVersion | NServiceBus.Version | N | translated to NServiceBus x.x.x |
Supported Message Types | NServiceBus.EnclosedMessageTypes | Y | converted from AssemblyQualifiedName, types must be resolvable via Type.GetType() |
NServiceBus.MessageIntent | N | Ignored |
# RabbitMQ
NServiceBus follows the same broker topology conventions established by MassTransit. This means exchange names should be the same, which means that publish/subsribe with receive endpoints should work as expected.
RabbitMQ was tested using the following NServiceBus configuration:
var endpointConfiguration = new EndpointConfiguration("Gateway.Producer");
endpointConfiguration.UseSerialization<NewtonsoftSerializer>();
endpointConfiguration.EnableInstallers();
var transport = endpointConfiguration.UseTransport<RabbitMQTransport>();
transport.UseConventionalRoutingTopology();
transport.ConnectionString("host=localhost");
Two message contracts were created:
public class ClockUpdated :
IEvent
{
public DateTime CurrentTime { get; set; }
}
public class ClockSynchronized :
IEvent
{
public string Host {get;set;}
}
From the NServiceBus endpoint, the ClockUpdated
message was published:
var session = _provider.GetRequiredService<IMessageSession>();
await session.Publish(new ClockUpdated {CurrentTime = DateTime.UtcNow}, new PublishOptions());
And the handler in NServiceBus for the ClockSynchronized
message:
public class ClockSynchronizedHandler :
IHandleMessages<ClockSynchronized>
{
readonly ILogger<ClockSynchronizedHandler> _logger;
public ClockSynchronizedHandler(ILogger<ClockSynchronizedHandler> logger)
{
_logger = logger;
}
public Task Handle(ClockSynchronized message, IMessageHandlerContext context)
{
_logger.LogInformation("Clock synchronized: {Host}", message.Host);
return Task.CompletedTask;
}
}
On the MassTransit side, the bus was configured to use the consumer with the same message contract assembly.
services.AddMassTransit(x =>
{
x.AddConsumer<TimeConsumer>();
x.AddBus(context => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseNServiceBusJsonSerializer();
cfg.ConfigureEndpoints(context);
}));
});
With the consumer:
class TimeConsumer :
IConsumer<ClockUpdated>
{
readonly ILogger<TimeConsumer> _logger;
public TimeConsumer(ILogger<TimeConsumer> logger)
{
_logger = logger;
}
public async Task Consume(ConsumeContext<ClockUpdated> context)
{
_logger.LogInformation("Clock was updated: {CurrentTime}", context.Message.CurrentTime);
await context.Publish(new ClockSynchronized
{
Host = HostMetadataCache.Host.MachineName
});
}
}