Skip to content

Commit 8f50777

Browse files
committed
experimental
1 parent 9783b1e commit 8f50777

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
@@ -577,10 +577,12 @@ private async Task StopAsyncCore(bool disposing)
577577
TaskScheduler.Default);
578578
}
579579

580+
#pragma warning disable CA2252 // This API requires opting into preview features
580581
if (connectionState.Connection.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
581582
{
582583
feature.DisableReconnect();
583584
}
585+
#pragma warning restore CA2252 // This API requires opting into preview features
584586
}
585587
else
586588
{
@@ -1091,10 +1093,12 @@ private async Task SendWithLock(ConnectionState expectedConnectionState, HubMess
10911093
Log.ReceivedCloseWithError(_logger, close.Error);
10921094
}
10931095

1096+
#pragma warning disable CA2252 // This API requires opting into preview features
10941097
if (connectionState.Connection.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
10951098
{
10961099
feature.DisableReconnect();
10971100
}
1101+
#pragma warning restore CA2252 // This API requires opting into preview features
10981102

10991103
return close;
11001104
case PingMessage _:
@@ -1908,12 +1912,14 @@ public ConnectionState(ConnectionContext connection, HubConnection hubConnection
19081912
_logger = _hubConnection._logger;
19091913
_hasInherentKeepAlive = connection.Features.Get<IConnectionInherentKeepAliveFeature>()?.HasInherentKeepAlive ?? false;
19101914

1915+
#pragma warning disable CA2252 // This API requires opting into preview features
19111916
if (Connection.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
19121917
{
19131918
_messageBuffer = new MessageBuffer(connection, hubConnection._protocol);
19141919

19151920
feature.NotifyOnReconnect = _messageBuffer.Resend;
19161921
}
1922+
#pragma warning restore CA2252 // This API requires opting into preview features
19171923
}
19181924

19191925
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
@@ -2284,7 +2284,9 @@ public async Task NegotiateDoesNotReturnUseAckWhenNotEnabledOnServer()
22842284
Assert.False(negotiateResponse.TryGetValue("useAck", out _));
22852285

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

@@ -2311,7 +2313,9 @@ public async Task NegotiateDoesNotReturnUseAckWhenEnabledOnServerButNotRequested
23112313
Assert.False(negotiateResponse.TryGetValue("useAck", out _));
23122314

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

@@ -2338,7 +2342,9 @@ public async Task NegotiateReturnsUseAckWhenEnabledOnServerAndRequestedByClient(
23382342
Assert.True((bool)negotiateResponse["useAck"]);
23392343

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

@@ -2366,7 +2372,9 @@ public async Task ReconnectStopsPreviousConnection()
23662372

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

2375+
#pragma warning disable CA2252 // This API requires opting into preview features
23692376
var reconnectFeature = connection.Features.Get<IReconnectFeature>();
2377+
#pragma warning restore CA2252 // This API requires opting into preview features
23702378
Assert.NotNull(reconnectFeature);
23712379

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

23822390
var called = false;
2391+
#pragma warning disable CA2252 // This API requires opting into preview features
23832392
var reconnectCallback = reconnectFeature.NotifyOnReconnect;
2393+
#pragma warning restore CA2252 // This API requires opting into preview features
2394+
#pragma warning disable CA2252 // This API requires opting into preview features
23842395
reconnectFeature.NotifyOnReconnect = (writer) =>
23852396
{
23862397
called = true;
23872398
reconnectCallback(writer);
23882399
};
2400+
#pragma warning restore CA2252 // This API requires opting into preview features
23892401

23902402
// New websocket connection with previous connection token
23912403
context = MakeRequest("/foo", connection, services);
@@ -2438,7 +2450,9 @@ public async Task DisableReconnectDisallowsReplacementConnection()
24382450

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

2453+
#pragma warning disable CA2252 // This API requires opting into preview features
24412454
var reconnectFeature = connection.Features.Get<IReconnectFeature>();
2455+
#pragma warning restore CA2252 // This API requires opting into preview features
24422456
Assert.NotNull(reconnectFeature);
24432457

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

24542468
var called = false;
2469+
#pragma warning disable CA2252 // This API requires opting into preview features
24552470
var reconnectCallback = reconnectFeature.NotifyOnReconnect;
2471+
#pragma warning restore CA2252 // This API requires opting into preview features
2472+
#pragma warning disable CA2252 // This API requires opting into preview features
24562473
reconnectFeature.NotifyOnReconnect = (writer) =>
24572474
{
24582475
called = true;
24592476
reconnectCallback(writer);
24602477
};
2478+
#pragma warning restore CA2252 // This API requires opting into preview features
24612479

24622480
// Disable will not allow new connection to override existing
2481+
#pragma warning disable CA2252 // This API requires opting into preview features
24632482
reconnectFeature.DisableReconnect();
2483+
#pragma warning restore CA2252 // This API requires opting into preview features
24642484

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

3961+
#pragma warning disable CA2252 // This API requires opting into preview features
39413962
var reconnectFeature = connection.Features.Get<IReconnectFeature>();
3963+
#pragma warning restore CA2252 // This API requires opting into preview features
39423964
Assert.NotNull(reconnectFeature);
3965+
#pragma warning disable CA2252 // This API requires opting into preview features
39433966
reconnectFeature.NotifyOnReconnect = NotifyReconnect;
3967+
#pragma warning restore CA2252 // This API requires opting into preview features
39443968

39453969
do
39463970
{

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

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

460462
_allowReconnect = false;
461463
AbortAllowReconnect();
@@ -579,12 +581,14 @@ await WriteHandshakeResponseAsync(new HandshakeResponseMessage(
579581

580582
await WriteHandshakeResponseAsync(HandshakeResponseMessage.Empty);
581583

584+
#pragma warning disable CA2252 // This API requires opting into preview features
582585
if (_connectionContext.Features.Get<IReconnectFeature>() is IReconnectFeature feature)
583586
{
584587
_useAcks = true;
585588
_messageBuffer = new MessageBuffer(_connectionContext, Protocol);
586589
feature.NotifyOnReconnect = _messageBuffer.Resend;
587590
}
591+
#pragma warning restore CA2252 // This API requires opting into preview features
588592
return true;
589593
}
590594
else if (overLength)

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

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

50515051
using var client = new TestClient();
50525052
var reconnectFeature = new TestReconnectFeature();
5053+
#pragma warning disable CA2252 // This API requires opting into preview features
50535054
client.Connection.Features.Set<IReconnectFeature>(reconnectFeature);
5055+
#pragma warning restore CA2252 // This API requires opting into preview features
50545056

50555057
var connectionHandlerTask = await client.ConnectAsync(connectionHandler);
50565058
UpdateConnectionPair(client.Connection);
@@ -5112,7 +5114,9 @@ public async Task GracefulCloseDisablesReconnect()
51125114
using var client = new TestClient();
51135115

51145116
var reconnectFeature = new TestReconnectFeature();
5117+
#pragma warning disable CA2252 // This API requires opting into preview features
51155118
client.Connection.Features.Set<IReconnectFeature>(reconnectFeature);
5119+
#pragma warning restore CA2252 // This API requires opting into preview features
51165120

51175121
var connectionHandlerTask = await client.ConnectAsync(connectionHandler);
51185122

@@ -5129,15 +5133,21 @@ public async Task GracefulCloseDisablesReconnect()
51295133
}
51305134
}
51315135

5136+
#pragma warning disable CA2252 // This API requires opting into preview features
51325137
private class TestReconnectFeature : IReconnectFeature
5138+
#pragma warning restore CA2252 // This API requires opting into preview features
51335139
{
51345140
private TaskCompletionSource _reconnectDisabled = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
51355141

51365142
public Task ReconnectDisabled => _reconnectDisabled.Task;
51375143

5144+
#pragma warning disable CA2252 // This API requires opting into preview features
51385145
public Action<PipeWriter> NotifyOnReconnect { get; set; } = (_) => { };
5146+
#pragma warning restore CA2252 // This API requires opting into preview features
51395147

5148+
#pragma warning disable CA2252 // This API requires opting into preview features
51405149
public void DisableReconnect()
5150+
#pragma warning restore CA2252 // This API requires opting into preview features
51415151
{
51425152
_reconnectDisabled.TrySetResult();
51435153
}

0 commit comments

Comments
 (0)