Skip to content

Commit fc8f7a6

Browse files
Use new System.Net.ServerSentEvents package in SignalR (#56206)
1 parent f6d12df commit fc8f7a6

10 files changed

+107
-493
lines changed

eng/Dependencies.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ and are generated based on the last package release.
8585
<LatestPackageReference Include="System.Net.Http" />
8686
<LatestPackageReference Include="System.Net.Http.Json" />
8787
<LatestPackageReference Include="System.Net.Sockets" />
88+
<LatestPackageReference Include="System.Net.ServerSentEvents" />
8889
<LatestPackageReference Include="System.Private.Uri" />
8990
<LatestPackageReference Include="System.Reflection.Metadata" />
9091
<LatestPackageReference Include="System.Runtime.InteropServices.RuntimeInformation" />

eng/Version.Details.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@
218218
<Uri>https://github.com/dotnet/runtime</Uri>
219219
<Sha>8fac5af2b11dc98fa0504f6fd06df790164ec958</Sha>
220220
</Dependency>
221+
<Dependency Name="System.Net.ServerSentEvents" Version="9.0.0-preview.6.24307.2">
222+
<Uri>https://github.com/dotnet/runtime</Uri>
223+
<Sha>8fac5af2b11dc98fa0504f6fd06df790164ec958</Sha>
224+
</Dependency>
221225
<Dependency Name="System.Reflection.Metadata" Version="9.0.0-preview.6.24307.2">
222226
<Uri>https://github.com/dotnet/runtime</Uri>
223227
<Sha>8fac5af2b11dc98fa0504f6fd06df790164ec958</Sha>

eng/Versions.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
<SystemIOPipelinesVersion>9.0.0-preview.6.24307.2</SystemIOPipelinesVersion>
117117
<SystemNetHttpJsonVersion>9.0.0-preview.6.24307.2</SystemNetHttpJsonVersion>
118118
<SystemNetHttpWinHttpHandlerVersion>9.0.0-preview.6.24307.2</SystemNetHttpWinHttpHandlerVersion>
119+
<SystemNetServerSentEventsVersion>9.0.0-preview.6.24307.2</SystemNetServerSentEventsVersion>
119120
<SystemReflectionMetadataVersion>9.0.0-preview.6.24307.2</SystemReflectionMetadataVersion>
120121
<SystemResourcesExtensionsVersion>9.0.0-preview.6.24307.2</SystemResourcesExtensionsVersion>
121122
<SystemSecurityCryptographyPkcsVersion>9.0.0-preview.6.24307.2</SystemSecurityCryptographyPkcsVersion>

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

Lines changed: 0 additions & 215 deletions
This file was deleted.

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

Lines changed: 82 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
5-
using System.IO;
4+
using System.Diagnostics;
65
using System.IO.Pipelines;
6+
using System.Net;
77
using System.Net.Http;
88
using System.Net.Http.Headers;
99
using System.Text;
10-
using System.Threading;
11-
using System.Threading.Tasks;
1210
using Microsoft.AspNetCore.Connections;
1311
using Microsoft.AspNetCore.Http.Connections.Client.Internal;
1412
using Microsoft.AspNetCore.Internal;
15-
using Microsoft.AspNetCore.SignalR.Tests;
1613
using Microsoft.AspNetCore.InternalTesting;
14+
using Microsoft.AspNetCore.SignalR.Tests;
1715
using Microsoft.Extensions.Logging.Testing;
1816
using Moq;
1917
using Moq.Protected;
20-
using Xunit;
21-
using System.Net;
2218

2319
namespace Microsoft.AspNetCore.SignalR.Client.Tests;
2420

@@ -121,7 +117,7 @@ await sseTransport.StartAsync(
121117
}
122118

123119
[Fact]
124-
public async Task SSETransportStopsWithErrorIfServerSendsIncompleteResults()
120+
public async Task SSETransportStopIfServerSendsIncompleteResults()
125121
{
126122
var mockHttpHandler = new Mock<HttpMessageHandler>();
127123
var calls = 0;
@@ -156,11 +152,9 @@ public async Task SSETransportStopsWithErrorIfServerSendsIncompleteResults()
156152
await sseTransport.StartAsync(
157153
new Uri("http://fakeuri.org"), TransferFormat.Text).DefaultTimeout();
158154

159-
var exception = await Assert.ThrowsAsync<FormatException>(() => sseTransport.Input.ReadAllAsync());
155+
await sseTransport.Input.ReadAllAsync().DefaultTimeout();
160156

161157
await sseTransport.Running.DefaultTimeout();
162-
163-
Assert.Equal("Incomplete message.", exception.Message);
164158
}
165159
}
166160

