Migrating from an asynchronous programming model (APM) to a task-based asynchronous template (TAP)

There is a group of classes in .NET that use the old asynchronous programming model (APM) , which is "no longer recommended for new development." APM uses Begin / End method pairs, and End method accepts an IAsyncResult object as a parameter. One of these TcpClient classes that you can connect to asynchronously, for example:

private void SomeMethod() { this.tcpClient = new TcpClient(); IAsyncResult result = this.tcpClient.BeginConnect(ip, port, EndConnect, null); } private void EndConnect(IAsyncResult asyncResult) { this.tcpClient.EndConnect(asyncResult); // ... do stuff ... } 

A task-based asynchronous template (TAP) is a more modern form of asynchronous programming that is facilitated by the use of the async and await keywords.

So, if you have a class like TcpClient that uses the APM model and doesn't reveal any tasks, how can you adapt your asynchronous methods to TAP so that they can be used with async / await ?

+7
c # asynchronous async-await task
source share
2 answers

This is in the documentation you are attached to .

Generally, you should first review or ask for updated APIs that support TAP directly. Almost all BCL classes have already been updated to support TAP, and several (for example, HttpWebRequest ) have been replaced by alternatives to TAP (for example, HttpClient ). In this case, there is no equivalent to TAP TcpClient , so their packaging is the best choice.

If you are writing TAP on top of APM wrappers, I recommend using simple extension methods:

 public static Task ConnectTaskAsync(this TcpClient client, IPAddress address, int port) { return Task.Factory.FromAsync(client.BeginConnect, client.EndConnect, address, port, null); } 

This gives you a natural way to destroy them and separates your "interop" code from any code that contains actual logic:

 async Task SomeMethodAsync() { this.tcpClient = new TcpClient(); await this.tcpClient.ConnectTaskAsync(ip, port); // ... do stuff ... } 
+11
source share

You can use Task.Factory.FromAsync . Example (for BeginReceive / EndReceive ):

 public static class SocketsExt { static public Task ReceiveDataAsync( this TcpClient tcpClient, byte[] buffer) { return Task.Factory.FromAsync( (asyncCallback, state) => tcpClient.Client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, asyncCallback, state), (asyncResult) => tcpClient.Client.EndReceive(asyncResult), null); } } 
+3
source share

All Articles