C# ClientAPI await/async usage question

I’ve noticed some strange issues when using the C# Client API. (3.4.0)

Specifically around the use of the async methods.

Many of the docs show use of the .Wait() method, vs use of “await”

Is the expectation that we should explicitly use .Wait()? If so, what (if any) benefit would we have to use the async methods?

If the expectation is that we should be able to use await, then I have a number of reproducible oddities with the ClientAPI project.

Feel free to put them up though there is a plethora of discussion
around async/await previously on this list and IIRC every single one
has been subtleties of async/await that people didn't know about.

All Tasks are awaitable.

All Tasks are awaitable, and the Method has the “Async” suffix, however, In all tests I have, using await causes the program to stall out.

I assume, because the method returns Task and is named “Async” that it will complete if I use await… which it does not.

await conn.CreatePersistentSubscriptionAsync(_subscriptionStreamName, _subscriptionGroupName, settings, Creds); //<— just stalls out

``

All the following run, however, they are really synchronous running, not “Async”

await conn.CreatePersistentSubscriptionAsync(
_subscriptionStreamName,
_subscriptionGroupName,
settings,
Creds).ContinueWith(t => { Console.WriteLine(“Continued…”); }).ConfigureAwait(false);

``

await Task.Run(()=>conn.CreatePersistentSubscriptionAsync(
_subscriptionStreamName,
_subscriptionGroupName,
settings,
Creds).ConfigureAwait(false));

``

Also works:

conn.CreatePersistentSubscriptionAsync(_subscriptionStreamName, _subscriptionGroupName, settings, Creds).Wait();

``

Many people are using exactly what you put as “hangs” I’m guessing its a console app with a readline?

Configureawait false

Simple console example.

See the lines preceded by #warning

Can you get either of the ‘awaited’ calls to work? I always get a “Lost connection” message on my server console.

The .Wait() version always runs to completion

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EventStore.ClientAPI;
using EventStore.ClientAPI.SystemData;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Repro
{

class Program
{
    private static string _testStreamName = "TestEvents-" + Guid.NewGuid();

    private static string _subscriptionStreamName = "$ce-TestEvents";
    private static string _subscriptionGroupName = "TestEvents-" + Guid.NewGuid();
    private static string _filePath = _subscriptionGroupName;

    public static Uri EsEndpoint = new Uri("tcp://localhost:1113");
    public static UserCredentials Creds = new UserCredentials("admin", "changeit");

    static void Main()
    {
        Console.WriteLine("Main()");

        Task.Run(async () =>
        {
            await MainAsync().ConfigureAwait(false);
        }).Wait();

        Console.WriteLine("Main() Complete");
    }

    private static async Task MainAsync()
    {
        Console.WriteLine("\tMainAsync()");

        ConnectionSettingsBuilder connectionSettingsBuilder = ConnectionSettings.Create();

        ConnectionSettings connectionSettings = connectionSettingsBuilder.Build();

        var conn = EventStoreConnection.Create(connectionSettings, EsEndpoint);

        conn.ConnectAsync().Wait();

        await Test(conn);

        Console.WriteLine("\n\tDelay in MainAsync : start");
        await Task.Delay(10000);

        Console.WriteLine("\n\tDelay in MainAsync : done");
    }

    private static async Task Test(IEventStoreConnection conn)
    {
        var settings =
        PersistentSubscriptionSettings.Create().ResolveLinkTos().StartFromBeginning();

        Console.WriteLine("Creating Subscription");

#warning Only the .Wait() version creates a working program
//conn.CreatePersistentSubscriptionAsync(_subscriptionStreamName, _subscriptionGroupName, settings, Creds).Wait();

#warning The following two statements result in a lost connection / halted program
await conn.CreatePersistentSubscriptionAsync(_subscriptionStreamName,_subscriptionGroupName,settings,Creds);
//await conn.CreatePersistentSubscriptionAsync(_subscriptionStreamName, _subscriptionGroupName, settings, Creds).ConfigureAwait(false);

        Console.WriteLine("Created Subscription");

        Console.WriteLine("Connecting to Subscription");

        conn.ConnectToPersistentSubscription(
            _subscriptionStreamName,
            _subscriptionGroupName,
            //(sub, e) => Resolve(sub, e),
            (sub, e) => Console.WriteLine("Event"),
            (sub, reason, ex) =>
            {
                Console.WriteLine(reason);
                Console.WriteLine(ex);
            },
            autoAck: false,
            userCredentials: Creds);

        Console.WriteLine("Connected  to Subscription");

        Console.WriteLine("\n\t Delay from Test : start");
        await Task.Delay(1000);
        Console.WriteLine("\n\t Delay from Test : done");
    }

    public static void ColoredConsoleWrite(ConsoleColor color, string text)
    {
        ConsoleColor originalColor = Console.ForegroundColor;
        Console.ForegroundColor = color;
        Console.WriteLine(text);
        Console.ForegroundColor = originalColor;
    }
}

}

``

It’s because of the console app. Install nito.async and use asyncContext

That did it.

Directly answering the original question for anyone who finds this later (correct me if its wrong):

Many of the docs show use of the .Wait() method, vs use of “await”
Is the expectation that we should explicitly use .Wait()? If so, what (if any) benefit would we have to use the async methods?

Use of .Wait() in documentation is for example purposes only.

Any method returning Task should be able to be “await-ed”.

ThanksĄ