Icewing726
Icewing726

Reputation: 33

Calling Async in a Sync method

I've been reading examples for a long time now, but unfortunately I've been unable to apply the solutions to the code I'm working with. Some quick Facts/Assorted Info:

1) I'm new to C#

2) The code posted below is modified from Amazon Web Services (mostly stock)

3) Purpose of code is to compare server info to offline already downloaded info and create a list of need to download files. This snip is for the list made from the server side, only option with AWS is to call async, but I need this to finish before moving forward.

public void InitiateSearch()
{
    UnityInitializer.AttachToGameObject(this.gameObject);
    //these are the access key and secret access key for credentials
    BasicAWSCredentials credentials = new BasicAWSCredentials("secret key", "very secret key");
    AmazonS3Config S3Config = new AmazonS3Config()
    {
        ServiceURL = ("url"),
        RegionEndpoint = RegionEndpoint.blahblah

    };
    //Setting the client to be used in the call below
    AmazonS3Client Client = new AmazonS3Client(credentials, S3Config);
    var request = new ListObjectsRequest()
    {
        BucketName = "thebucket"
    };

    Client.ListObjectsAsync(request, (responseObject) =>
    {

        if (responseObject.Exception == null)
        {
            responseObject.Response.S3Objects.ForEach((o) =>
            {
                int StartCut = o.Key.IndexOf(SearchType) - 11;
                if (SearchType == o.Key.Substring(o.Key.IndexOf(SearchType), SearchType.Length))
                {
                    if (ZipCode == o.Key.Substring(StartCut + 12 + SearchType.Length, 5))
                    {
                        AWSFileList.Add(o.Key + ", " + o.LastModified);
                    }
                }
            }

            );
        }
        else
        {
            Debug.Log(responseObject.Exception);
        }
    });
}

I have no idea how to apply await to the Client.ListObjectsAsync line, I'm hoping you all can give me some guidance and let me keep my hair for a few more years.

Upvotes: 0

Views: 1296

Answers (3)

Stephen Cleary
Stephen Cleary

Reputation: 456457

I have no idea how to apply await to the Client.ListObjectsAsync line

You probably just put await in front of it:

await Client.ListObjectsAsync(request, (responseObject) => ...

As soon as you do this, Visual Studio will give you an error. Take a good look at the error message, because it tells you exactly what to do next (mark InitiateSearch with async and change its return type to Task):

public async Task InitiateSearchAsync()

(it's also a good idea to add an Async suffix to follow the common pattern).

Next, you'd add an await everywhere that InitiateSearchAsync is called, and so on.

Upvotes: 1

Florian Moser
Florian Moser

Reputation: 2663

I'm assuming Client.ListObjectsAsync returns a Task object, so a solution for your specific problem would be this:

public async void InitiateSearch()
{
    //code
    var collection = await Client.ListObjectsAsync(request, (responseObject) =>
    {
        //code
    });
    foreach (var item in collection)
    {
        //do stuff with item
    }
}

the variable result will now be filled with the objects. You may want to set the return type of InitiateSearch() to Task, so you can await it too.

await InitiateSearch(); //like this

If this method is an event handler of some sort (like called by the click of a button), then you can keep using void as return type.

A simple introduction from an unpublished part of the documentation for async-await:

Three things are needed to use async-await:

  • The Task object: This object is returned by a method which is executed asynchronous. It allows you to control the execution of the method.
  • The await keyword: "Awaits" a Task. Put this keyword before the Task to asynchronously wait for it to finish
  • The async keyword: All methods which use the await keyword have to be marked as async

A small example which demonstrates the usage of this keywords

public async Task DoStuffAsync()
{
    var result = await DownloadFromWebpageAsync(); //calls method and waits till execution finished
    var task = WriteTextAsync(@"temp.txt", result); //starts saving the string to a file, continues execution right await
    Debug.Write("this is executed parallel with WriteTextAsync!"); //executed parallel with WriteTextAsync!
    await task; //wait for WriteTextAsync to finish execution
}

private async Task<string> DownloadFromWebpageAsync()
{
    using (var client = new WebClient())
    {
        return await client.DownloadStringTaskAsync(new Uri("http://stackoverflow.com"));
    }
}

private async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);

    using (FileStream sourceStream = new FileStream(filePath, FileMode.Append))
    {
        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    }
} 

Some thing to note:

  • You can specify a return value from an asynchronous operations with Task. The await keyword waits till the execution of the method finishes, and returns the string.
  • the Task object contains the status of the execution of the method, it can be used as any other variable.
  • if an exception is thrown (for example by the WebClient) it bubbles up at the first time the await keyword is used (in this example at the line string result (...))
  • It is recommended to name methods which return the Task object as MethodNameAsync

For more information about this take a look at http://blog.stephencleary.com/2012/02/async-and-await.html.

Upvotes: 0

Collin Stevens
Collin Stevens

Reputation: 817

You can either mark your method async and await it, or you can call .Wait() or .Result() on the Task you're given back.

Upvotes: 1

Related Questions