@@ -21,6 +21,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels
2121 /// <seealso cref="Microsoft.AspNetCore.NodeServices.HostingModels.OutOfProcessNodeInstance" />
2222 internal class HttpNodeInstance : OutOfProcessNodeInstance
2323 {
24+ private readonly static int streamBufferSize = 16 * 1024 ;
2425 private static readonly Regex PortMessageRegex =
2526 new Regex ( @"^\[Microsoft.AspNetCore.NodeServices.HttpNodeHost:Listening on port (\d+)\]$" ) ;
2627
@@ -67,8 +68,10 @@ protected override async Task<T> InvokeExportAsync<T>(
6768 if ( ! response . IsSuccessStatusCode )
6869 {
6970 // Unfortunately there's no true way to cancel ReadAsStringAsync calls, hence AbandonIfCancelled
70- var responseErrorString = await response . Content . ReadAsStringAsync ( ) . OrThrowOnCancellation ( cancellationToken ) ;
71- throw new Exception ( "Call to Node module failed with error: " + responseErrorString ) ;
71+ var responseJson = await response . Content . ReadAsStringAsync ( ) . OrThrowOnCancellation ( cancellationToken ) ;
72+ var responseError = JsonConvert . DeserializeObject < RpcJsonResponse > ( responseJson , jsonSerializerSettings ) ;
73+
74+ throw new NodeInvocationException ( responseError . ErrorMessage , responseError . ErrorDetails ) ;
7275 }
7376
7477 var responseContentType = response . Content . Headers . ContentType ;
@@ -136,5 +139,35 @@ protected override void Dispose(bool disposing)
136139 _disposed = true ;
137140 }
138141 }
142+
143+ private static async Task < T > ReadJsonAsync < T > ( Stream stream , CancellationToken cancellationToken )
144+ {
145+ var json = Encoding . UTF8 . GetString ( await ReadAllBytesAsync ( stream , cancellationToken ) ) ;
146+ return JsonConvert . DeserializeObject < T > ( json , jsonSerializerSettings ) ;
147+ }
148+
149+ private static async Task < byte [ ] > ReadAllBytesAsync ( Stream input , CancellationToken cancellationToken )
150+ {
151+ byte [ ] buffer = new byte [ streamBufferSize ] ;
152+
153+ using ( var ms = new MemoryStream ( ) )
154+ {
155+ int read ;
156+ while ( ( read = await input . ReadAsync ( buffer , 0 , buffer . Length , cancellationToken ) ) > 0 )
157+ {
158+ ms . Write ( buffer , 0 , read ) ;
159+ }
160+
161+ return ms . ToArray ( ) ;
162+ }
163+ }
164+
165+ #pragma warning disable 649 // These properties are populated via JSON deserialization
166+ private class RpcJsonResponse
167+ {
168+ public string ErrorMessage { get ; set ; }
169+ public string ErrorDetails { get ; set ; }
170+ }
171+ #pragma warning restore 649
139172 }
140173}
0 commit comments