HaBo
HaBo

Reputation: 14297

Understanding Async Methods using C# 4.6.1

I have following Synchronous an Asynchronous methods

public static void Info(string message)
{
    if (_logTypes.Contains(InfoLogType))
    {
        string applicationName, methodName, className;
        ReflectClassAndMethod(out applicationName, out className, out methodName);
        Write(applicationName, "Info", className, methodName, message);
    }
}

public static async void InfoAsync(string message)
{
    if (_logTypes.Contains(InfoLogType))
    {
        string applicationName, methodName, className;
        ReflectClassAndMethod(out applicationName, out className, out methodName);
        await WriteAsync(applicationName, "Info", className, methodName, message);
    }
}

Further my write methods are like this:

private static void Write(string applicationName, string logType, string className, string methodName, string message)
        {
         // construct me _event object
         var collection = Database.GetCollection<Event>(typeof(Event).Name);
         collection.InsertOne(_event);
    }

 private static Task WriteAsync(string applicationName, string logType, string className, string methodName, string message)
        {
         // construct my _event object
         var collection = Database.GetCollection<Event>(typeof(Event).Name);
          await collection.InsertOneAsync(_event);

        }

Using a test console app I call these synchronous and asynchronous method as below:

 static void Main(string[] args)
    {
      Log.Info("Synchronous write");
      Log.InfoAsync(DateTime.Now.ToString(CultureInfo.InvariantCulture));
    }

This will insert two documents into my Mongo Collection. but if I comment the synchronous call out, nothing will be inserted.

 static void Main(string[] args)
        {
          //Log.Info("Synchronous write");
          Log.InfoAsync(DateTime.Now.ToString(CultureInfo.InvariantCulture));
        }

This will insert nothing. Why is that?

Upvotes: 0

Views: 552

Answers (2)

Mafii
Mafii

Reputation: 7445

Because your application terminates before the logger is finished.

You can simply await the call:

static void Main(string[] args)
{
  //Log.Info("Synchronous write");
  await Log.InfoAsync(DateTime.Now.ToString(CultureInfo.InvariantCulture));
}

Or, because this doesn't work in Main, read that: Can't specify the 'async' modifier on the 'Main' method of a console app

You can simply Log.InfoAsync(DateTime.Now.ToString(CultureInfo.InvariantCulture)).Wait();


EDIT:

async Main is now available when using C# 7.1: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/async-main.md

So just use static async Task Main(string[] args)

Upvotes: 2

smoksnes
smoksnes

Reputation: 10851

First, I would try to avoid async void InfoAsync.

Prefer async Task methods over async void methods

Instead you should try something like this:

public static Task InfoAsync(string message)
{
    if (_logTypes.Contains(InfoLogType))
    {
        string applicationName, methodName, className;
        ReflectClassAndMethod(out applicationName, out className, out methodName);
        return WriteAsync(applicationName, "Info", className, methodName, message);
    }
}

This has several upsides. First, there's no reason to await WriteAsync. Read more about it here. It only adds overhead and could affect performance negatively. Secondly, because you return a Task instead of void it can be properly awaited by the caller instead.

And await it in your main instead. Since it's main you cannot use await, instead you can use WaitAndUnwrapException().

static void Main(string[] args)
{
    //Log.Info("Synchronous write");
    var task = Log.InfoAsync(DateTime.Now.ToString(CultureInfo.InvariantCulture));
    task.WaitAndUnwrapException();

    // or
    // task.Wait();
    // Now the application won't finish before the async method is done.
}

What if I have to use this Log.InfoAsync in any other methods of my WebAPP, which are not async methods?

Then they should use Info instead of InfoAsync. If possible, try to use async all the way. If it's not possible, then you should consider if you really add anything by using the async method. When you await it you will still block the thread, and if you're using .Result there's a chance of deadlock. So, in my opinion there's really few cases when you want to use an async method in an synchronous context.

Further interesting reading: Should Task.Wait be deprecated?

Upvotes: 3

Related Questions