5

Situation is pretty simple - I wrote an extension method and made it async with return type Task<T>. But when I try to call it using await, compiler throws an error which suggests that the extension method wasn't recognized as async at all. Here's my code:

public static async Task<NodeReference<T>> CreateWithLabel<T>(this GraphClient client, T source, String label) where T: class
    {
        var node = client.Create(source);
        var url = string.Format(ConfigurationManager.AppSettings[configKey] + "/node/{0}/labels", node.Id);
        var serializedLabel = string.Empty;
        using (var tempStream = new MemoryStream())
        {
            new DataContractJsonSerializer(label.GetType()).WriteObject(tempStream, label);
            serializedLabel = Encoding.Default.GetString(tempStream.ToArray());
        }
        var bytes = Encoding.Default.GetBytes(serializedLabel);

        using (var webClient = new WebClient())
        {
            webClient.Headers.Add("Content-Type", "application/json");
            webClient.Headers.Add("Accept", "application/json; charset=UTF-8");
            await webClient.UploadDataTaskAsync(url, "POST", bytes);
        }

        return node;
    }


var newNode = await client.CreateWithLabel(new Task(), "Task");

Exact error message is this:

The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'

Am I doing something wrong or is it a language/compiler limitation?

slugster
  • 49,403
  • 14
  • 95
  • 145
chester89
  • 8,328
  • 17
  • 68
  • 113

1 Answers1

22

The error message is pretty clear: the method where you're calling the extension method should be marked as async.

public Task<string> MyExtension(this string s) { ... }

public async Task MyCallingMethod()
{    
    string result = await "hi".MyExtension();
}

Re-reading this part should make much more sense now:

"The 'await' operator can only be used within an async method. "

dcastro
  • 66,540
  • 21
  • 145
  • 155
  • I see. Will be more attentive next time. – chester89 Nov 01 '13 at 13:46
  • 2
    @dcastro, you may want to change the signature of `MyCallingMethod` to return a `Task`, `void` is only good for async event handlers. – noseratio Nov 02 '13 at 01:14
  • @Noseratio I disagree, there are plenty of other scenarios where you'd want "fire and forget" behaviour. I will edit my post though, simply because less experienced users might be surprised by the results of `async void`. – dcastro Nov 02 '13 at 21:48
  • 1
    @dcastro, I disagree too that there are plenty. I'd be interested to learn about any useful scenarios other than [async event handlers](http://stackoverflow.com/q/19415646/1768303) (which is obviously not the case here). – noseratio Nov 02 '13 at 21:58
  • 3
    Logging, for example. A service may want to fire a method and trigger some business logic, but return to the client asap. You don't _always_ need to wait for the result of a method. Maybe the word "plenty" was a bit too much, but saying that "void is only good for async event handlers" isn't correct either. – dcastro Nov 02 '13 at 22:12
  • Although being aware of the side effects of `async void` is very important when going down that road. – dcastro Nov 02 '13 at 22:14