Skip to content

Commit

Permalink
Merge in 'release/8.0-rc1' changes
Browse files Browse the repository at this point in the history
  • Loading branch information
dotnet-bot committed Aug 21, 2023
2 parents 3ddcd4d + 7d80971 commit b70b7ef
Show file tree
Hide file tree
Showing 24 changed files with 66 additions and 60 deletions.
2 changes: 1 addition & 1 deletion src/Servers/Kestrel/Core/src/ListenOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core;
/// </summary>
public class ListenOptions : IConnectionBuilder, IMultiplexedConnectionBuilder
{
internal const HttpProtocols DefaultHttpProtocols = HttpProtocols.Http1AndHttp2AndHttp3;
internal const HttpProtocols DefaultHttpProtocols = HttpProtocols.Http1AndHttp2;

private readonly List<Func<ConnectionDelegate, ConnectionDelegate>> _middleware = new List<Func<ConnectionDelegate, ConnectionDelegate>>();
private readonly List<Func<MultiplexedConnectionDelegate, MultiplexedConnectionDelegate>> _multiplexedMiddleware = new List<Func<MultiplexedConnectionDelegate, MultiplexedConnectionDelegate>>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1904,7 +1904,7 @@ public ConnectionState(ConnectionContext connection, HubConnection hubConnection
{
_messageBuffer = new MessageBuffer(connection, hubConnection._protocol,
_hubConnection._serviceProvider.GetService<IOptions<HubConnectionOptions>>()?.Value.StatefulReconnectBufferSize
?? DefaultStatefulReconnectBufferSize);
?? DefaultStatefulReconnectBufferSize);

feature.NotifyOnReconnect = _messageBuffer.Resend;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ namespace Microsoft.AspNetCore.SignalR.Client;
/// </summary>
public static class HubConnectionBuilderHttpExtensions
{
/// <summary>
/// Configures the <see cref="HttpConnectionOptions"/> to negotiate stateful reconnect with the server.
/// </summary>
/// <param name="hubConnectionBuilder">The <see cref="IHubConnectionBuilder" /> to configure.</param>
/// <returns>The same instance of the <see cref="IHubConnectionBuilder"/> for chaining.</returns>
public static IHubConnectionBuilder WithStatefulReconnect(this IHubConnectionBuilder hubConnectionBuilder)
{
hubConnectionBuilder.Services.Configure<HttpConnectionOptions>(options => options.UseStatefulReconnect = true);

return hubConnectionBuilder;
}

/// <summary>
/// Configures the <see cref="HubConnection" /> to use HTTP-based transports to connect to the specified URL.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#nullable enable
static Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilderHttpExtensions.WithStatefulReconnect(this Microsoft.AspNetCore.SignalR.Client.IHubConnectionBuilder! hubConnectionBuilder) -> Microsoft.AspNetCore.SignalR.Client.IHubConnectionBuilder!
Original file line number Diff line number Diff line change
Expand Up @@ -2560,7 +2560,7 @@ await using (var server = await StartServer<Startup>(w => w.EventId.Name == "Rec
tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
return websocket;
};
o.UseAcks = true;
o.UseStatefulReconnect = true;
});
connectionBuilder.Services.AddSingleton(protocol);
var connection = connectionBuilder.Build();
Expand Down Expand Up @@ -2617,7 +2617,7 @@ await using (var server = await StartServer<Startup>(w => w.EventId.Name == "Rec
tcs.SetResult();
return websocket;
};
o.UseAcks = true;
o.UseStatefulReconnect = true;
})
.WithAutomaticReconnect();
connectionBuilder.Services.AddSingleton(protocol);
Expand Down Expand Up @@ -2691,8 +2691,8 @@ await using (var server = await StartServer<Startup>())
tcs.SetResult();
return websocket;
};
o.UseAcks = true;
})
.WithStatefulReconnect()
.WithAutomaticReconnect();
connectionBuilder.Services.AddSingleton(protocol);
var connection = connectionBuilder.Build();
Expand Down Expand Up @@ -2756,7 +2756,7 @@ await using (var server = await StartServer<Startup>())
await ws.ConnectAsync(context.Uri, token);
return ws;
};
o.UseAcks = true;
o.UseStatefulReconnect = true;
});
connectionBuilder.Services.AddSingleton(protocol);
var connection = connectionBuilder.Build();
Expand Down Expand Up @@ -2799,12 +2799,10 @@ await using (var server = await StartServer<Startup>())
const string originalMessage = "SignalR";
var connectionBuilder = new HubConnectionBuilder()
.WithLoggerFactory(LoggerFactory)
.WithUrl(server.Url + "/default", HttpTransportType.WebSockets, o =>
{
o.UseAcks = true;
});
connectionBuilder.Services.Configure<HubConnectionOptions>(o => o.StatefulReconnectBufferSize = 500);
.WithStatefulReconnect()
.WithUrl(server.Url + "/default", HttpTransportType.WebSockets);
connectionBuilder.Services.AddSingleton(protocol);
connectionBuilder.Services.Configure<HubConnectionOptions>(o => o.StatefulReconnectBufferSize = 500);
var connection = connectionBuilder.Build();

