1

I have adapted the following code to attempt to load from a web api from the asp.net code by Wasson.

static public async Task<IEnumerable<T>> ExecuteAsync(HttpClient client, String endPoint)
    {
        IEnumerable<T> result = null;
        HttpResponseMessage response =  client.GetAsync(endPoint).Result;
        response.EnsureSuccessStatusCode();
        if (response.IsSuccessStatusCode)
        {
            var tResult = await response.Content.ReadAsStringAsync();
            result = JsonConvert.DeserializeObject<IEnumerable<T>>(tResult);
        }
        return result;
    }

As I have it designed, I think this procedure will run asynchronously, but I am not sure how to test it to make sure it does.

I am new to using asynchronous coding, so any suggestions would be helpful.

The calling procedure is as follows:

public virtual IEnumerable<T> Fill()
    {
        IEnumerable<T> result = null;
        try
        {
            using (var client = CreateClient("", new MediaTypeWithQualityHeaderValue("application/json")))
            {

                String _endPoint = "api/" + typeof(T).Name + "/Get";

                result = (ExecuteAsync(client, _endPoint)).Result;
            }
        }
        catch (Exception ex)
        {
            LogError(ex.Message);

        }
        return result;
    }

Is this combination likely to run asynchronously as I want it to?

The reason I want to be able to run it asynchronously is that the Fill routines fetch large amounts of data from a database. It is more a case of a large number of individual records rather than a large size for each record, although the size of some of the records may also be an issue.

What I don't want is the user sitting there waiting for the entire page to load while the communication with the database is occurring.

It doesn't really matter in this case whether I am directly connecting to the database or going through the web api I am using: It takes a long time in some cases either way.

I am also concerned about deadlocks: One large fetch coming in while another is pending.

I initially patterned the code after Mike Wasson's sample code, but found that the code hanged indefinitely even though it compiled.

Does this help frame the situation a little better?

Timothy Dooling
  • 470
  • 1
  • 4
  • 17
  • No. the `.Result` makes it a blocking call. `Fill` should be marked `async` so you can call `result = await ExecuteAsync(client, _endpoint);` – Ron Beyer Nov 09 '15 at 18:37
  • In Visual Studio, I believe your Output will tell you when the threads used are exiting. That's how I've always seen if async is actually creating threads. My logic is probably faulty, but if it doesn't show multiple threads there, then I assume it didn't....and so far it's been right. – trueCamelType Nov 09 '15 at 18:39
  • As for testing some suggestions. At first I fell in the trap using `await Task.Delay(TimeInMillisecondsHere)` but then realized that you need a blocking operation to actually test that so now using for loops like `for(int i=0; i – kirotab Nov 09 '15 at 18:40
  • 3
    @trueCamelType `async` doesn't create any threads – kirotab Nov 09 '15 at 18:42
  • So it doesn't. As shown [here](http://stackoverflow.com/questions/27265818/does-async-await-create-new-thread). My bad! – trueCamelType Nov 09 '15 at 18:45
  • I am trying to avoid marking the Fill as async because then I have to change the code everywhere it is used to return the IEnumerable I want instead of Task>. – Timothy Dooling Nov 09 '15 at 18:57
  • 2
    @TimothyDooling The **definition** of an asynchronous method is one that returns before it has finished doing its work. If you force the method to return the finished value from the method when it returns then it can't ever be asynchronous, by definition. There are lots of ways that an asynchronous method can allow a caller to access the results of the operation; a `Task`, is one way, a callback is another, events is a third, and there are others, but fundamentally the method **must** return to the caller before it has done its work, or else it is not asynchronous. – Servy Nov 09 '15 at 19:39
  • 1
    Given the excellent feedback you've been given so far, especially by commenter Servy and answerer Alexei Levenkov, please edit and improve your question so we can understand what you are really asking. Clearly the code you wrote is _not_ asynchronous. But it also seems that you don't actually want asynchronous code; if you did, you would be willing and able to change the callers to suit. – Peter Duniho Nov 09 '15 at 22:03

1 Answers1

0

Not sure what you're after here mate. The code you posted will still block the thread it's on since you're calling Result which will block.

result = (ExecuteAsync(client, _endPoint)).Result;

You could make it asynchronous by letting the async and await keywords spread back to whatever method initially created the request.

public virtual async Task<IEnumerable<T>> Fill()
{
    ...
    result = await ExecuteAsync(client, _endPoint);
    ...
}

However I'm not sure this really is what you're after since you mention

What I don't want is the user sitting there waiting for the entire page to load while the communication with the database is occurring.

By default, making things asynchronous will not solve this for you. An operation that takes 15 seconds to complete will take 15 seconds to complete regardless of it being synchronous or asynchronous. The difference is that if it's asynchronous then you're being more resource effective (meaning, you'll free up the thread to preform other duties while waiting for something to complete).

However, you can use tasks to achive parallelity. Take for example:

public void DoWork()
{
    Thread.Sleep(10000);
}

public void DoMoreWork()
{
    Thread.Sleep(10000);
}

If we called these two like this

DoWork();
DoMoreWork();

Then that would take 20000 ms or 20 seconds And if we make it asynchronous

public async Task DoWork()
{
    await Task.Delay(10000);
}

public async Task DoMoreWork()
{
    await Task.Delay(10000);
}

and call it like this

await DoWork();
await DoMoreWork();

Then it will STILL take 20 seconds to complete. However, since DoWork and DoMoreWork can operate independent from eachothers we could run them both at the same time by doing

await Task.WhenAll(DoWork(), DoMoreWork());

This would (in a perfect world) result in both tasks being done in 10 seconds halving the time the user has to wait.

Hope I shed some light on the issue :)

Shazi
  • 1,490
  • 1
  • 10
  • 22