-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Background and Motivation
In .NET 5, we added SocketsHttpHandler.ConnectCallback, which enables a developer to supply a delegate that'll be used to establish connections. In .NET 5, the callback is only usable for asynchronous operations, but we also added sync support to SocketsHttpHandler (and HttpClient), and if you try to both use the ConnectCallback and sync APIs, you get an exception. We can trivially remove this restriction simply by telling the ConnectCallback in what mode it should operate.
Proposed API
namespace System.Net.Http
{
public sealed class SocketsHttpConnectionContext
{
+ public bool ConnectAsynchronously { get; } // true for SendAsync, false for Send
...
}
}Usage Examples
socketsHttpHandler.ConnectCallback = async (ctx, cancellationToken) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
try
{
if (context.ConnectAsynchronously)
{
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken).ConfigureAwait(false);
}
else
{
using (cancellationToken.UnsafeRegister(static s => ((Socket)s!).Dispose(), socket))
socket.Connect(context.DnsEndPoint);
}
}
catch
{
socket.Dispose();
throw;
}
return new NetworkStream(socket, ownsSocket: true);
};ConnectAsynchronously will be true for all existing uses that work today, because today the synchronous Send will throw an exception if a callback is provided. If once this API exists the ConnectCallback hasn't been updated to respect a false ConnectAsynchronously and a synchronous Send is issued, the caller will simply block waiting for the operation to complete (alternatives are also possible, like throwing an exception).
This also helps to consolidate/simplify logic in SocketsHttpHandler, which no longer needs to maintain two separate connection code paths, to special-case ConnectCallback, etc.
Example implementation:
stephentoub@3674c8d