try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public void Configure(IApplicationBuilder app)

app.UseEndpoints(endpoints =>
{
endpoints.MapHub<TestHub>("/default", o => o.AllowAcks = true);
endpoints.MapHub<TestHub>("/default", o => o.AllowStatefulReconnects = true);
endpoints.MapHub<DynamicTestHub>("/dynamic");
endpoints.MapHub<TestHubT>("/hubT");
endpoints.MapHub<HubWithAuthorization>("/authorizedhub");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void ShallowCopyHttpConnectionOptionsCopiesAllPublicProperties()
{ $"{nameof(HttpConnectionOptions.WebSocketFactory)}", webSocketFactory },
{ $"{nameof(HttpConnectionOptions.ApplicationMaxBufferSize)}", 1L * 1024 * 1024 },
{ $"{nameof(HttpConnectionOptions.TransportMaxBufferSize)}", 1L * 1024 * 1024 },
{ $"{nameof(HttpConnectionOptions.UseAcks)}", true },
{ $"{nameof(HttpConnectionOptions.UseStatefulReconnect)}", true },
};

var options = new HttpConnectionOptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,13 @@ private async Task SelectAndStartTransport(TransferFormat transferFormat, Cancel
if (negotiationResponse == null)
{
// Temporary until other transports work
_httpConnectionOptions.UseAcks = transportType == HttpTransportType.WebSockets ? _httpConnectionOptions.UseAcks : false;
_httpConnectionOptions.UseStatefulReconnect = transportType == HttpTransportType.WebSockets ? _httpConnectionOptions.UseStatefulReconnect : false;
negotiationResponse = await GetNegotiationResponseAsync(uri, cancellationToken).ConfigureAwait(false);
connectUrl = CreateConnectUrl(uri, negotiationResponse.ConnectionToken);
}

Log.StartingTransport(_logger, transportType, uri);
await StartTransport(connectUrl, transportType, transferFormat, cancellationToken, negotiationResponse.UseAcking).ConfigureAwait(false);
await StartTransport(connectUrl, transportType, transferFormat, cancellationToken, negotiationResponse.UseStatefulReconnect).ConfigureAwait(false);
break;
}
}
Expand Down Expand Up @@ -457,7 +457,7 @@ private async Task<NegotiationResponse> NegotiateAsync(Uri url, HttpClient httpC
uri = Utils.AppendQueryString(urlBuilder.Uri, $"negotiateVersion={_protocolVersionNumber}");
}

if (_httpConnectionOptions.UseAcks)
if (_httpConnectionOptions.UseStatefulReconnect)
{
uri = Utils.AppendQueryString(uri, "useAck=true");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal static HttpConnectionOptions ShallowCopyHttpConnectionOptions(HttpConne
DefaultTransferFormat = options.DefaultTransferFormat,
ApplicationMaxBufferSize = options.ApplicationMaxBufferSize,
TransportMaxBufferSize = options.TransportMaxBufferSize,
UseAcks = options.UseAcks,
UseStatefulReconnect = options.UseStatefulReconnect,
};

if (!OperatingSystem.IsBrowser())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,14 +276,13 @@ public CookieContainer Cookies
}

/// <summary>
/// Setting to enable acking bytes sent between client and server, this allows reconnecting that preserves messages sent while disconnected.
/// Setting to enable Stateful Reconnect between client and server, this allows reconnecting that preserves messages sent while disconnected.
/// Also preserves the <see cref="HttpConnection.ConnectionId"/> when the reconnect is successful.
/// </summary>
/// <remarks>
/// Only works with WebSockets transport currently.
/// API likely to change in future previews.
/// </remarks>
public bool UseAcks { get; set; }
public bool UseStatefulReconnect { get; set; }

private static void ThrowIfUnsupportedPlatform()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ internal sealed partial class WebSocketsTransport : ITransport, IReconnectFeatur
private readonly HttpConnectionOptions _httpConnectionOptions;
private readonly HttpClient? _httpClient;
private CancellationTokenSource _stopCts = default!;
private readonly bool _useAck;
private readonly bool _useStatefulReconnect;

