Pregunta

There are a bunch of classes in .NET that use the old Asynchronous Programming Model (APM), which "is no longer recommended for new development". The APM uses Begin/End method pairs, and the End method takes an IAsyncResult object as a parameter. One such class is TcpClient, with which you can connect asynchronously, like so:

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 ...
}

The Task-based Asynchronous Pattern (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 which uses the APM model and does not expose any tasks, how would one go about adapting its asynchronous methods to the TAP so that they can be used with async/await?

¿Fue útil?

Solución

It's in the documentation you linked to.

As a general rule, you should first look or ask around for updated APIs that support TAP directly. Almost all BCL classes have already been updated to support TAP, and a handful (such as HttpWebRequest) have been replaced with TAP alternatives (e.g., HttpClient). In this case, there isn't a TAP TcpClient equivalent, so wrapping them is your best bet.

If you do write TAP over 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 consume them, and separates your "interop" code from any code containing actual logic:

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

Otros consejos

You can use Task.Factory.FromAsync for that. 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);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top