1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . IO . Pipelines ;
4
5
using System . Net . ServerSentEvents ;
5
6
using System . Reflection ;
6
7
using System . Runtime . CompilerServices ;
7
8
using System . Text ;
8
9
using Microsoft . AspNetCore . Builder ;
10
+ using Microsoft . AspNetCore . Http . Features ;
9
11
using Microsoft . AspNetCore . Http . Json ;
10
12
using Microsoft . AspNetCore . Http . Metadata ;
11
13
using Microsoft . AspNetCore . Routing ;
@@ -31,6 +33,7 @@ public async Task ExecuteAsync_SetsContentTypeAndHeaders()
31
33
Assert . Equal ( "text/event-stream" , httpContext . Response . ContentType ) ;
32
34
Assert . Equal ( "no-cache,no-store" , httpContext . Response . Headers . CacheControl ) ;
33
35
Assert . Equal ( "no-cache" , httpContext . Response . Headers . Pragma ) ;
36
+ Assert . Equal ( "identity" , httpContext . Response . Headers . ContentEncoding ) ;
34
37
}
35
38
36
39
[ Fact ]
@@ -259,6 +262,75 @@ async IAsyncEnumerable<string> GetEvents([EnumeratorCancellation] CancellationTo
259
262
}
260
263
}
261
264
265
+ [ Fact ]
266
+ public async Task ExecuteAsync_DisablesBuffering ( )
267
+ {
268
+ // Arrange
269
+ var httpContext = GetHttpContext ( ) ;
270
+ var events = AsyncEnumerable . Empty < string > ( ) ;
271
+ var result = TypedResults . ServerSentEvents ( events ) ;
272
+ var bufferingDisabled = false ;
273
+
274
+ var mockBufferingFeature = new MockHttpResponseBodyFeature (
275
+ onDisableBuffering : ( ) => bufferingDisabled = true ) ;
276
+
277
+ httpContext . Features . Set < IHttpResponseBodyFeature > ( mockBufferingFeature ) ;
278
+
279
+ // Act
280
+ await result . ExecuteAsync ( httpContext ) ;
281
+
282
+ // Assert
283
+ Assert . True ( bufferingDisabled ) ;
284
+ }
285
+
286
+ [ Fact ]
287
+ public async Task ExecuteAsync_WithByteArrayData_WritesDataDirectly ( )
288
+ {
289
+ // Arrange
290
+ var httpContext = GetHttpContext ( ) ;
291
+ var bytes = "event1"u8 . ToArray ( ) ;
292
+ var events = new [ ] { new SseItem < byte [ ] > ( bytes ) } . ToAsyncEnumerable ( ) ;
293
+ var result = TypedResults . ServerSentEvents ( events ) ;
294
+
295
+ // Act
296
+ await result . ExecuteAsync ( httpContext ) ;
297
+
298
+ // Assert
299
+ var responseBody = Encoding . UTF8 . GetString ( ( ( MemoryStream ) httpContext . Response . Body ) . ToArray ( ) ) ;
300
+ Assert . Contains ( "data: event1\n \n " , responseBody ) ;
301
+
302
+ // Assert that string is not JSON serialized
303
+ Assert . DoesNotContain ( "data: \" event1" , responseBody ) ;
304
+ }
305
+
306
+ [ Fact ]
307
+ public async Task ExecuteAsync_WithByteArrayData_HandlesNullData ( )
308
+ {
309
+ // Arrange
310
+ var httpContext = GetHttpContext ( ) ;
311
+ var events = new [ ] { new SseItem < byte [ ] > ( null ) } . ToAsyncEnumerable ( ) ;
312
+ var result = TypedResults . ServerSentEvents ( events ) ;
313
+
314
+ // Act
315
+ await result . ExecuteAsync ( httpContext ) ;
316
+
317
+ // Assert
318
+ var responseBody = Encoding . UTF8 . GetString ( ( ( MemoryStream ) httpContext . Response . Body ) . ToArray ( ) ) ;
319
+ Assert . Contains ( "data: \n \n " , responseBody ) ;
320
+ }
321
+
322
+ private class MockHttpResponseBodyFeature ( Action onDisableBuffering ) : IHttpResponseBodyFeature
323
+ {
324
+ public Stream Stream => new MemoryStream ( ) ;
325
+ public PipeWriter Writer => throw new NotImplementedException ( ) ;
326
+ public Task CompleteAsync ( ) => throw new NotImplementedException ( ) ;
327
+ public void DisableBuffering ( ) => onDisableBuffering ( ) ;
328
+ public Task SendFileAsync ( string path , long offset , long ? count , CancellationToken cancellationToken = default )
329
+ => throw new NotImplementedException ( ) ;
330
+ public Task StartAsync ( CancellationToken cancellationToken = default )
331
+ => throw new NotImplementedException ( ) ;
332
+ }
333
+
262
334
private static void PopulateMetadata < TResult > ( MethodInfo method , EndpointBuilder builder )
263
335
where TResult : IEndpointMetadataProvider => TResult . PopulateMetadata ( method , builder ) ;
264
336
0 commit comments