private IDuplexPipe? _transport;
// Used for reconnect (when enabled) to determine if the close was ungraceful or not, reconnect only happens on ungraceful disconnect
Expand All @@ -53,9 +53,9 @@ internal sealed partial class WebSocketsTransport : ITransport, IReconnectFeatur
public Action NotifyOnReconnect { get => _notifyOnReconnect is not null ? _notifyOnReconnect : () => { }; set => _notifyOnReconnect = value; }

public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory, Func<Task<string?>> accessTokenProvider, HttpClient? httpClient,
bool useAck = false)
bool useStatefulReconnect = false)
{
_useAck = useAck;
_useStatefulReconnect = useStatefulReconnect;
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<WebSocketsTransport>();
_httpConnectionOptions = httpConnectionOptions ?? new HttpConnectionOptions();

Expand Down Expand Up @@ -368,7 +368,7 @@ private async Task ProcessSocketAsync(WebSocket socket, Uri url, bool ignoreFirs
}
}

if (_useAck && !_gracefulClose)
if (_useStatefulReconnect && !_gracefulClose)
{
UpdateConnectionPair();
await StartAsync(url, _webSocketMessageType == WebSocketMessageType.Binary ? TransferFormat.Binary : TransferFormat.Text, default).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#nullable enable
Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionOptions.UseAcks.get -> bool
Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionOptions.UseAcks.set -> void
Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionOptions.UseStatefulReconnect.get -> bool
Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionOptions.UseStatefulReconnect.set -> void
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public static void WriteResponse(NegotiationResponse response, IBufferWriter<byt
return;
}

if (response.UseAcking)
if (response.UseStatefulReconnect)
{
writer.WriteBoolean(AckPropertyNameBytes, true);
}
Expand Down Expand Up @@ -262,7 +262,7 @@ public static NegotiationResponse ParseResponse(ReadOnlySpan<byte> content)
AvailableTransports = availableTransports,
Error = error,
Version = version,
UseAcking = useAck,
UseStatefulReconnect = useAck,
};
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ public class NegotiationResponse
/// It should also set <see cref="IReconnectFeature"/> on the <see cref="BaseConnectionContext.Features"/> collection so other layers of the
/// application (like SignalR) can react.
/// </summary>
public bool UseAcking { get; set; }
public bool UseStatefulReconnect { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#nullable enable
Microsoft.AspNetCore.Http.Connections.NegotiationResponse.UseAcking.get -> bool
Microsoft.AspNetCore.Http.Connections.NegotiationResponse.UseAcking.set -> void
Microsoft.AspNetCore.Http.Connections.NegotiationResponse.UseStatefulReconnect.get -> bool
Microsoft.AspNetCore.Http.Connections.NegotiationResponse.UseStatefulReconnect.set -> void
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO.Pipelines;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Connections;

namespace Microsoft.AspNetCore.Http.Connections;

Expand Down Expand Up @@ -125,12 +126,12 @@ public TimeSpan TransportSendTimeout
public bool CloseOnAuthenticationExpiration { get; set; }

/// <summary>
/// Set to allow connections to ack messages, helps enable reconnects that keep connection state.
/// Set to allow connections to reconnect with the same <see cref="BaseConnectionContext.ConnectionId"/>.
/// </summary>
/// <remarks>
/// Keeps messages in memory until acked (up to a limit), and keeps connections around for a short time to allow stateful reconnects.
/// Client still has to negotiate this option.
/// </remarks>
public bool AllowAcks { get; set; }
public bool AllowStatefulReconnects { get; set; }

internal long TransportSendTimeoutTicks { get; private set; }
internal bool TransportSendTimeoutEnabled => _transportSendTimeout != Timeout.InfiniteTimeSpan;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ internal sealed partial class HttpConnectionContext : ConnectionContext,
private CancellationTokenSource? _sendCts;
private bool _activeSend;
private long _startedSendTime;
private readonly bool _useAcks;
private readonly bool _useStatefulReconnect;
private readonly object _sendingLock = new object();
internal CancellationToken SendingToken { get; private set; }

Expand Down Expand Up @@ -105,10 +105,10 @@ internal sealed partial class HttpConnectionContext : ConnectionContext,
_connectionCloseRequested = new CancellationTokenSource();
ConnectionClosedRequested = _connectionCloseRequested.Token;
AuthenticationExpiration = DateTimeOffset.MaxValue;
_useAcks = useAcks;
_useStatefulReconnect = useAcks;
}

public bool UseAcks => _useAcks;
public bool UseStatefulReconnect => _useStatefulReconnect;

public CancellationTokenSource? Cancellation { get; set; }

Expand Down Expand Up @@ -548,7 +548,7 @@ internal async Task<bool> CancelPreviousPoll(HttpContext context)
cts?.Cancel();

