From 1d76284e25b603f4fc6c00ac4b6625ca7bca7e29 Mon Sep 17 00:00:00 2001 From: Brad Christensen Date: Fri, 16 Sep 2016 18:45:44 +1200 Subject: [PATCH] Serialize node invocationInfo JSON directly to stream to avoid running out of memory Fixed only for SocketNodeInstance, as it deals nicely with streams. Previously ~30MB of JSON text and 32-bit IIS Express would result in an OutOfMemoryException at the GetBytes method, which is now fixed by writing the JSON string directly to the stream and not handling it as a string in between. --- .../HostingModels/SocketNodeInstance.cs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs b/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs index 2ee2aa4..dc8f9a3 100644 --- a/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs +++ b/src/Microsoft.AspNetCore.NodeServices/HostingModels/SocketNodeInstance.cs @@ -33,6 +33,9 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels TypeNameHandling = TypeNameHandling.None }; + private readonly static int streamBufferSize = 16 * 1024; + private readonly static UTF8Encoding utf8EncodingWithoutBom = new UTF8Encoding(false); + private readonly SemaphoreSlim _connectionCreationSemaphore = new SemaphoreSlim(1); private bool _connectionHasFailed; private StreamConnection _physicalConnection; @@ -89,7 +92,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels virtualConnection = _virtualConnectionClient.OpenVirtualConnection(); // Send request - await WriteJsonLineAsync(virtualConnection, invocationInfo, cancellationToken); + WriteJsonLine(virtualConnection, invocationInfo, cancellationToken); // Determine what kind of response format is expected if (typeof(T) == typeof(Stream)) @@ -169,11 +172,20 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels base.Dispose(disposing); } - private static async Task WriteJsonLineAsync(Stream stream, object serializableObject, CancellationToken cancellationToken) + private static void WriteJsonLine(Stream stream, object serializableObject, CancellationToken cancellationToken) { - var json = JsonConvert.SerializeObject(serializableObject, jsonSerializerSettings); - var bytes = Encoding.UTF8.GetBytes(json + '\n'); - await stream.WriteAsync(bytes, 0, bytes.Length, cancellationToken); + using (var streamWriter = new StreamWriter(stream, utf8EncodingWithoutBom, streamBufferSize, true)) + using (var jsonWriter = new JsonTextWriter(streamWriter)) + { + jsonWriter.CloseOutput = false; + + var serializer = JsonSerializer.Create(jsonSerializerSettings); + serializer.Serialize(jsonWriter, serializableObject); + jsonWriter.Flush(); + + streamWriter.WriteLine(); + streamWriter.Flush(); + } } private static async Task ReadJsonAsync(Stream stream, CancellationToken cancellationToken) @@ -184,7 +196,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels private static async Task ReadAllBytesAsync(Stream input, CancellationToken cancellationToken) { - byte[] buffer = new byte[16 * 1024]; + byte[] buffer = new byte[streamBufferSize]; using (var ms = new MemoryStream()) {