I am trying to port some TcpClient
dependant code to .net 4.5, using StreamSocket
and DataReader
instead.
I have a function named ReadLine()
which is used everywhere. By using DataReader
in the body (LoadAsync()
) of this code, my method is forced to be marked with the async
keyword.
The chain reaction is as follows:
Now I have hundreds of places where I have to add async
to calling methods and apply await to underlying async
method calls.
This leads me to my next question...
Is there an easy way to wrap ReadLine()
so that calling methods are not aware that it's an asynchronous method, so that I don't have to change the rest of my code?
Also...
I often use this method call in a loop, from multiple places. If these methods are now marked async
, i'm afraid I might be reading data off a stream when I shouldn't be, which will cause all sorts of nightmares. Is it a problem or am I thinking too far ahead?
In this way, an async function without an await expression will run synchronously. If there is an await expression inside the function body, however, the async function will always complete asynchronously. Code after each await expression can be thought of as existing in a .then callback.
Because async functions are Promises under the hood, we can run both asyncThing1() and asyncThing2() in parallel by calling them without await . Then we can use await and Promise. all , which returns an array of results once all Promises have completed.
Marking a function as async without using await or returning a value inside it can lead to an unintended promise return and a larger transpiled output. Often the function can be synchronous and the async keyword is there by mistake.
If you forget to use await while calling an async function, the function starts executing. This means that await is not required for executing the function. The async function will return a promise, which you can use later.
Also... I often use this method call in a loop, from multiple places. If these methods are now marked async, i'm afraid I might be reading data off a stream when I shouldn't be, which will cause all sorts of nightmares. Is it a problem or am I thinking too far ahead?
If you always use await
whenver you call *Async
methods, then your async
methods will act just like synchronous methods (except they won't block). So using await
in a loop will work just like you expect.
async
does indeed "grow" through the code base. I usually think of this as similar to the old story about "turtles all the way down"; others have called it a "zombie virus".
I describe the deadlock situation in detail on my blog. As I state there, the best option is to allow async
to grow.
If you must create a synchronous wrapper for an asynchronous method, see Stephen Toub's advice. You can use Task.Result
, but you need to do two things:
ConfigureAwait(false)
everywhere. This will sidestep the deadlock situation.Result
has different error handling semantics.For your particular example, something like this should suffice:
private async Task<string> ReadLineAsync()
{
... // *Every* await in this method and every method it calls
// must make use of ConfigureAwait(false).
}
public string ReadLine()
{
try
{
return ReadLineAsync().Result;
}
catch (AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
throw;
}
}
Please carefully consider the complexity before choosing a mixed synchronous/asynchronous code base. It's not as easy as it first appears.
P.S. Generally speaking, TCP/IP code should all be asynchronous anyway. It's usually a good idea to have a continuous asynchronous read going on a socket.
Make a ReadLineAsync function and a ReadLine function.
In the ReadLine function you can call ReadLineAsync like this:
var readLineTask = ReadLineAsync();
readLineTask.Wait()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With