@@ -444,4 +438,81 @@ public async Task StartAsyncSetsCorrectAcceptHeaderForSSE()
444438
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
445439
}
446440
}
441+
442+
[Theory]
443+
[InlineData(new[] { "\r\n" }, "")]
444+
[InlineData(new[] { "\r\n:\r\n" }, "")]
445+
[InlineData(new[] { "\r\n:comment\r\n" }, "")]
446+
[InlineData(new[] { "data: \r\r\n\n" }, "")]
447+
[InlineData(new[] { ":comment\r\ndata: \r\r\n\r\n" }, "")]
448+
[InlineData(new[] { "data: A\rB\r\n\r\n" }, "A")]
449+
[InlineData(new[] { "data: Hello, World\r\n\r\n" }, "Hello, World")]
450+
[InlineData(new[] { "data: Hello, World\r\n\r\ndata: " }, "Hello, World")]
451+
[InlineData(new[] { "data: Hello, World\r\n\r\n:comment\r\ndata: " }, "Hello, World")]
452+
[InlineData(new[] { "data: Hello, World\r\n\r\n:comment" }, "Hello, World")]
453+
[InlineData(new[] { "data: Hello, World\r\n\r\n:comment\r\n" }, "Hello, World")]
454+
[InlineData(new[] { "data: Hello, World\r\n:comment\r\n\r\n" }, "Hello, World")]
455+
[InlineData(new[] { "data: SGVsbG8sIFdvcmxk\r\n\r\n" }, "SGVsbG8sIFdvcmxk")]
456+
[InlineData(new[] { "d", "ata: Hello, World\r\n\r\n" }, "Hello, World")]
457+
[InlineData(new[] { "da", "ta: Hello, World\r\n\r\n" }, "Hello, World")]
458+
[InlineData(new[] { "dat", "a: Hello, World\r\n\r\n" }, "Hello, World")]
459+
[InlineData(new[] { "data", ": Hello, World\r\n\r\n" }, "Hello, World")]
460+
[InlineData(new[] { "data:", " Hello, World\r\n\r\n" }, "Hello, World")]
461+
[InlineData(new[] { "data: Hello, World", "\r\n\r\n" }, "Hello, World")]
462+
[InlineData(new[] { "data: Hello, World\r\n", "\r\n" }, "Hello, World")]
463+
[InlineData(new[] { "data: ", "Hello, World\r\n\r\n" }, "Hello, World")]
464+
[InlineData(new[] { "data: ", "Hello, World\n\n" }, "Hello, World")]
465+
[InlineData(new[] { "data: ", "Hello, World\r\n\n" }, "Hello, World")]
466+
[InlineData(new[] { ":", "comment", "\r\n", "d", "ata: Hello, World\r\n\r\n" }, "Hello, World")]
467+
[InlineData(new[] { ":comment", "\r\n", "data: Hello, World", "\r\n\r\n" }, "Hello, World")]
468+
[InlineData(new[] { "data: Hello, World\r\n", ":comment\r\n", "\r\n" }, "Hello, World")]
469+
[InlineData(new[] { "data: Hello \r\n", "data: World\r\n\r\n" }, "Hello \nWorld")]
470+
public async Task CanProcessMessagesSuccessfully(string[] messageParts, string expectedMessage)
471+
{
472+
var mockHttpHandler = new Mock<HttpMessageHandler>();
473+
mockHttpHandler.Protected()
474+
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
475+
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
476+
{
477+
await Task.Yield();
478+
return new HttpResponseMessage { Content = new StreamContent(new OneAtATimeStream(messageParts)) };
479+
});
480+
481+
using (var httpClient = new HttpClient(mockHttpHandler.Object))
482+
using (StartVerifiableLog())
483+
{
484+
var sseTransport = new ServerSentEventsTransport(httpClient, loggerFactory: LoggerFactory);
485+
486+
await sseTransport.StartAsync(
487+
new Uri("http://fakeuri.org"), TransferFormat.Text).DefaultTimeout();
488+
489+
var message = await sseTransport.Input.ReadAllAsync().DefaultTimeout();
490+
Assert.Equal(expectedMessage, Encoding.ASCII.GetString(message));
491+
492+
await sseTransport.Running.DefaultTimeout();
493+
}
494+
}
495+
496+
public sealed class OneAtATimeStream : MemoryStream
497+
{
498+
private readonly string[] _contents;
499+
private int _index;
500+
501+
public OneAtATimeStream(string[] contents)
502+
{
503+
_contents = contents;
504+
}
505+
506+
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
507+
{
508+
if (_index == _contents.Length)
509+
{
510+
return new(0);
511+
}
512+
513+
Debug.Assert(buffer.Length > _contents[_index].Length);
514+
515+
return new(Encoding.UTF8.GetBytes(_contents[_index++], buffer.Span));
516+
}
517+
}
447518
}

0 commit comments

Comments
 (0)