Skip to content

Commit c974807

Browse files
committed
Add TcpClient.ConnectAsync polyfill with cancellation support
Introduces a polyfill for TcpClient.ConnectAsync(IPAddress, int, CancellationToken) for platforms lacking this overload. Updates documentation and API lists, and adds a test to verify cancellation behavior.
1 parent 0b96dac commit c974807

File tree

20 files changed

+801
-2
lines changed

20 files changed

+801
-2
lines changed

apiCount.include.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
**API count: 661**
1+
**API count: 662**

api_list.include.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,11 @@
781781
* `IAsyncEnumerable<Task<TResult>> WhenEach<TResult>(IEnumerable<Task<TResult>>, CancellationToken)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.wheneach?view=net-10.0)
782782

783783

784+
#### TcpClient
785+
786+
* `ValueTask ConnectAsync(IPAddress, int, CancellationToken)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.connectasync?view=net-10.0#system-net-sockets-tcpclient-connectasync(system-net-ipaddress-system-int32-system-threading-cancellationtoken))
787+
788+
784789
#### TextReader
785790

786791
* `ValueTask<int> ReadAsync(Memory<char>, CancellationToken)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.io.textreader.readasync?view=net-10.0#system-io-textreader-readasync(system-memory((system-char))-system-threading-cancellationtoken))

readme.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The package targets `netstandard2.0` and is designed to support the following ru
1313
* `uap10`
1414

1515

16-
**API count: 661**<!-- singleLineInclude: apiCount. path: /apiCount.include.md -->
16+
**API count: 662**<!-- singleLineInclude: apiCount. path: /apiCount.include.md -->
1717

1818

1919
**See [Milestones](../../milestones?state=closed) for release notes.**
@@ -1226,6 +1226,11 @@ The class `Polyfill` includes the following extension methods:
12261226
* `IAsyncEnumerable<Task<TResult>> WhenEach<TResult>(IEnumerable<Task<TResult>>, CancellationToken)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.wheneach?view=net-10.0)
12271227

12281228

1229+
#### TcpClient
1230+
1231+
* `ValueTask ConnectAsync(IPAddress, int, CancellationToken)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.connectasync?view=net-10.0#system-net-sockets-tcpclient-connectasync(system-net-ipaddress-system-int32-system-threading-cancellationtoken))
1232+
1233+
12291234
#### TextReader
12301235

12311236
* `ValueTask<int> ReadAsync(Memory<char>, CancellationToken)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.io.textreader.readasync?view=net-10.0#system-io-textreader-readasync(system-memory((system-char))-system-threading-cancellationtoken))

