diff --git a/src/Microsoft.AspNetCore.OData/Formatter/ODataOutputFormatterHelper.cs b/src/Microsoft.AspNetCore.OData/Formatter/ODataOutputFormatterHelper.cs index 57d28ab60..d49aaee32 100644 --- a/src/Microsoft.AspNetCore.OData/Formatter/ODataOutputFormatterHelper.cs +++ b/src/Microsoft.AspNetCore.OData/Formatter/ODataOutputFormatterHelper.cs @@ -21,6 +21,7 @@ using Microsoft.AspNetCore.OData.Formatter.Value; using Microsoft.AspNetCore.OData.Query; using Microsoft.AspNetCore.OData.Routing; +using Microsoft.IO; using Microsoft.Net.Http.Headers; using Microsoft.OData; using Microsoft.OData.Edm; @@ -31,6 +32,8 @@ namespace Microsoft.AspNetCore.OData.Formatter { internal static class ODataOutputFormatterHelper { + private static readonly Lazy recycleableMemoryStreamManager = new Lazy(); + public static ODataSerializerContext BuildSerializerContext(HttpRequest request) { if (request == null) @@ -68,18 +71,19 @@ internal static async Task WriteToStreamAsync( ODataPath path = request.ODataFeature().Path; IEdmNavigationSource targetNavigationSource = path.GetNavigationSource(); HttpResponse response = request.HttpContext.Response; + MemoryStream responseBody = recycleableMemoryStreamManager.Value.GetStream(nameof(ODataOutputFormatterHelper.WriteToStreamAsync)); // serialize a response string preferHeader = RequestPreferenceHelpers.GetRequestPreferHeader(requestHeaders); string annotationFilter = null; if (!string.IsNullOrEmpty(preferHeader)) { - ODataMessageWrapper messageWrapper = ODataMessageWrapperHelper.Create(response.Body, response.Headers); + ODataMessageWrapper messageWrapper = ODataMessageWrapperHelper.Create(responseBody, response.Headers); messageWrapper.SetHeader(RequestPreferenceHelpers.PreferHeaderName, preferHeader); annotationFilter = messageWrapper.PreferHeader().AnnotationFilter; } - IODataResponseMessageAsync responseMessage = ODataMessageWrapperHelper.Create(new StreamWrapper(response.Body), response.Headers, request.GetRouteServices()); + IODataResponseMessageAsync responseMessage = ODataMessageWrapperHelper.Create(new StreamWrapper(responseBody), response.Headers, request.GetRouteServices()); if (annotationFilter != null) { responseMessage.PreferenceAppliedHeader().AnnotationFilter = annotationFilter; @@ -131,6 +135,7 @@ internal static async Task WriteToStreamAsync( metadataLevel = ODataMediaTypes.GetMetadataLevel(contentType.MediaType.ToString(), parameters); } + using (responseBody) using (ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage, writerSettings, model)) { ODataSerializerContext writeContext = BuildSerializerContext(request); @@ -150,6 +155,8 @@ internal static async Task WriteToStreamAsync( } await serializer.WriteObjectAsync(value, type, messageWriter, writeContext).ConfigureAwait(false); + responseBody.Position = 0; + await responseBody.CopyToAsync(response.Body); } } diff --git a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.csproj b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.csproj index f6d8b063b..8bd9fda5b 100644 --- a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.csproj +++ b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.csproj @@ -28,6 +28,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive +