From 54aad643c8584e6d42f538667819ec7591c748bb Mon Sep 17 00:00:00 2001 From: SteveSandersonMS Date: Thu, 5 Nov 2015 22:05:43 +0000 Subject: [PATCH] Decode Node's JSON response into arbitrary .NET type. Add VS stuff. --- .gitignore | 1 + .../AngularRenderer.cs | 2 +- ...icrosoft.AspNet.NodeServices.Angular.xproj | 19 ++++++ .../Microsoft.AspNet.NodeServices.React.xproj | 19 ++++++ .../ReactRenderer.cs | 2 +- .../Content/Node/entrypoint-http.js | 6 +- .../Content/Node/entrypoint-stream.js | 2 +- .../HostingModels/HttpNodeInstance.cs | 11 +++- .../InputOutputStreamNodeInstance.cs | 5 +- .../HostingModels/OutOfProcessNodeInstance.cs | 10 +-- .../INodeInstance.cs | 4 +- .../Microsoft.AspNet.NodeServices.xproj | 19 ++++++ NodeServices.sln | 64 +++++++++++++++++++ samples/angular/MusicStore/MusicStore.xproj | 19 ++++++ samples/angular/MusicStore/wwwroot/web.config | 8 +-- .../ES2015Transpilation.xproj | 19 ++++++ samples/misc/ES2015Transpilation/Startup.cs | 2 +- .../ES2015Transpilation/wwwroot/web.config | 8 +-- samples/react/ReactGrid/ReactGrid.xproj | 19 ++++++ 19 files changed, 213 insertions(+), 26 deletions(-) create mode 100644 Microsoft.AspNet.NodeServices.Angular/Microsoft.AspNet.NodeServices.Angular.xproj create mode 100644 Microsoft.AspNet.NodeServices.React/Microsoft.AspNet.NodeServices.React.xproj create mode 100644 Microsoft.AspNet.NodeServices/Microsoft.AspNet.NodeServices.xproj create mode 100644 NodeServices.sln create mode 100644 samples/angular/MusicStore/MusicStore.xproj create mode 100644 samples/misc/ES2015Transpilation/ES2015Transpilation.xproj create mode 100644 samples/react/ReactGrid/ReactGrid.xproj diff --git a/.gitignore b/.gitignore index 4fc10d2..0d2dd9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vs *.xproj.user project.lock.json +npm-debug.log diff --git a/Microsoft.AspNet.NodeServices.Angular/AngularRenderer.cs b/Microsoft.AspNet.NodeServices.Angular/AngularRenderer.cs index 4ca5868..511a53c 100644 --- a/Microsoft.AspNet.NodeServices.Angular/AngularRenderer.cs +++ b/Microsoft.AspNet.NodeServices.Angular/AngularRenderer.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNet.NodeServices.Angular } public static async Task RenderToString(INodeServices nodeServices, string componentModuleName, string componentExportName, string componentTagName, string requestUrl) { - return await nodeServices.InvokeExport(nodeScript.FileName, "renderToString", new { + return await nodeServices.InvokeExport(nodeScript.FileName, "renderToString", new { moduleName = componentModuleName, exportName = componentExportName, tagName = componentTagName, diff --git a/Microsoft.AspNet.NodeServices.Angular/Microsoft.AspNet.NodeServices.Angular.xproj b/Microsoft.AspNet.NodeServices.Angular/Microsoft.AspNet.NodeServices.Angular.xproj new file mode 100644 index 0000000..a8b1bbe --- /dev/null +++ b/Microsoft.AspNet.NodeServices.Angular/Microsoft.AspNet.NodeServices.Angular.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 421807e6-b62c-417b-b901-46c5dedaa8f1 + Microsoft.AspNet.NodeServices.Angular + ..\artifacts\obj\$(MSBuildProjectName) + ..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/Microsoft.AspNet.NodeServices.React/Microsoft.AspNet.NodeServices.React.xproj b/Microsoft.AspNet.NodeServices.React/Microsoft.AspNet.NodeServices.React.xproj new file mode 100644 index 0000000..2e0a0c8 --- /dev/null +++ b/Microsoft.AspNet.NodeServices.React/Microsoft.AspNet.NodeServices.React.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + b04381de-991f-4831-a0b5-fe1bd3ef80c4 + Microsoft.AspNet.NodeServices.React + ..\artifacts\obj\$(MSBuildProjectName) + ..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/Microsoft.AspNet.NodeServices.React/ReactRenderer.cs b/Microsoft.AspNet.NodeServices.React/ReactRenderer.cs index d48a694..222d031 100644 --- a/Microsoft.AspNet.NodeServices.React/ReactRenderer.cs +++ b/Microsoft.AspNet.NodeServices.React/ReactRenderer.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNet.NodeServices.React } public static async Task RenderToString(INodeServices nodeServices, string componentModuleName, string componentExportName, string requestUrl) { - return await nodeServices.InvokeExport(nodeScript.FileName, "renderToString", new { + return await nodeServices.InvokeExport(nodeScript.FileName, "renderToString", new { moduleName = componentModuleName, exportName = componentExportName, requestUrl = requestUrl diff --git a/Microsoft.AspNet.NodeServices/Content/Node/entrypoint-http.js b/Microsoft.AspNet.NodeServices/Content/Node/entrypoint-http.js index 16d2a77..f19c114 100644 --- a/Microsoft.AspNet.NodeServices/Content/Node/entrypoint-http.js +++ b/Microsoft.AspNet.NodeServices/Content/Node/entrypoint-http.js @@ -14,15 +14,15 @@ var server = http.createServer(function(req, res) { if (!func) { throw new Error('The module "' + resolvedPath + '" has no export named "' + bodyJson.exportedFunctionName + '"'); } - + var hasSentResult = false; var callback = function(errorValue, successValue) { if (!hasSentResult) { hasSentResult = true; if (errorValue) { res.status(500).send(errorValue); - } else if (typeof successValue === 'object') { - // Arbitrary object - JSON-serialize it + } else if (typeof successValue !== 'string') { + // Arbitrary object/number/etc - JSON-serialize it res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify(successValue)); } else { diff --git a/Microsoft.AspNet.NodeServices/Content/Node/entrypoint-stream.js b/Microsoft.AspNet.NodeServices/Content/Node/entrypoint-stream.js index 7f5218e..d2318fa 100644 --- a/Microsoft.AspNet.NodeServices/Content/Node/entrypoint-stream.js +++ b/Microsoft.AspNet.NodeServices/Content/Node/entrypoint-stream.js @@ -6,7 +6,7 @@ function invocationCallback(errorValue, successValue) { if (errorValue) { throw new Error('InputOutputStreamHost doesn\'t support errors. Got error: ' + errorValue.toString()); } else { - var serializedResult = typeof successValue === 'object' ? JSON.stringify(successValue) : successValue; + var serializedResult = JSON.stringify(successValue); console.log(serializedResult); } } diff --git a/Microsoft.AspNet.NodeServices/HostingModels/HttpNodeInstance.cs b/Microsoft.AspNet.NodeServices/HostingModels/HttpNodeInstance.cs index 6c94f2a..b863ad1 100644 --- a/Microsoft.AspNet.NodeServices/HostingModels/HttpNodeInstance.cs +++ b/Microsoft.AspNet.NodeServices/HostingModels/HttpNodeInstance.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNet.NodeServices { { } - public override async Task Invoke(NodeInvocationInfo invocationInfo) { + public override async Task Invoke(NodeInvocationInfo invocationInfo) { await this.EnsureReady(); using (var client = new HttpClient()) { @@ -29,7 +29,14 @@ namespace Microsoft.AspNet.NodeServices { var payload = new StringContent(payloadJson, Encoding.UTF8, "application/json"); var response = await client.PostAsync("http://localhost:" + this._portNumber, payload); var responseString = await response.Content.ReadAsStringAsync(); - return responseString; + var responseIsJson = response.Content.Headers.ContentType.MediaType == "application/json"; + if (responseIsJson) { + return JsonConvert.DeserializeObject(responseString); + } else if (typeof(T) != typeof(string)) { + throw new System.ArgumentException("Node module responded with non-JSON string. This cannot be converted to the requested generic type: " + typeof(T).FullName); + } else { + return (T)(object)responseString; + } } } diff --git a/Microsoft.AspNet.NodeServices/HostingModels/InputOutputStreamNodeInstance.cs b/Microsoft.AspNet.NodeServices/HostingModels/InputOutputStreamNodeInstance.cs index e44d788..1408911 100644 --- a/Microsoft.AspNet.NodeServices/HostingModels/InputOutputStreamNodeInstance.cs +++ b/Microsoft.AspNet.NodeServices/HostingModels/InputOutputStreamNodeInstance.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNet.NodeServices { { } - public override async Task Invoke(NodeInvocationInfo invocationInfo) { + public override async Task Invoke(NodeInvocationInfo invocationInfo) { await this._invocationSemaphore.WaitAsync(); try { await this.EnsureReady(); @@ -39,7 +39,8 @@ namespace Microsoft.AspNet.NodeServices { this._currentInvocationResult = new TaskCompletionSource(); nodeProcess.StandardInput.Write("\ninvoke:"); nodeProcess.StandardInput.WriteLine(payloadJson); // WriteLineAsync isn't supported cross-platform - return await this._currentInvocationResult.Task; + var resultString = await this._currentInvocationResult.Task; + return JsonConvert.DeserializeObject(resultString); } finally { this._invocationSemaphore.Release(); this._currentInvocationResult = null; diff --git a/Microsoft.AspNet.NodeServices/HostingModels/OutOfProcessNodeInstance.cs b/Microsoft.AspNet.NodeServices/HostingModels/OutOfProcessNodeInstance.cs index e6accf0..0d4ce17 100644 --- a/Microsoft.AspNet.NodeServices/HostingModels/OutOfProcessNodeInstance.cs +++ b/Microsoft.AspNet.NodeServices/HostingModels/OutOfProcessNodeInstance.cs @@ -33,14 +33,14 @@ namespace Microsoft.AspNet.NodeServices { this._commandLineArguments = commandLineArguments ?? string.Empty; } - public abstract Task Invoke(NodeInvocationInfo invocationInfo); + public abstract Task Invoke(NodeInvocationInfo invocationInfo); - public Task Invoke(string moduleName, params object[] args) { - return this.InvokeExport(moduleName, null, args); + public Task Invoke(string moduleName, params object[] args) { + return this.InvokeExport(moduleName, null, args); } - public async Task InvokeExport(string moduleName, string exportedFunctionName, params object[] args) { - return await this.Invoke(new NodeInvocationInfo { + public async Task InvokeExport(string moduleName, string exportedFunctionName, params object[] args) { + return await this.Invoke(new NodeInvocationInfo { ModuleName = moduleName, ExportedFunctionName = exportedFunctionName, Args = args diff --git a/Microsoft.AspNet.NodeServices/INodeInstance.cs b/Microsoft.AspNet.NodeServices/INodeInstance.cs index 9118688..8464675 100644 --- a/Microsoft.AspNet.NodeServices/INodeInstance.cs +++ b/Microsoft.AspNet.NodeServices/INodeInstance.cs @@ -3,8 +3,8 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.NodeServices { public interface INodeServices : IDisposable { - Task Invoke(string moduleName, params object[] args); + Task Invoke(string moduleName, params object[] args); - Task InvokeExport(string moduleName, string exportedFunctionName, params object[] args); + Task InvokeExport(string moduleName, string exportedFunctionName, params object[] args); } } diff --git a/Microsoft.AspNet.NodeServices/Microsoft.AspNet.NodeServices.xproj b/Microsoft.AspNet.NodeServices/Microsoft.AspNet.NodeServices.xproj new file mode 100644 index 0000000..a02a349 --- /dev/null +++ b/Microsoft.AspNet.NodeServices/Microsoft.AspNet.NodeServices.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + b0fa4175-8b29-4904-9780-28b3c24b0567 + Microsoft.AspNet.NodeServices + ..\NodeServices.sln\artifacts\obj\$(MSBuildProjectName) + ..\NodeServices.sln\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/NodeServices.sln b/NodeServices.sln new file mode 100644 index 0000000..1ded2ba --- /dev/null +++ b/NodeServices.sln @@ -0,0 +1,64 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{E6E88944-4800-40BA-8AF5-069EA3ADFEB8}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.NodeServices", "Microsoft.AspNet.NodeServices\Microsoft.AspNet.NodeServices.xproj", "{B0FA4175-8B29-4904-9780-28B3C24B0567}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ES2015Transpilation", "samples\misc\ES2015Transpilation\ES2015Transpilation.xproj", "{6D4BCDD6-7951-449B-BE55-CB7F014B7430}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{78DAC76C-1092-45AB-BF0D-594B8C7B6569}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + EndProjectSection +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MusicStore", "samples\angular\MusicStore\MusicStore.xproj", "{1A74148F-9DC0-435D-B5AC-7D1B0D3D5E0B}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ReactGrid", "samples\react\ReactGrid\ReactGrid.xproj", "{ABF90A5B-F4E0-438C-A6E4-9549FB43690B}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.NodeServices.Angular", "Microsoft.AspNet.NodeServices.Angular\Microsoft.AspNet.NodeServices.Angular.xproj", "{421807E6-B62C-417B-B901-46C5DEDAA8F1}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.NodeServices.React", "Microsoft.AspNet.NodeServices.React\Microsoft.AspNet.NodeServices.React.xproj", "{B04381DE-991F-4831-A0B5-FE1BD3EF80C4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B0FA4175-8B29-4904-9780-28B3C24B0567}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0FA4175-8B29-4904-9780-28B3C24B0567}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0FA4175-8B29-4904-9780-28B3C24B0567}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0FA4175-8B29-4904-9780-28B3C24B0567}.Release|Any CPU.Build.0 = Release|Any CPU + {6D4BCDD6-7951-449B-BE55-CB7F014B7430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D4BCDD6-7951-449B-BE55-CB7F014B7430}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D4BCDD6-7951-449B-BE55-CB7F014B7430}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D4BCDD6-7951-449B-BE55-CB7F014B7430}.Release|Any CPU.Build.0 = Release|Any CPU + {1A74148F-9DC0-435D-B5AC-7D1B0D3D5E0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A74148F-9DC0-435D-B5AC-7D1B0D3D5E0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A74148F-9DC0-435D-B5AC-7D1B0D3D5E0B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A74148F-9DC0-435D-B5AC-7D1B0D3D5E0B}.Release|Any CPU.Build.0 = Release|Any CPU + {ABF90A5B-F4E0-438C-A6E4-9549FB43690B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABF90A5B-F4E0-438C-A6E4-9549FB43690B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABF90A5B-F4E0-438C-A6E4-9549FB43690B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABF90A5B-F4E0-438C-A6E4-9549FB43690B}.Release|Any CPU.Build.0 = Release|Any CPU + {421807E6-B62C-417B-B901-46C5DEDAA8F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {421807E6-B62C-417B-B901-46C5DEDAA8F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {421807E6-B62C-417B-B901-46C5DEDAA8F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {421807E6-B62C-417B-B901-46C5DEDAA8F1}.Release|Any CPU.Build.0 = Release|Any CPU + {B04381DE-991F-4831-A0B5-FE1BD3EF80C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B04381DE-991F-4831-A0B5-FE1BD3EF80C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B04381DE-991F-4831-A0B5-FE1BD3EF80C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B04381DE-991F-4831-A0B5-FE1BD3EF80C4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6D4BCDD6-7951-449B-BE55-CB7F014B7430} = {E6E88944-4800-40BA-8AF5-069EA3ADFEB8} + {1A74148F-9DC0-435D-B5AC-7D1B0D3D5E0B} = {E6E88944-4800-40BA-8AF5-069EA3ADFEB8} + {ABF90A5B-F4E0-438C-A6E4-9549FB43690B} = {E6E88944-4800-40BA-8AF5-069EA3ADFEB8} + EndGlobalSection +EndGlobal diff --git a/samples/angular/MusicStore/MusicStore.xproj b/samples/angular/MusicStore/MusicStore.xproj new file mode 100644 index 0000000..b4d622b --- /dev/null +++ b/samples/angular/MusicStore/MusicStore.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 1a74148f-9dc0-435d-b5ac-7d1b0d3d5e0b + MusicStore + ..\artifacts\obj\$(MSBuildProjectName) + ..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + 5068 + + + \ No newline at end of file diff --git a/samples/angular/MusicStore/wwwroot/web.config b/samples/angular/MusicStore/wwwroot/web.config index db6e6f4..f51dd9a 100644 --- a/samples/angular/MusicStore/wwwroot/web.config +++ b/samples/angular/MusicStore/wwwroot/web.config @@ -1,9 +1,9 @@ - + - + - + - + \ No newline at end of file diff --git a/samples/misc/ES2015Transpilation/ES2015Transpilation.xproj b/samples/misc/ES2015Transpilation/ES2015Transpilation.xproj new file mode 100644 index 0000000..7b9d1f7 --- /dev/null +++ b/samples/misc/ES2015Transpilation/ES2015Transpilation.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 6d4bcdd6-7951-449b-be55-cb7f014b7430 + ES2015Transpilation + ..\..\..\NodeServices.sln\artifacts\obj\$(MSBuildProjectName) + ..\..\..\NodeServices.sln\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + 2018 + + + \ No newline at end of file diff --git a/samples/misc/ES2015Transpilation/Startup.cs b/samples/misc/ES2015Transpilation/Startup.cs index a95bd1a..80e7e5f 100755 --- a/samples/misc/ES2015Transpilation/Startup.cs +++ b/samples/misc/ES2015Transpilation/Startup.cs @@ -63,7 +63,7 @@ namespace ES2015Example if (requestPath.StartsWith("/js/") && requestPath.EndsWith(".js")) { var fileInfo = env.WebRootFileProvider.GetFileInfo(requestPath); if (fileInfo.Exists) { - var transpiled = await nodeServices.Invoke("transpilation.js", fileInfo.PhysicalPath, requestPath); + var transpiled = await nodeServices.Invoke("transpilation.js", fileInfo.PhysicalPath, requestPath); await context.Response.WriteAsync(transpiled); return; } diff --git a/samples/misc/ES2015Transpilation/wwwroot/web.config b/samples/misc/ES2015Transpilation/wwwroot/web.config index db6e6f4..f51dd9a 100644 --- a/samples/misc/ES2015Transpilation/wwwroot/web.config +++ b/samples/misc/ES2015Transpilation/wwwroot/web.config @@ -1,9 +1,9 @@ - + - + - + - + \ No newline at end of file diff --git a/samples/react/ReactGrid/ReactGrid.xproj b/samples/react/ReactGrid/ReactGrid.xproj new file mode 100644 index 0000000..d2d598c --- /dev/null +++ b/samples/react/ReactGrid/ReactGrid.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + abf90a5b-f4e0-438c-a6e4-9549fb43690b + ReactGrid + ..\..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + 2311 + + + \ No newline at end of file