'Using Consumer Class names as queue names

In this video by Garry Taylor, between minutes 35:00 to 39:50, he is able to create queues in RabbitMQ that are named based upon the class names of the consumer. He does this by calling the ConfigureEndpoints method on the RabbitMQ BusFactory Configurator and passing a Bus Registration Context as a parameter to that method like so:

rmqBusFactoryConfigurator.ConfigureEndpoints(busRegistrationContext);

I was wondering if I can achieve the same thing with the ReceiveEndpoint method on the RabbitMQ BusFactory Configurator.

My setup is as follows:

.NET6 WepApi (Publisher) :

===========================

Program.cs

    public static IServiceCollection EnableMessagePublisher(this IServiceCollection services)
    {
        services.AddMassTransit(busRegistrationConfigurator =>
        {
            busRegistrationConfigurator.SetKebabCaseEndpointNameFormatter();
            
            busRegistrationConfigurator.UsingRabbitMq((busRegistrationContext, rmqBusFactoryConfigurator) =>
            {
                rmqBusFactoryConfigurator.Host("busbunny", "/", "15672", rmqHostConfigurator =>
                {
                    rmqHostConfigurator.Username("guest");
                    rmqHostConfigurator.Password("guest");
                });
                
                rmqBusFactoryConfigurator.Message<ICreateResourceMessage>(messageTopologyConfigurator =>
                {
                    messageTopologyConfigurator.SetEntityName("ResourceCreator.Exchange");
                });
                
                rmqBusFactoryConfigurator.Publish<ICreateResourceMessage>(rmqMessageTopologyConfigurator =>
                {
                    rmqMessageTopologyConfigurator.ExchangeType = ExchangeType.Fanout;
                });
            });
        });
        return services;
    }

Controller.cs

[ApiController]
[Route("api/resources")]
public class ResourcesController : ControllerBase
{
    private readonly IPublishEndpoint publishEndpoint;

    public ResourcesController(IPublishEndpoint publishEndpoint)
    {
        this.publishEndpoint = publishEndpoint;
    }

    // POST
    [HttpPost]
    public async Task<IActionResult> CreateResource([FromBody]Resource resource)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(modelState: ModelState);
        }
    
        ICreateResourceMessage createResourceMessage =
            new CreateResourceMessage(Guid.NewGuid(), resource.Name, resource.Description);

        await this.publishEndpoint.Publish<ICreateResourceMessage>(createResourceMessage);
    
        return Ok(createResourceMessage);
    }
}

.NET6 Worker Service (Consumer) :

==================================

Consumer.cs

I have two consumers both have the same lines of code as below so I am only including one for brevity.

public class Resource1MessageConsumer : IConsumer<ICreateResourceMessage>
{
    private readonly ILogger<Resource1MessageConsumer> logger;

    public Resource1MessageConsumer(ILogger<Resource1MessageConsumer> logger)
    {
        this.logger = logger;
    }

    public async Task Consume(ConsumeContext<ICreateResourceMessage> context)
    {
        var x = context.Message;
    }
}

Program.cs

    public static IServiceCollection EnableMessageConsumers(this IServiceCollection services)
    {
        services.AddMassTransit(busRegistrationConfigurator =>
        {
            busRegistrationConfigurator.SetKebabCaseEndpointNameFormatter();
        
            busRegistrationConfigurator.AddConsumer<Resource1MessageConsumer, Resource1MessageConsumerDefinition>();
            busRegistrationConfigurator.AddConsumer<Resource2MessageConsumer, Resource2MessageConsumerDefinition>();
        
            busRegistrationConfigurator.UsingRabbitMq((busRegistrationContext, rmqBusFactoryConfigurator) =>
            {
                rmqBusFactoryConfigurator.Host("bugsbunny", "/", "15672", rmqHostConfigurator =>
                {
                    rmqHostConfigurator.Username("guest");
                    rmqHostConfigurator.Password("guest");
                });
            
                rmqBusFactoryConfigurator.ReceiveEndpoint(rmqReceiveEndpointConfigurator =>
                {
                    rmqReceiveEndpointConfigurator.ConfigureConsumer(busRegistrationContext, typeof(Resource1MessageConsumer));
                    rmqReceiveEndpointConfigurator.ConfigureConsumer(busRegistrationContext, typeof(Resource2MessageConsumer));
                    rmqReceiveEndpointConfigurator.Bind("ResourceCreator.Exchange");
                });
            
            });
        });
        return services;
    }

From my understanding, one could either use the ConfigureEndpoints method or the ReceiveEndpoints method. In my case, the ReceiveEndpoints works well for what I am trying to achieve as I can specifically bind a consumer to an exchange.

However, I would like the consumer's queues and their related exchanges (in RabbitMQ) to have the same naming convention as the consumer classes i.e. exactly the way it works with the ConfigureEndpoints.

Has anyone been able to achieve this?

Thanks in advance.



Solution 1:[1]

You have two consumers on the endpoint, each of which would have a different name. So the code below configures them using one of the consumers names:

busRegistrationConfigurator.UsingRabbitMq((busRegistrationContext, rmqBusFactoryConfigurator) =>
{
    rmqBusFactoryConfigurator.Host("bugsbunny", 5672, "/", rmqHostConfigurator =>
    {
        rmqHostConfigurator.Username("guest");
        rmqHostConfigurator.Password("guest");
    });

    var formatter = busRegistrationContext.GetService<IEndpointNameFormatter>() 
        ?? DefaultEndpointNameFormatter.Instance;

    var endpointName = formatter.Consumer<Resource1MessageConsumer>();

    rmqBusFactoryConfigurator.ReceiveEndpoint(endpointName, rmqReceiveEndpointConfigurator =>
    {
        rmqReceiveEndpointConfigurator.ConfigureConsumer<Resource1MessageConsumer>(busRegistrationContext);
        rmqReceiveEndpointConfigurator.ConfigureConsumer<Resource2MessageConsumer>(busRegistrationContext);
        rmqReceiveEndpointConfigurator.Bind("ResourceCreator.Exchange");
    });
});

Note, I also fixed the PORT in your host configuration since it was wrong.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chris Patterson