DoWork2 is not immediately executed following the completion of client.GetStringAsync if DoWork1 runs longer time than client.GetStringAsync
Once you hit that point await client.GetStrinkAsync, DoWork1() has already completed, as from your example it looks as it's execution is synchronous. Once client.GetStringAsync completes, then DoWork2 is set to execute.
The execution flow will be:
GetStringAsync asynchronously starts. It is executed until it hits it's first internal await, and then yields control back to AccessTheWebAsync.
DoWork1() kicks off. As it's synchronous, everyone waits for it's completion
client.GetStringAsync is asynchronously waited for completion. await will naturally yield the control of execution to it's caller.
Once client.GetStringAsync completes, execution will return to AccessTheWebAsync and DoWork2() will execute synchronously.
urlContents.length will be returned.
Generally, everything after the first await keyword is set to be the continuation for the rest of the method.