0

I'm starting with IoT Hub and Azure services. I'm following this quickstart tutorial: Quickstart: Send telemetry from a device to an IoT hub and read it with a back-end application (.NET)

I created a Free Tier IoT Hub in my Azure account and registered a device using Azure Cloud Shell. Now I'm developing a "starter" library send D2C messages and I can see that it is possible to read sent messages. I have problems with the last step, it seems that the code is written in C# 8, but I'm developing with VS 2017 and get an error in a await foreach loop.

The sample code is here, and this is the code I want to change to C# 7:

private static async Task ReceiveMessagesFromDeviceAsync(CancellationToken cancellationToken)
{
    string connectionString = "{MyConnectionString}";
    await using EventHubConsumerClient consumer = new EventHubConsumerClient(EventHubConsumerClient.DefaultConsumerGroupName, connectionString, EventHubName);
    Console.WriteLine("Listening for messages on all partitions");

    try
    {
        await foreach (PartitionEvent partitionEvent in consumer.ReadEventsAsync(cancellationToken))
        {
            ...
        }
    }
    catch (TaskCanceledException)
    {
        ...
    }
}

This is the error I get in Visual Studio:

foreach statement cannot operate on variables of type 'IAsyncEnumerable' because 'IAsyncEnumerable' does not contain a public instance definition for 'GetEnumerator'

Is it possible to rewrite this line to use with C# 7?

Some details:

  • Visual Studio Professional 2017
  • Library target framework: .NET Core 2.1 .NET 4.7.2
Jesse Squire
  • 6,107
  • 1
  • 27
  • 30
Jon
  • 891
  • 13
  • 32

1 Answers1

1

It is possible to use the library without C# 8 by managing the enumerable manually. The basic form would look something like:

public static async Task Main(string[] args)
{
    var connection = "<< CONNECTION STRING >>" ;
    var hub = "<< EVENT HUB NAME >>";
    var producer = new EventHubProducerClient(connection, hub);
    var consumer = new EventHubConsumerClient(EventHubConsumerClient.DefaultConsumerGroupName, connection, hub);

    try
    {
        Console.WriteLine("Sending...");

        using (var batch = await producer.CreateBatchAsync())
        {
            for (var index = 0; index < 50; ++index)
            {
                batch.TryAdd(new EventData(Encoding.UTF8.GetBytes(index.ToString())));
            }

            await producer.SendAsync(batch);
        }

        Console.WriteLine("Reading...");

        var iterator = consumer.ReadEventsAsync(new ReadEventOptions { MaximumWaitTime = TimeSpan.FromMilliseconds(500) }).GetAsyncEnumerator();

        try
        {
            var consecutiveEmpties = 0;

            while (await iterator.MoveNextAsync())
            {
                var item = iterator.Current;

                if (item.Data != null)
                {
                    Console.WriteLine($"\tEvent: { Encoding.UTF8.GetString(item.Data.Body.ToArray()) }");
                    consecutiveEmpties = 0;
                }
                else if (++consecutiveEmpties > 5)
                {
                    break;
                }
            }
        }
        finally
        {
           await iterator.DisposeAsync();
        }

        Console.WriteLine("Done reading.");
    }
    finally
    {
        await producer.CloseAsync();
        await consumer.CloseAsync();
    }

    Console.ReadKey();
}

If you prefer, it is also possible to use C# 8 with Visual Studio 2017 by using the latest compilers package, as mentioned in the answer to this question.

Apologies; we've been intending a sample to demonstrate but have not yet had the opportunity to implement it. More context can be found in this GitHub issue.

Jesse Squire
  • 6,107
  • 1
  • 27
  • 30
  • Thank you! This works for me. I going to install the latest compiler to use C# new capabilities. – Jon Oct 23 '20 at 12:05