3

I have a service-class that looks like:

class BillingService
{
    public void CheckBillingStatus(BillingOperationRequestDto dto)
    {
    }

    public void AnotherOperationOnBillings(BillingOperationRequestDto dto)
    {
    }
}

Also I have another class that listen to some queue from RabbitMq. I want to write something like:

class MessageListener<T> where T : BaseDto {
        public void GetMessage<T>(Func ... )

        MessageListener<T>(string queueToListen)
        {
        }
}

The idea behind this code is that I want to use it as:

BillingService bs = new BillingService();
var listener = new MessageListener<BillingOperationRequestDto>();

listener.GetMessage<BillingOperationRequestDto>(bs.CheckBillingStatus);

I want to specifiy not only the data expected from queue, but also which method to invoke on this data. Is it correct approach? I thought about getting only one message from queue and than send data to another class, but didn't find an apporach to do it, so decided to run GetMessage in loop and specify what action should be performed when message appears.

Update #1.1: Is there a way to send a delegate to

listener.GetMessage<BillingOperationRequestDto>(bs.CheckBillingStatus);

if my methods in BillingService class will have different method signatures? For example,

public BillingStatusResult CheckBillingStatus(BillingOperationRequestDto dto)
{
}
public AnotherReturnValue AnotherOperationOnBilling(BillingOperationRequestDto dto, string requestedIp, TimeSpan period)
{
}
  • 2
    The delegate type has to have a signature that matches your method. In your case a method that takes one argument and returns void. That's an `Action` Also I don't think you want to redefine the generic type on the methods, it's already defined on the class. – juharr Aug 14 '18 at 16:17
  • Just as an aside, `GetMessage` is a bad name for a void method since it doesn't actually 'get' anything. And `CheckBillingStatus` is a bad name for a method that actually returns something. – Chris Dunaway Aug 14 '18 at 21:56

2 Answers2

3

As @juharr already mentioned, you can use generic delegates (which has type of Action<T> or Func<T, TResult> if you need to retrieve result from a delegate).

More information you can find in this question or documentation

class MessageListener<T> where T : BaseDto {
    public void GetMessage<T>(Action<T> action)
    {
    }

    MessageListener<T>(string queueToListen)
    {
    }
}
Renat Zamaletdinov
  • 1,210
  • 1
  • 21
  • 36
0

A Func<T, TResult> is a delegate that returns a result. You'll want to use an Action<T>, which does not return a result. The generic type parameters of your Action<T> must match the signature of the method you'll be passing.

Oftentimes when consuming messages coming off of a message queue, you'll have a listener class that wraps the client for that message queue and you'll handle a MessageReceived event within your listener (I'm speaking in general terms - I've not worked specifically with RabbitMQ). So your listener might look something like this (pseudocode):

class MessageListener<T> where T : BaseDto {
    var _client = new QueueClient();

    MessageListener<T>(string queueToListen, Action<T> onMessageReceived)
    {
        _client = new QueueClient("<your_connection_string>", queueToListen);
        _client.MessageReceived += onMessageReceived;
    }
}

Usage would then be something like this:

BillingService bs = new BillingService();
var listener = new MessageListener<BillingOperationRequestDto>("myQueue", bs.CheckBillingStatus);
Jon
  • 569
  • 2
  • 11