I have a method that calls the Bing Api.

IEnumerable<WebResult> Search(string query)

I want to make this asynchronous so that if I make many calls to it, each one of those calls is independant. So, following the advice here I changed the signature to

async Task<IEnumerable<WebResult>> SearchAsynch(string query)

But I get the warning

This async method lacks 'await' operators and will run synchronously...

I want the entire method to be asynch (at least that's how I think it should work). How do I do that? Here's my code

public async Task<IEnumerable<WebResult>> SearchAsynch(string query)
        {
            if (query == null)
            {
                throw new ArgumentNullException("query cannot be null");
            }

            DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null);
            IEnumerable<WebResult> webResults = webQuery.Execute();
            return webResults;
        }

The issue is that I'm not sure what to await in this code.

有帮助吗?

解决方案

The async keyword doesn't create a new asynchronous operation, it is simply a way of more easily configuring continuations for tasks (i.e. asynchronous operations) that already exist.

In this case, the DataServiceQuery class already provides a way to asynchronously execute the query. Unfortunately it's using the old async model, not the new Task based model, so you need to use Task.Factory.FromAsync to translate it:

public Task<IEnumerable<WebResult>> SearchAsynch(string query)
{
    DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null);

    return Task.Factory.FromAsync(webQuery.BeginExecute(null, null)
        , asyncResult => webQuery.EndExecute(asyncResult)));

}

In this particular case since you don't need to do anything other than create the task you don't need async or await at all, you can just return the task that is constructed. If you wanted to do something after you got the result you could instead await the task:

public async Task<IEnumerable<WebResult>> SearchAsynch(string query)
{
    DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null);
    var results = await Task.Factory.FromAsync(webQuery.BeginExecute(null, null)
            , asyncResult=> webQuery.EndExecute(asyncResult));
    Console.WriteLine("Hi there");
    return results;
}

其他提示

I'm not really familiar with Bing API, but if the API does not contain async methods, you can make one async by wrapping the calls in a started Task. async modifier does not make your method automagically asynchronous, it only allows to await other async methods inside.

So, in your case, it would probably be the easiest to:

public Task<IEnumerable<WebResult>> SearchAsync(string query)
    {
        if (query == null)
        {
            throw new ArgumentNullException("query cannot be null");
        }

        return Task.Run(() => 
            {
                DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null);
                return webQuery.Execute();
            }
    }

Then you can await this method in other method marked as async:

var result = await SearchAsync("yourQuery");

If the Bing API has the async method pairs Begin/End, you can use Task.Factory.FromAsync to create task from the async method pairs. Servy's answer goes into more detail there.

Per MSDN

Typically, a method modified by the async keyword contains at least one await expression or statement. The method runs synchronously until it reaches the first await expression, at which point it is suspended until the awaited task is complete. In the meantime, control is returned to the caller of the method. If the method does not contain an await expression or statement, then it executes synchronously. A compiler warning alerts you to any async methods that don't contain await because that situation might indicate an error. For more information, see Compiler Warning (level 1) CS4014.

EDIT: I figured I would add to this, but it is already in the comment section of this post. A method marked with async doesn't actually run async until it hits a await keyword.

This is an example of using async in a stand alone project.

private async void button2_Click(object sender, EventArgs e)
{
    DataTable dtMessages = await getMessages2(string sqlConn2, nMessage);
}
public async Task<DataTable> getMessages2(string sqlConn, int n)
{
    //create your query and command
    var o = await cmd2.ExecuteReaderAsync();
    DataTable dtMessages = o;
    return dtMessages;
}

The warning is just telling you that wherever you are calling SearchAsynch it needs to have await before it.

var result = await SearchAsynch(query);

However, the SearchAsynch is not properly implemented as others have stated.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top