src/Polyfill/Polyfill_TcpClient.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#if !NET5_0_OR_GREATER && FeatureValueTask
2+
3+
namespace Polyfills;
4+
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
11+
static partial class Polyfill
12+
{
13+
/// <summary>
14+
/// Connects the client to a remote TCP host using the specified IP address and port number as an asynchronous operation.
15+
/// </summary>
16+
//Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.connectasync?view=net-10.0#system-net-sockets-tcpclient-connectasync(system-net-ipaddress-system-int32-system-threading-cancellationtoken)
17+
public static ValueTask ConnectAsync(
18+
this TcpClient target,
19+
IPAddress address,
20+
int port,
21+
CancellationToken cancellationToken = default)
22+
{
23+
if (cancellationToken.IsCancellationRequested)
24+
{
25+
return new ValueTask(Task.FromCanceled(cancellationToken));
26+
}
27+
28+
return new ValueTask(ConnectWithCancellationAsync(target, address, port, cancellationToken));
29+
}
30+
31+
static async Task ConnectWithCancellationAsync(
32+
TcpClient target,
33+
IPAddress address,
34+
int port,
35+
CancellationToken cancellationToken)
36+
{
37+
using var registration = cancellationToken.Register(() => target.Close());
38+
try
39+
{
40+
await target.ConnectAsync(address, port);
41+
}
42+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
43+
{
44+
throw new OperationCanceledException(cancellationToken);
45+
}
46+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
47+
{
48+
throw new OperationCanceledException(cancellationToken);
49+
}
50+
}
51+
}
52+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// <auto-generated />
2+
#pragma warning disable
3+
#if FeatureValueTask
4+
namespace Polyfills;
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
static partial class Polyfill
11+
{
12+
/// <summary>
13+
/// Connects the client to a remote TCP host using the specified IP address and port number as an asynchronous operation.
14+
/// </summary>
15+
public static ValueTask ConnectAsync(
16+
this TcpClient target,
17+
IPAddress address,
18+
int port,
19+
CancellationToken cancellationToken = default)
20+
{
21+
if (cancellationToken.IsCancellationRequested)
22+
{
23+
return new ValueTask(Task.FromCanceled(cancellationToken));
24+
}
25+
return new ValueTask(ConnectWithCancellationAsync(target, address, port, cancellationToken));
26+
}
27+
static async Task ConnectWithCancellationAsync(
28+
TcpClient target,
29+
IPAddress address,
30+
int port,
31+
CancellationToken cancellationToken)
32+
{
33+
using var registration = cancellationToken.Register(() => target.Close());
34+
try
35+
{
36+
await target.ConnectAsync(address, port);
37+
}
38+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
39+
{
40+
throw new OperationCanceledException(cancellationToken);
41+
}
42+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
43+
{
44+
throw new OperationCanceledException(cancellationToken);
45+
}
46+
}
47+
}
48+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// <auto-generated />
2+
#pragma warning disable
3+
#if FeatureValueTask
4+
namespace Polyfills;
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
static partial class Polyfill
11+
{
12+
/// <summary>
13+
/// Connects the client to a remote TCP host using the specified IP address and port number as an asynchronous operation.
14+
/// </summary>
15+
public static ValueTask ConnectAsync(
16+
this TcpClient target,
17+
IPAddress address,
18+
int port,
19+
CancellationToken cancellationToken = default)
20+
{
21+
if (cancellationToken.IsCancellationRequested)
22+
{
23+
return new ValueTask(Task.FromCanceled(cancellationToken));
24+
}
25+
return new ValueTask(ConnectWithCancellationAsync(target, address, port, cancellationToken));
26+
}
27+
static async Task ConnectWithCancellationAsync(
28+
TcpClient target,
29+
IPAddress address,
30+
int port,
31+
CancellationToken cancellationToken)
32+
{
33+
using var registration = cancellationToken.Register(() => target.Close());
34+
try
35+
{
36+
await target.ConnectAsync(address, port);
37+
}
38+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
39+
{
40+
throw new OperationCanceledException(cancellationToken);
41+
}
42+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
43+
{
44+
throw new OperationCanceledException(cancellationToken);
45+
}
46+
}
47+
}
48+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// <auto-generated />
2+
#pragma warning disable
3+
#if FeatureValueTask
4+
namespace Polyfills;
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
static partial class Polyfill
11+
{
12+
/// <summary>
13+
/// Connects the client to a remote TCP host using the specified IP address and port number as an asynchronous operation.
14+
/// </summary>
15+
public static ValueTask ConnectAsync(
16+
this TcpClient target,
17+
IPAddress address,
18+
int port,
19+
CancellationToken cancellationToken = default)
20+
{
21+
if (cancellationToken.IsCancellationRequested)
22+
{
23+
return new ValueTask(Task.FromCanceled(cancellationToken));
24+
}
25+
return new ValueTask(ConnectWithCancellationAsync(target, address, port, cancellationToken));
26+
}
27+
static async Task ConnectWithCancellationAsync(
28+
TcpClient target,
29+
IPAddress address,
30+
int port,
31+
CancellationToken cancellationToken)
32+
{
33+
using var registration = cancellationToken.Register(() => target.Close());
34+
try
35+
{
36+
await target.ConnectAsync(address, port);
37+
}
38+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
39+
{
40+
throw new OperationCanceledException(cancellationToken);
41+
}
42+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
43+
{
44+
throw new OperationCanceledException(cancellationToken);
45+
}
46+
}
47+
}
48+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// <auto-generated />
2+
#pragma warning disable
3+
#if FeatureValueTask
4+
namespace Polyfills;
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
static partial class Polyfill
11+
{
12+
/// <summary>
13+
/// Connects the client to a remote TCP host using the specified IP address and port number as an asynchronous operation.
14+
/// </summary>
15+
public static ValueTask ConnectAsync(
16+
this TcpClient target,
17+
IPAddress address,
18+
int port,
19+
CancellationToken cancellationToken = default)
20+
{
21+
if (cancellationToken.IsCancellationRequested)
22+
{
23+
return new ValueTask(Task.FromCanceled(cancellationToken));
24+
}
25+
return new ValueTask(ConnectWithCancellationAsync(target, address, port, cancellationToken));
26+
}
27+
static async Task ConnectWithCancellationAsync(
28+
TcpClient target,
29+
IPAddress address,
30+
int port,
31+
CancellationToken cancellationToken)
32+
{
33+
using var registration = cancellationToken.Register(() => target.Close());
34+
try
35+
{
36+
await target.ConnectAsync(address, port);
37+
}
38+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
39+
{
40+
throw new OperationCanceledException(cancellationToken);
41+
}
42+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
43+
{
44+
throw new OperationCanceledException(cancellationToken);
45+
}
46+
}
47+
}
48+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// <auto-generated />
2+
#pragma warning disable
3+
#if FeatureValueTask
4+
namespace Polyfills;
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
static partial class Polyfill
11+
{
12+
/// <summary>
13+
/// Connects the client to a remote TCP host using the specified IP address and port number as an asynchronous operation.
14+
/// </summary>
15+
public static ValueTask ConnectAsync(
16+
this TcpClient target,
17+
IPAddress address,
18+
int port,
19+
CancellationToken cancellationToken = default)
20+
{
21+
if (cancellationToken.IsCancellationRequested)
22+
{
23+
return new ValueTask(Task.FromCanceled(cancellationToken));
24+
}
25+
return new ValueTask(ConnectWithCancellationAsync(target, address, port, cancellationToken));
26+
}
27+
static async Task ConnectWithCancellationAsync(
28+
TcpClient target,
29+
IPAddress address,
30+
int port,
31+
CancellationToken cancellationToken)
32+
{
33+
using var registration = cancellationToken.Register(() => target.Close());
34+
try
35+
{
36+
await target.ConnectAsync(address, port);
37+
}
38+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
39+
{
40+
throw new OperationCanceledException(cancellationToken);
41+
}
42+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
43+
{
44+
throw new OperationCanceledException(cancellationToken);
45+
}
46+
}
47+
}
48+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// <auto-generated />
2+
#pragma warning disable
3+
#if FeatureValueTask
4+
namespace Polyfills;
5+
using System;
6+
using System.Net;
7+
using System.Net.Sockets;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
static partial class Polyfill
11+
{
12+
/// <summary>
13+
/// Connects the client to a remote TCP host using the specified IP address and port number as an asynchronous operation.
14+
/// </summary>
15+
public static ValueTask ConnectAsync(
16+
this TcpClient target,
17+
IPAddress address,
18+
int port,
19+
CancellationToken cancellationToken = default)
20+
{
21+
if (cancellationToken.IsCancellationRequested)
22+
{
23+
return new ValueTask(Task.FromCanceled(cancellationToken));
24+
}
25+
return new ValueTask(ConnectWithCancellationAsync(target, address, port, cancellationToken));
26+
}
27+
static async Task ConnectWithCancellationAsync(
28+
TcpClient target,
29+
IPAddress address,
30+
int port,
31+
CancellationToken cancellationToken)
32+
{
33+
using var registration = cancellationToken.Register(() => target.Close());
34+
try
35+
{
36+
await target.ConnectAsync(address, port);
37+
}
38+
catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested)
39+
{
40+
throw new OperationCanceledException(cancellationToken);
41+
}
42+
catch (SocketException) when (cancellationToken.IsCancellationRequested)
43+
{
44+
throw new OperationCanceledException(cancellationToken);
45+
}
46+
}
47+
}
48+
#endif

0 commit comments

Comments
 (0)