// TODO: remove transport check once other transports support acks
if (UseAcks && TransportType == HttpTransportType.WebSockets)
if (UseStatefulReconnect && TransportType == HttpTransportType.WebSockets)
{
// Break transport send loop in case it's still waiting on reading from the application
Application.Input.CancelPendingRead();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ private async Task ExecuteAsync(HttpContext context, ConnectionDelegate connecti
return;
}

if (connection.TransportType != HttpTransportType.WebSockets || connection.UseAcks)
if (connection.TransportType != HttpTransportType.WebSockets || connection.UseStatefulReconnect)
{
if (!await connection.CancelPreviousPoll(context))
{
Expand Down Expand Up @@ -336,7 +336,7 @@ private async Task ProcessNegotiate(HttpContext context, HttpConnectionDispatche
}

var useAck = false;
if (options.AllowAcks == true && context.Request.Query.TryGetValue("UseAck", out var useAckValue))
if (options.AllowStatefulReconnects == true && context.Request.Query.TryGetValue("UseAck", out var useAckValue))
{
var useAckStringValue = useAckValue.ToString();
bool.TryParse(useAckStringValue, out useAck);
Expand Down Expand Up @@ -389,7 +389,7 @@ private async Task ProcessNegotiate(HttpContext context, HttpConnectionDispatche
response.ConnectionId = connectionId;
response.ConnectionToken = connectionToken;
response.AvailableTransports = new List<AvailableTransport>();
response.UseAcking = useAck;
response.UseStatefulReconnect = useAck;

if ((options.Transports & HttpTransportType.WebSockets) != 0 && ServerHasWebSockets(context.Features))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#nullable enable
Microsoft.AspNetCore.Http.Connections.HttpConnectionDispatcherOptions.AllowAcks.get -> bool
Microsoft.AspNetCore.Http.Connections.HttpConnectionDispatcherOptions.AllowAcks.set -> void
Microsoft.AspNetCore.Http.Connections.HttpConnectionDispatcherOptions.AllowStatefulReconnects.get -> bool
Microsoft.AspNetCore.Http.Connections.HttpConnectionDispatcherOptions.AllowStatefulReconnects.set -> void
Original file line number Diff line number Diff line change
Expand Up @@ -2279,7 +2279,7 @@ public async Task NegotiateDoesNotReturnUseAckWhenNotEnabledOnServer()
context.Request.Method = "POST";
context.Response.Body = ms;
context.Request.QueryString = new QueryString("?negotiateVersion=1&UseAck=true");
await dispatcher.ExecuteNegotiateAsync(context, new HttpConnectionDispatcherOptions { AllowAcks = false });
await dispatcher.ExecuteNegotiateAsync(context, new HttpConnectionDispatcherOptions { AllowStatefulReconnects = false });

var negotiateResponse = JsonConvert.DeserializeObject<JObject>(Encoding.UTF8.GetString(ms.ToArray()));
Assert.False(negotiateResponse.TryGetValue("useAck", out _));
Expand All @@ -2306,7 +2306,7 @@ public async Task NegotiateDoesNotReturnUseAckWhenEnabledOnServerButNotRequested
context.Request.Method = "POST";
context.Response.Body = ms;
context.Request.QueryString = new QueryString("?negotiateVersion=1");
await dispatcher.ExecuteNegotiateAsync(context, new HttpConnectionDispatcherOptions { AllowAcks = true });
await dispatcher.ExecuteNegotiateAsync(context, new HttpConnectionDispatcherOptions { AllowStatefulReconnects = true });

var negotiateResponse = JsonConvert.DeserializeObject<JObject>(Encoding.UTF8.GetString(ms.ToArray()));
Assert.False(negotiateResponse.TryGetValue("useAck", out _));
Expand All @@ -2333,7 +2333,7 @@ public async Task NegotiateReturnsUseAckWhenEnabledOnServerAndRequestedByClient(
context.Request.Method = "POST";
context.Response.Body = ms;
context.Request.QueryString = new QueryString("?negotiateVersion=1&UseAck=true");
await dispatcher.ExecuteNegotiateAsync(context, new HttpConnectionDispatcherOptions { AllowAcks = true });
await dispatcher.ExecuteNegotiateAsync(context, new HttpConnectionDispatcherOptions { AllowStatefulReconnects = true });

var negotiateResponse = JsonConvert.DeserializeObject<JObject>(Encoding.UTF8.GetString(ms.ToArray()));
Assert.True((bool)negotiateResponse["useAck"]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public void GlobalSetup()
new HubContext<TestHub>(hubLifetimeManager),
enableDetailedErrors: false,
disableImplicitFromServiceParameters: true,
useAcks: false,
new Logger<DefaultHubDispatcher<TestHub>>(NullLoggerFactory.Instance),
hubFilters: null,
hubLifetimeManager);
Expand Down
Loading

0 comments on commit b70b7ef

Please sign in to comment.