Skip to content

Commit 5de266e

Browse files
committed
experimental
1 parent 40b6542 commit 5de266e

File tree

9 files changed

+81
-3
lines changed

9 files changed

+81
-3
lines changed

src/Servers/Connections.Abstractions/src/Features/IReconnectFeature.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,29 @@
55
using System.Collections.Generic;
66
using System.IO.Pipelines;
77
using System.Linq;
8+
#if NET8_0_OR_GREATER
9+
using System.Runtime.Versioning;
10+
#endif
811
using System.Text;
912
using System.Threading.Tasks;
1013

1114
namespace Microsoft.AspNetCore.Connections.Abstractions;
1215

1316
/// <summary>
14-
///
17+
/// Provides access to connection reconnect operations.
1518
/// </summary>
19+
#if NET8_0_OR_GREATER
20+
[RequiresPreviewFeatures("IReconnectFeature is a preview interface")]
21+
#endif
1622
public interface IReconnectFeature
1723
{
1824
/// <summary>
19-
///
25+
/// Called when a connection reconnects. The new <see cref="PipeWriter"/> that application code should write to is passed in.
2026
/// </summary>
2127
public Action<PipeWriter> NotifyOnReconnect { get; set; }
2228

2329
/// <summary>
24-
///
30+
/// Allows disabling the reconnect feature so a reconnecting connection will not be allowed anymore.
2531
/// </summary>
2632
void DisableReconnect();
2733
}

src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,10 +580,12 @@ private async Task StopAsyncCore(bool disposing)
580580
TaskScheduler.Default);
581581
}
582582

