0

I want use AMQP connection string. I want to create a single shared connection (and channel per app lifetime to avoid resource exhaustion.

1 Answer 1

0

I found this way to do it:

    public class RabbitMqService
    {
        private readonly string _rabbitMqConnectionString;
        private IConnection? _connection;
        private IChannel? _channel;
        private readonly ILogger<RabbitMqService> _logger;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private bool _initialized = false;
        public RabbitMqService(
            IConfiguration configuration,
            ILogger<RabbitMqService> logger,
            IHttpContextAccessor httpContextAccessor
        )
        {
            var rabbitMqSection = configuration.GetSection("RabbitMq");
            _rabbitMqConnectionString = rabbitMqSection["ConnectionString"]!;
            _logger = logger;
            _httpContextAccessor = httpContextAccessor;
        }

        private string GetCorrelationId()
        {
            return _httpContextAccessor.HttpContext?.TraceIdentifier 
                ?? Guid.NewGuid().ToString();
        }

        public async Task InitAsync()
        {
            if (_initialized && _connection?.IsOpen == true && 
                _channel?.IsOpen == true)
                return;
            try
            {
                var factory = new ConnectionFactory
                {
                    Uri = new Uri(_rabbitMqConnectionString)
                };

                _connection = await factory.CreateConnectionAsync();
                _channel = await _connection.CreateChannelAsync();
                _initialized = true;
            }
            catch (Exception ex)
            {
                _initialized = false;
                string correlationId = GetCorrelationId();
                _logger.LogError(ex, 
                    "Error in RabbitMq initAsync| CorrelationId: {CorrelationId}",
                    correlationId
                );
            }
        }

        public async Task<IChannel> GetChannel()
        {
            if (_connection == null || 
                !_connection.IsOpen || 
                _channel == null || !_channel.IsOpen
                )
            {
                _initialized = false;
                await InitAsync();
            }

            if (_channel == null)
                throw new InvalidOperationException(
                "Failed to initialize RabbitMQ channel."
            );

            return _channel;
        }

        public async ValueTask DisposeAsync()
        {
            if (_channel is not null)
            {
                await _channel.CloseAsync();
            }
            if (_connection is not null)
            {
                await _connection.DisposeAsync();
            }
        }
    } 


And in the program.cs file:

builder.Services.AddSingleton<RabbitMqService>();

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
    var rabbitService = scope.ServiceProvider.GetRequiredService<RabbitMqService>();
    await rabbitService.InitAsync();
}

If there is a better way please share it and THANK you very much.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.