Mike Perrenoud
Mike Perrenoud

Reputation: 67898

ASB MessageReceiver ReceiveAsync crashes

Environment

  1. Windows 10 Professional
  2. .NET Core Console Application

Code

I have an abstracted message receiver that looks like this. In this code the entity is the name of the Subscription (e.g. user).

public class AzureMessageReceiver : ITdlMessageReceiver
{
    private readonly ServiceBusConnection serviceBusConnection;
    private readonly ILogger<AzureMessageReceiver> logger;

    public AzureMessageReceiver(ServiceBusConnection serviceBusConnection, ILogger<AzureMessageReceiver> logger)
    {
        this.serviceBusConnection = serviceBusConnection;
        this.logger = logger;
    }

    public async Task<TdlMessage<T>> ReceiveAsync<T>(string topic, string entity) where T : class
    {
        try
        {
            var subscriptionPath = EntityNameHelper.FormatSubscriptionPath(topic, entity);
            var messageReceiver = new MessageReceiver(serviceBusConnection, subscriptionPath, ReceiveMode.ReceiveAndDelete);
            var message = await messageReceiver.ReceiveAsync();

            if (message == null)
            {
                return null;
            }

            var messageString = Encoding.UTF8.GetString(message.Body);
            return JsonConvert.DeserializeObject<TdlMessage<T>>(messageString);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Error receiving Azure message.");
            return null;
        }
    }
}

The injected ServiceBusConnection is constructed like this. NOTE: this same connection initialization works to write messages to the same Topic and Subscription.

services.AddSingleton(serviceProvider =>
    new ServiceBusConnection(configuration[$"{DurableCommunicationKey}:AzureConnectionString"]));

UPDATE: here is the code that wraps the call to the receiver class and is the controller for receiving messages:

static async void Receive(ITdlMessageReceiver receiver, ILogger logger)
{
    while (true)
    {
        var message = await receiver.ReceiveAsync<TdlMessage<object>>(topic, entity);
        if (message != null)
        {
            logger.LogDebug($"Message received. Topic: {topic}. Action: {Enum.GetName(typeof(TopicActions), message.Action)}. Message: {JsonConvert.SerializeObject(message)}.");

        }

        Thread.Sleep(sleepTime);
    }
}

Problem

Every time I execute this line var message = await messageReceiver.ReceiveAsync(); it just crashes the Console app. No Exception and nothing in Event Viewer.

What I've Tried

Upvotes: 2

Views: 796

Answers (1)

Nkosi
Nkosi

Reputation: 247018

async void should be converted to an async Task as well as you should be awaiting Task.Delay instead of invoking Thread.Sleep. If going async you need to go async all the way

static async Task Receive(ITdlMessageReceiver receiver, ILogger logger) {
    while (true) {
        var message = await receiver.ReceiveAsync<TdlMessage<object>>(topic, entity);
        if (message != null) {
            logger.LogDebug($"Message received. Topic: {topic}. Action: {Enum.GetName(typeof(TopicActions), message.Action)}. Message: {JsonConvert.SerializeObject(message)}.");    
        }    
        await Task.Delay(sleepTime);
    }
}

Try making the code async all the way through, yes, but as a console application (single thread) you will be allowed to call Wait() on the Receive method in Main as it is not mixing calls that would cause problem with the async flow.

public static void Main(string[] args) {

    //...
    //...
    //...


    Receive(receiver, logger).Wait();
}

Reference Async/Await - Best Practices in Asynchronous Programming

Upvotes: 2

Related Questions