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