583+
#pragma warning disable CA2252 // This API requires opting into preview features
583584
if (connectionState.Connection.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
584585
{
585586
feature.DisableReconnect();
586587
}
588+
#pragma warning restore CA2252 // This API requires opting into preview features
587589
}
588590
else
589591
{
@@ -1094,10 +1096,12 @@ private async Task SendWithLock(ConnectionState expectedConnectionState, HubMess
10941096
Log.ReceivedCloseWithError(_logger, close.Error);
10951097
}
10961098

1099+
#pragma warning disable CA2252 // This API requires opting into preview features
10971100
if (connectionState.Connection.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
10981101
{
10991102
feature.DisableReconnect();
11001103
}
1104+
#pragma warning restore CA2252 // This API requires opting into preview features
11011105

11021106
return close;
11031107
case PingMessage _:
@@ -1911,6 +1915,7 @@ public ConnectionState(ConnectionContext connection, HubConnection hubConnection
19111915
_logger = _hubConnection._logger;
19121916
_hasInherentKeepAlive = connection.Features.Get<IConnectionInherentKeepAliveFeature>()?.HasInherentKeepAlive ?? false;
19131917

1918+
#pragma warning disable CA2252 // This API requires opting into preview features
19141919
if (Connection.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
19151920
{
19161921
_messageBuffer = new MessageBuffer(connection, hubConnection._protocol,
@@ -1919,6 +1924,7 @@ public ConnectionState(ConnectionContext connection, HubConnection hubConnection
19191924

19201925
feature.NotifyOnReconnect = _messageBuffer.Resend;
19211926
}
1927+
#pragma warning restore CA2252 // This API requires opting into preview features
19221928
}
19231929

19241930
public string GetNextId() => (++_nextInvocationId).ToString(CultureInfo.InvariantCulture);

src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,9 @@ public async Task DisableReconnectCalledWhenCloseMessageReceived()
885885
var builder = new HubConnectionBuilder().WithUrl("http://example.com");
886886
var innerConnection = new TestConnection();
887887
var reconnectFeature = new TestReconnectFeature();
888+
#pragma warning disable CA2252 // This API requires opting into preview features
888889
innerConnection.Features.Set<IReconnectFeature>(reconnectFeature);
890+
#pragma warning restore CA2252 // This API requires opting into preview features
889891

890892
var delegateConnectionFactory = new DelegateConnectionFactory(
891893
endPoint => innerConnection.StartAsync());
@@ -915,7 +917,9 @@ public async Task DisableReconnectCalledWhenSendingCloseMessage()
915917
var builder = new HubConnectionBuilder().WithUrl("http://example.com");
916918
var innerConnection = new TestConnection();
917919
var reconnectFeature = new TestReconnectFeature();
920+
#pragma warning disable CA2252 // This API requires opting into preview features
918921
innerConnection.Features.Set<IReconnectFeature>(reconnectFeature);
922+
#pragma warning restore CA2252 // This API requires opting into preview features
919923

920924
var delegateConnectionFactory = new DelegateConnectionFactory(
921925
endPoint => innerConnection.StartAsync());
@@ -1024,15 +1028,21 @@ public ReadOnlyMemory<byte> GetMessageBytes(HubMessage message)
10241028
}
10251029
}
10261030

1031+
#pragma warning disable CA2252 // This API requires opting into preview features
10271032
private sealed class TestReconnectFeature : IReconnectFeature
1033+
#pragma warning restore CA2252 // This API requires opting into preview features
10281034
{
10291035
private TaskCompletionSource _disableReconnect = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
10301036

10311037
public Task DisableReconnectCalled => _disableReconnect.Task;
10321038

1039+
#pragma warning disable CA2252 // This API requires opting into preview features
10331040
public Action<PipeWriter> NotifyOnReconnect { get; set; }
1041+
#pragma warning restore CA2252 // This API requires opting into preview features
10341042

1043+
#pragma warning disable CA2252 // This API requires opting into preview features
10351044
public void DisableReconnect()
1045+
#pragma warning restore CA2252 // This API requires opting into preview features
10361046
{
10371047
_disableReconnect.TrySetResult();
10381048
}

src/SignalR/clients/csharp/Http.Connections.Client/src/HttpConnection.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,9 @@ private async Task StartTransport(Uri connectUrl, HttpTransportType transportTyp
533533

534534
if (useAck && _transport is IReconnectFeature reconnectFeature)
535535
{
536+
#pragma warning disable CA2252 // This API requires opting into preview features
536537
Features.Set(reconnectFeature);
538+
#pragma warning restore CA2252 // This API requires opting into preview features
537539
}
538540

539541
Log.TransportStarted(_logger, transportType);

src/SignalR/clients/csharp/Http.Connections.Client/src/Internal/WebSocketsTransport.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525

2626
namespace Microsoft.AspNetCore.Http.Connections.Client.Internal;
2727

28+
#pragma warning disable CA2252 // This API requires opting into preview features
2829
internal sealed partial class WebSocketsTransport : ITransport, IReconnectFeature
30+
#pragma warning restore CA2252 // This API requires opting into preview features
2931
{
3032
private WebSocket? _webSocket;
3133
private IDuplexPipe? _application;
@@ -50,7 +52,9 @@ internal sealed partial class WebSocketsTransport : ITransport, IReconnectFeatur
5052

5153
public PipeWriter Output => _transport!.Output;
5254

55+
#pragma warning disable CA2252 // This API requires opting into preview features
5356
public Action<PipeWriter> NotifyOnReconnect { get => _notifyOnReconnect is not null ? _notifyOnReconnect : (_) => { }; set => _notifyOnReconnect = value; }
57+
#pragma warning restore CA2252 // This API requires opting into preview features
5458

5559
public WebSocketsTransport(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory, Func<Task<string?>> accessTokenProvider, HttpClient? httpClient,
5660
bool useAck = false)
@@ -652,7 +656,9 @@ private void UpdateConnectionPair()
652656
_notifyOnReconnect.Invoke(input.Writer);
653657
}
654658

659+
#pragma warning disable CA2252 // This API requires opting into preview features
655660
public void DisableReconnect()
661+
#pragma warning restore CA2252 // This API requires opting into preview features
656662
{
657663
_useAck = false;
658664
}

src/SignalR/common/Http.Connections/src/Internal/HttpConnectionContext.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ internal sealed partial class HttpConnectionContext : ConnectionContext,
3131
IConnectionInherentKeepAliveFeature,
3232
IConnectionLifetimeFeature,
3333
IConnectionLifetimeNotificationFeature,
34+
#pragma warning disable CA2252 // This API requires opting into preview features
3435
IReconnectFeature
36+
#pragma warning restore CA2252 // This API requires opting into preview features
3537
{
3638
private readonly HttpConnectionDispatcherOptions _options;
3739

@@ -96,7 +98,9 @@ public HttpConnectionContext(string connectionId, string connectionToken, ILogge
9698

9799
if (useAcks)
98100
{
101+
#pragma warning disable CA2252 // This API requires opting into preview features
99102
Features.Set<IReconnectFeature>(this);
103+
#pragma warning restore CA2252 // This API requires opting into preview features
100104
}
101105

102106
_connectionClosedTokenSource = new CancellationTokenSource();
@@ -204,7 +208,9 @@ public IDuplexPipe Application
204208

205209
public CancellationToken ConnectionClosedRequested { get; set; }
206210

211+
#pragma warning disable CA2252 // This API requires opting into preview features
207212
public Action<PipeWriter> NotifyOnReconnect { get; set; } = (_) => { };
213+
#pragma warning restore CA2252 // This API requires opting into preview features
208214

209215
public override void Abort()
210216
{
@@ -666,10 +672,14 @@ private void UpdateConnectionPair()
666672
Application = applicationToTransport;
667673
Transport = transportToApplication;
668674

675+
#pragma warning disable CA2252 // This API requires opting into preview features
669676
Features.GetRequiredFeature<IReconnectFeature>().NotifyOnReconnect.Invoke(input.Writer);
677+
#pragma warning restore CA2252 // This API requires opting into preview features
670678
}
671679

680+
#pragma warning disable CA2252 // This API requires opting into preview features
672681
public void DisableReconnect()
682+
#pragma warning restore CA2252 // This API requires opting into preview features
673683
{
674684
_useAcks = false;
675685
}

src/SignalR/common/Http.Connections/test/HttpConnectionDispatcherTests.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,7 +2285,9 @@ public async Task NegotiateDoesNotReturnUseAckWhenNotEnabledOnServer()
22852285
Assert.False(negotiateResponse.TryGetValue("useAck", out _));
22862286

22872287
Assert.True(manager.TryGetConnection(negotiateResponse["connectionToken"].ToString(), out var connection));
2288+
#pragma warning disable CA2252 // This API requires opting into preview features
22882289
Assert.Null(connection.Features.Get<IReconnectFeature>());
2290+
#pragma warning restore CA2252 // This API requires opting into preview features
22892291
}
22902292
}
22912293

@@ -2312,7 +2314,9 @@ public async Task NegotiateDoesNotReturnUseAckWhenEnabledOnServerButNotRequested
23122314
Assert.False(negotiateResponse.TryGetValue("useAck", out _));
23132315

23142316
Assert.True(manager.TryGetConnection(negotiateResponse["connectionToken"].ToString(), out var connection));
2317+
#pragma warning disable CA2252 // This API requires opting into preview features
23152318
Assert.Null(connection.Features.Get<IReconnectFeature>());
2319+
#pragma warning restore CA2252 // This API requires opting into preview features
23162320
}
23172321
}
23182322

@@ -2339,7 +2343,9 @@ public async Task NegotiateReturnsUseAckWhenEnabledOnServerAndRequestedByClient(
23392343
Assert.True((bool)negotiateResponse["useAck"]);
23402344

23412345
Assert.True(manager.TryGetConnection(negotiateResponse["connectionToken"].ToString(), out var connection));
2346+
#pragma warning disable CA2252 // This API requires opting into preview features
23422347
Assert.NotNull(connection.Features.Get<IReconnectFeature>());
2348+
#pragma warning restore CA2252 // This API requires opting into preview features
23432349
}
23442350
}
23452351

@@ -2367,7 +2373,9 @@ public async Task ReconnectStopsPreviousConnection()
23672373

23682374
var initialWebSocketTask = dispatcher.ExecuteAsync(context, options, app);
23692375

2376+
#pragma warning disable CA2252 // This API requires opting into preview features
23702377
var reconnectFeature = connection.Features.Get<IReconnectFeature>();
2378+
#pragma warning restore CA2252 // This API requires opting into preview features
23712379
Assert.NotNull(reconnectFeature);
23722380

23732381
var firstMsg = new byte[] { 1, 4, 8, 9 };
@@ -2381,12 +2389,16 @@ public async Task ReconnectStopsPreviousConnection()
23812389
Assert.Equal(firstMsg, webSocketMessage.Buffer);
23822390

23832391
var called = false;
2392+
#pragma warning disable CA2252 // This API requires opting into preview features
23842393
var reconnectCallback = reconnectFeature.NotifyOnReconnect;
2394+
#pragma warning restore CA2252 // This API requires opting into preview features
2395+
#pragma warning disable CA2252 // This API requires opting into preview features
23852396
reconnectFeature.NotifyOnReconnect = (writer) =>
23862397
{
23872398
called = true;
23882399
reconnectCallback(writer);
23892400
};
2401+
#pragma warning restore CA2252 // This API requires opting into preview features
23902402

23912403
// New websocket connection with previous connection token
23922404
context = MakeRequest("/foo", connection, services);
@@ -2439,7 +2451,9 @@ public async Task DisableReconnectDisallowsReplacementConnection()
24392451

24402452
var initialWebSocketTask = dispatcher.ExecuteAsync(context, options, app);
24412453

2454+
#pragma warning disable CA2252 // This API requires opting into preview features
24422455
var reconnectFeature = connection.Features.Get<IReconnectFeature>();
2456+
#pragma warning restore CA2252 // This API requires opting into preview features
24432457
Assert.NotNull(reconnectFeature);
24442458

24452459
var firstMsg = new byte[] { 1, 4, 8, 9 };
@@ -2453,15 +2467,21 @@ public async Task DisableReconnectDisallowsReplacementConnection()
24532467
Assert.Equal(firstMsg, webSocketMessage.Buffer);
24542468

24552469
var called = false;
2470+
#pragma warning disable CA2252 // This API requires opting into preview features
24562471
var reconnectCallback = reconnectFeature.NotifyOnReconnect;
2472+
#pragma warning restore CA2252 // This API requires opting into preview features
2473+
#pragma warning disable CA2252 // This API requires opting into preview features
24572474
reconnectFeature.NotifyOnReconnect = (writer) =>
24582475
{
24592476
called = true;
24602477
reconnectCallback(writer);
24612478
};
2479+
#pragma warning restore CA2252 // This API requires opting into preview features
24622480

24632481
// Disable will not allow new connection to override existing
2482+
#pragma warning disable CA2252 // This API requires opting into preview features
24642483
reconnectFeature.DisableReconnect();
2484+
#pragma warning restore CA2252 // This API requires opting into preview features
24652485

24662486
// New websocket connection with previous connection token
24672487
context = MakeRequest("/foo", connection, services);
@@ -3939,9 +3959,13 @@ public override async Task OnConnectedAsync(ConnectionContext connection)
39393959
_pause.TrySetResult(false);
39403960
});
39413961

