22// The .NET Foundation licenses this file to you under the MIT license. 
33
44using  System . Diagnostics . CodeAnalysis ; 
5+ using  System . IO . Pipelines ; 
56using  System . Text . Json ; 
67using  System . Text . Json . Serialization ; 
78using  System . Text . Json . Serialization . Metadata ; 
@@ -89,13 +90,23 @@ public static Task WriteAsJsonAsync<TValue>(
8990
9091        response . ContentType  =  contentType  ??  JsonConstants . JsonContentTypeWithCharset ; 
9192
93+         var  startTask  =  Task . CompletedTask ; 
94+         if  ( ! response . HasStarted ) 
95+         { 
96+             // Flush headers before starting Json serialization. This avoids an extra layer of buffering before the first flush. 
97+             startTask  =  response . StartAsync ( cancellationToken ) ; 
98+         } 
99+ 
92100        // if no user provided token, pass the RequestAborted token and ignore OperationCanceledException 
93-         if  ( ! cancellationToken . CanBeCanceled ) 
101+         if  ( ! startTask . IsCompleted   ||   ! cancellationToken . CanBeCanceled ) 
94102        { 
95-             return  WriteAsJsonAsyncSlow ( response . Body ,  value ,  options ,  response . HttpContext . RequestAborted ) ; 
103+             return  WriteAsJsonAsyncSlow ( startTask ,  response . BodyWriter ,  value ,  options , 
104+                 ignoreOCE :  ! cancellationToken . CanBeCanceled , 
105+                 cancellationToken . CanBeCanceled  ?  cancellationToken  :  response . HttpContext . RequestAborted ) ; 
96106        } 
97107
98-         return  JsonSerializer . SerializeAsync ( response . Body ,  value ,  options ,  cancellationToken ) ; 
108+         startTask . GetAwaiter ( ) . GetResult ( ) ; 
109+         return  JsonSerializer . SerializeAsync ( response . BodyWriter ,  value ,  options ,  cancellationToken ) ; 
99110    } 
100111
101112    /// <summary> 
@@ -120,21 +131,33 @@ public static Task WriteAsJsonAsync<TValue>(
120131
121132        response . ContentType  =  contentType  ??  JsonConstants . JsonContentTypeWithCharset ; 
122133
134+         var  startTask  =  Task . CompletedTask ; 
135+         if  ( ! response . HasStarted ) 
136+         { 
137+             // Flush headers before starting Json serialization. This avoids an extra layer of buffering before the first flush. 
138+             startTask  =  response . StartAsync ( cancellationToken ) ; 
139+         } 
140+ 
123141        // if no user provided token, pass the RequestAborted token and ignore OperationCanceledException 
124-         if  ( ! cancellationToken . CanBeCanceled ) 
142+         if  ( ! startTask . IsCompleted   ||   ! cancellationToken . CanBeCanceled ) 
125143        { 
126-             return  WriteAsJsonAsyncSlow ( response ,  value ,  jsonTypeInfo ) ; 
144+             return  WriteAsJsonAsyncSlow ( startTask ,  response ,  value ,  jsonTypeInfo , 
145+                 ignoreOCE :  ! cancellationToken . CanBeCanceled , 
146+                 cancellationToken . CanBeCanceled  ?  cancellationToken  :  response . HttpContext . RequestAborted ) ; 
127147        } 
128148
129-         return  JsonSerializer . SerializeAsync ( response . Body ,  value ,  jsonTypeInfo ,  cancellationToken ) ; 
149+         startTask . GetAwaiter ( ) . GetResult ( ) ; 
150+         return  JsonSerializer . SerializeAsync ( response . BodyWriter ,  value ,  jsonTypeInfo ,  cancellationToken ) ; 
130151
131-         static async  Task  WriteAsJsonAsyncSlow ( HttpResponse  response ,  TValue  value ,  JsonTypeInfo < TValue >  jsonTypeInfo ) 
152+         static async  Task  WriteAsJsonAsyncSlow ( Task  startTask ,  HttpResponse  response ,  TValue  value ,  JsonTypeInfo < TValue >  jsonTypeInfo , 
153+             bool  ignoreOCE ,  CancellationToken  cancellationToken ) 
132154        { 
133155            try 
134156            { 
135-                 await  JsonSerializer . SerializeAsync ( response . Body ,  value ,  jsonTypeInfo ,  response . HttpContext . RequestAborted ) ; 
157+                 await  startTask ; 
158+                 await  JsonSerializer . SerializeAsync ( response . BodyWriter ,  value ,  jsonTypeInfo ,  cancellationToken ) ; 
136159            } 
137-             catch  ( OperationCanceledException )  {  } 
160+             catch  ( OperationCanceledException )  when   ( ignoreOCE )   {  } 
138161        } 
139162    } 
140163
@@ -161,37 +184,52 @@ public static Task WriteAsJsonAsync(
161184
162185        response . ContentType  =  contentType  ??  JsonConstants . JsonContentTypeWithCharset ; 
163186
187+         var  startTask  =  Task . CompletedTask ; 
188+         if  ( ! response . HasStarted ) 
189+         { 
190+             // Flush headers before starting Json serialization. This avoids an extra layer of buffering before the first flush. 
191+             startTask  =  response . StartAsync ( cancellationToken ) ; 
192+         } 
193+ 
164194        // if no user provided token, pass the RequestAborted token and ignore OperationCanceledException 
165-         if  ( ! cancellationToken . CanBeCanceled ) 
195+         if  ( ! startTask . IsCompleted   ||   ! cancellationToken . CanBeCanceled ) 
166196        { 
167-             return  WriteAsJsonAsyncSlow ( response ,  value ,  jsonTypeInfo ) ; 
197+             return  WriteAsJsonAsyncSlow ( startTask ,  response ,  value ,  jsonTypeInfo , 
198+                 ignoreOCE :  ! cancellationToken . CanBeCanceled , 
199+                 cancellationToken . CanBeCanceled  ?  cancellationToken  :  response . HttpContext . RequestAborted ) ; 
168200        } 
169201
170-         return  JsonSerializer . SerializeAsync ( response . Body ,  value ,  jsonTypeInfo ,  cancellationToken ) ; 
202+         startTask . GetAwaiter ( ) . GetResult ( ) ; 
203+         return  JsonSerializer . SerializeAsync ( response . BodyWriter ,  value ,  jsonTypeInfo ,  cancellationToken ) ; 
171204
172-         static async  Task  WriteAsJsonAsyncSlow ( HttpResponse  response ,  object ?  value ,  JsonTypeInfo  jsonTypeInfo ) 
205+         static async  Task  WriteAsJsonAsyncSlow ( Task  startTask ,  HttpResponse  response ,  object ?  value ,  JsonTypeInfo  jsonTypeInfo , 
206+             bool  ignoreOCE ,  CancellationToken  cancellationToken ) 
173207        { 
174208            try 
175209            { 
176-                 await  JsonSerializer . SerializeAsync ( response . Body ,  value ,  jsonTypeInfo ,  response . HttpContext . RequestAborted ) ; 
210+                 await  startTask ; 
211+                 await  JsonSerializer . SerializeAsync ( response . BodyWriter ,  value ,  jsonTypeInfo ,  cancellationToken ) ; 
177212            } 
178-             catch  ( OperationCanceledException )  {  } 
213+             catch  ( OperationCanceledException )  when   ( ignoreOCE )   {  } 
179214        } 
180215    } 
181216
182217    [ RequiresUnreferencedCode ( RequiresUnreferencedCodeMessage ) ] 
183218    [ RequiresDynamicCode ( RequiresDynamicCodeMessage ) ] 
184219    private  static async  Task  WriteAsJsonAsyncSlow < TValue > ( 
185-         Stream  body , 
220+         Task  startTask , 
221+         PipeWriter  body , 
186222        TValue  value , 
187223        JsonSerializerOptions ?  options , 
224+         bool  ignoreOCE , 
188225        CancellationToken  cancellationToken ) 
189226    { 
190227        try 
191228        { 
229+             await  startTask ; 
192230            await  JsonSerializer . SerializeAsync ( body ,  value ,  options ,  cancellationToken ) ; 
193231        } 
194-         catch  ( OperationCanceledException )  {  } 
232+         catch  ( OperationCanceledException )  when   ( ignoreOCE )   {  } 
195233    } 
196234
197235    /// <summary> 
@@ -266,29 +304,42 @@ public static Task WriteAsJsonAsync(
266304
267305        response . ContentType  =  contentType  ??  JsonConstants . JsonContentTypeWithCharset ; 
268306
307+         var  startTask  =  Task . CompletedTask ; 
308+         if  ( ! response . HasStarted ) 
309+         { 
310+             // Flush headers before starting Json serialization. This avoids an extra layer of buffering before the first flush. 
311+             startTask  =  response . StartAsync ( cancellationToken ) ; 
312+         } 
313+ 
269314        // if no user provided token, pass the RequestAborted token and ignore OperationCanceledException 
270-         if  ( ! cancellationToken . CanBeCanceled ) 
315+         if  ( ! startTask . IsCompleted   ||   ! cancellationToken . CanBeCanceled ) 
271316        { 
272-             return  WriteAsJsonAsyncSlow ( response . Body ,  value ,  type ,  options ,  response . HttpContext . RequestAborted ) ; 
317+             return  WriteAsJsonAsyncSlow ( startTask ,  response . BodyWriter ,  value ,  type ,  options , 
318+                 ignoreOCE :  ! cancellationToken . CanBeCanceled , 
319+                 cancellationToken . CanBeCanceled  ?  cancellationToken  :  response . HttpContext . RequestAborted ) ; 
273320        } 
274321
275-         return  JsonSerializer . SerializeAsync ( response . Body ,  value ,  type ,  options ,  cancellationToken ) ; 
322+         startTask . GetAwaiter ( ) . GetResult ( ) ; 
323+         return  JsonSerializer . SerializeAsync ( response . BodyWriter ,  value ,  type ,  options ,  cancellationToken ) ; 
276324    } 
277325
278326    [ RequiresUnreferencedCode ( RequiresUnreferencedCodeMessage ) ] 
279327    [ RequiresDynamicCode ( RequiresDynamicCodeMessage ) ] 
280328    private  static async  Task  WriteAsJsonAsyncSlow ( 
281-         Stream  body , 
329+         Task  startTask , 
330+         PipeWriter  body , 
282331        object ?  value , 
283332        Type  type , 
284333        JsonSerializerOptions ?  options , 
334+         bool  ignoreOCE , 
285335        CancellationToken  cancellationToken ) 
286336    { 
287337        try 
288338        { 
339+             await  startTask ; 
289340            await  JsonSerializer . SerializeAsync ( body ,  value ,  type ,  options ,  cancellationToken ) ; 
290341        } 
291-         catch  ( OperationCanceledException )  {  } 
342+         catch  ( OperationCanceledException )  when   ( ignoreOCE )   {  } 
292343    } 
293344
294345    /// <summary> 
@@ -316,21 +367,33 @@ public static Task WriteAsJsonAsync(
316367
317368        response . ContentType  =  contentType  ??  JsonConstants . JsonContentTypeWithCharset ; 
318369
370+         var  startTask  =  Task . CompletedTask ; 
371+         if  ( ! response . HasStarted ) 
372+         { 
373+             // Flush headers before starting Json serialization. This avoids an extra layer of buffering before the first flush. 
374+             startTask  =  response . StartAsync ( cancellationToken ) ; 
375+         } 
376+ 
319377        // if no user provided token, pass the RequestAborted token and ignore OperationCanceledException 
320-         if  ( ! cancellationToken . CanBeCanceled ) 
378+         if  ( ! startTask . IsCompleted   ||   ! cancellationToken . CanBeCanceled ) 
321379        { 
322-             return  WriteAsJsonAsyncSlow ( ) ; 
380+             return  WriteAsJsonAsyncSlow ( startTask ,  response . BodyWriter ,  value ,  type ,  context , 
381+                 ignoreOCE :  ! cancellationToken . CanBeCanceled , 
382+                 cancellationToken . CanBeCanceled  ?  cancellationToken  :  response . HttpContext . RequestAborted ) ; 
323383        } 
324384
325-         return  JsonSerializer . SerializeAsync ( response . Body ,  value ,  type ,  context ,  cancellationToken ) ; 
385+         startTask . GetAwaiter ( ) . GetResult ( ) ; 
386+         return  JsonSerializer . SerializeAsync ( response . BodyWriter ,  value ,  type ,  context ,  cancellationToken ) ; 
326387
327-         async  Task  WriteAsJsonAsyncSlow ( ) 
388+         static async  Task  WriteAsJsonAsyncSlow ( Task  startTask ,  PipeWriter  body ,  object ?  value ,  Type  type ,  JsonSerializerContext  context , 
389+             bool  ignoreOCE ,  CancellationToken  cancellationToken ) 
328390        { 
329391            try 
330392            { 
331-                 await  JsonSerializer . SerializeAsync ( response . Body ,  value ,  type ,  context ,  cancellationToken ) ; 
393+                 await  startTask ; 
394+                 await  JsonSerializer . SerializeAsync ( body ,  value ,  type ,  context ,  cancellationToken ) ; 
332395            } 
333-             catch  ( OperationCanceledException )  {  } 
396+             catch  ( OperationCanceledException )  when   ( ignoreOCE )   {  } 
334397        } 
335398    } 
336399
0 commit comments