samedi 12 novembre 2022

Best practice for delegating specific methods based on recevied message from RabbitMQ in .NET Core

I implemented event listener for incoming messages to my RabbitMQ queue:

//Presentation layer in CQRS
public async Task ReceiveAsync<T>(string queue, Action<T> onMessage)
{
    _channel.QueueDeclare(queue, true, false, false);
    var consumer = new AsyncEventingBasicConsumer(_channel);
    consumer.Received += async (s, e) =>
    {
        var jsonSpecified = Encoding.UTF8.GetString(e.Body.Span);
  
        var item = JsonSerializer.Deserialize<RabbitRecieverWrapperModel>(jsonSpecified);
        
        string methodName = "GetTypes";

        //Get the method information using the method info class
        MethodInfo mi = this.GetType().GetMethod(methodName);

        //Invoke the method
        // (null- no parameter for the method call
        // or you can pass the array of parameters...)
        mi.Invoke(this, null);
        //onMessage(item);

        await Task.Yield();
    };
    _channel.BasicConsume(queue, true, consumer);
    await Task.Yield();
}

Methods that I want to call based on message that I recevie from RabbitMQ resides in the Core Project: For example this is one method that I should call from my event listener

namespace SefService.Application.Invoices.Queries
{
    public class GetUnitOfMeasuresQuery : IRequest<Result<IList<UnitOfMeasureResponseDto>>>
    {
        
    }

    public class GetUnitOfMeasuresQueryHandler : IRequestHandler<GetUnitOfMeasuresQuery, Result<IList<UnitOfMeasureResponseDto>>>
    {
        public ILogger<UnitOfMeasureResponseDto> _logger { get; }
        private readonly ISefProxy _sefProxy;

        public GetUnitOfMeasuresQueryHandler(ISefProxy sefProxy, ILogger<UnitOfMeasureResponseDto> logger)
        {
            _logger = logger;
            _sefProxy = sefProxy;
        }

        public async Task<Result<IList<UnitOfMeasureResponseDto>>> Handle(GetUnitOfMeasuresQuery request, CancellationToken cancellationToken)
        {
            try
            {
                if (request is null)
                {
                    throw new ArgumentNullException(nameof(request));
                }

                var response = await _sefProxy.GetUnitOfMeasures();
                return new Result<IList<UnitOfMeasureResponseDto>> { Data = response.Data };
            }
            catch (System.Exception ex)
            {
                _logger.LogError(ex.Message, ex);
                throw new ApiException(ex.Message);
            }
        }
    }
}

Also standard call for this method, from standard WebApi (Swagger) would be like this:

/// <summary>
        /// GetUnitOfMeasures
        /// </summary>
        /// <returns></returns>
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesDefaultResponseType]
        [Route(nameof(GetUnitOfMeasures))]
        [HttpGet]
        public async Task<IActionResult> GetUnitOfMeasures()
        {
            return Ok(await Mediator.Send(new GetUnitOfMeasuresQuery()));
        }

Here is the screenshot of my project and classes: https://i.imgur.com/WWkQzMl.png

I started with using reflection, but I really need to use reflection on another class (Command in CQRS pattern, which resides in separate project).

Should I continue to use reflation in order to distinguish which Command (method) should I call based on message (in message I will have string method name) or do I maybe need to use Chain Of Responsibility pattern? What is the best practice here?

Aucun commentaire:

Enregistrer un commentaire