3962+
#pragma warning disable CA2252 // This API requires opting into preview features
39423963
var reconnectFeature = connection.Features.Get<IReconnectFeature>();
3964+
#pragma warning restore CA2252 // This API requires opting into preview features
39433965
Assert.NotNull(reconnectFeature);
3966+
#pragma warning disable CA2252 // This API requires opting into preview features
39443967
reconnectFeature.NotifyOnReconnect = NotifyReconnect;
3968+
#pragma warning restore CA2252 // This API requires opting into preview features
39453969

39463970
do
39473971
{

src/SignalR/server/Core/src/HubConnectionContext.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,10 +454,12 @@ private async Task WriteHandshakeResponseAsync(HandshakeResponseMessage message)
454454
/// </summary>
455455
public virtual void Abort()
456456
{
457+
#pragma warning disable CA2252 // This API requires opting into preview features
457458
if (_useAcks && _connectionContext.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
458459
{
459460
feature.DisableReconnect();
460461
}
462+
#pragma warning restore CA2252 // This API requires opting into preview features
461463

462464
_allowReconnect = false;
463465
AbortAllowReconnect();
@@ -581,12 +583,14 @@ await WriteHandshakeResponseAsync(new HandshakeResponseMessage(
581583

582584
await WriteHandshakeResponseAsync(HandshakeResponseMessage.Empty);
583585

586+
#pragma warning disable CA2252 // This API requires opting into preview features
584587
if (_connectionContext.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
585588
{
586589
_useAcks = true;
587590
_messageBuffer = new MessageBuffer(_connectionContext, Protocol, _statefulReconnectBufferSize);
588591
feature.NotifyOnReconnect = _messageBuffer.Resend;
589592
}
593+
#pragma warning restore CA2252 // This API requires opting into preview features
590594
return true;
591595
}
592596
else if (overLength)

src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5222,7 +5222,9 @@ public async Task IReconnectNotifyTriggersSequenceMessage()
52225222

52235223
using var client = new TestClient();
52245224
var reconnectFeature = new TestReconnectFeature();
5225+
#pragma warning disable CA2252 // This API requires opting into preview features
52255226
client.Connection.Features.Set<IReconnectFeature>(reconnectFeature);
5227+
#pragma warning restore CA2252 // This API requires opting into preview features
52265228

52275229
var connectionHandlerTask = await client.ConnectAsync(connectionHandler);
52285230
UpdateConnectionPair(client.Connection);
@@ -5284,7 +5286,9 @@ public async Task GracefulCloseDisablesReconnect()
52845286
using var client = new TestClient();
52855287

52865288
var reconnectFeature = new TestReconnectFeature();
5289+
#pragma warning disable CA2252 // This API requires opting into preview features
52875290
client.Connection.Features.Set<IReconnectFeature>(reconnectFeature);
5291+
#pragma warning restore CA2252 // This API requires opting into preview features
52885292

52895293
var connectionHandlerTask = await client.ConnectAsync(connectionHandler);
52905294

@@ -5301,15 +5305,21 @@ public async Task GracefulCloseDisablesReconnect()
53015305
}
53025306
}
53035307

5308+
#pragma warning disable CA2252 // This API requires opting into preview features
53045309
private class TestReconnectFeature : IReconnectFeature
5310+
#pragma warning restore CA2252 // This API requires opting into preview features
53055311
{
53065312
private TaskCompletionSource _reconnectDisabled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
53075313

53085314
public Task ReconnectDisabled => _reconnectDisabled.Task;
53095315

5316+
#pragma warning disable CA2252 // This API requires opting into preview features
53105317
public Action<PipeWriter> NotifyOnReconnect { get; set; } = (_) => { };
5318+
#pragma warning restore CA2252 // This API requires opting into preview features
53115319

5320+
#pragma warning disable CA2252 // This API requires opting into preview features
53125321
public void DisableReconnect()
5322+
#pragma warning restore CA2252 // This API requires opting into preview features
53135323
{
53145324
_reconnectDisabled.TrySetResult();
53155325
}

0 commit comments

Comments
 (0)