Comments (7)
Hey! We got a direct email on this issue 3 weeks back. Out of curiosity, was that you? Asking to ascertain if this is the second occurrence of this issue. That would strongly suggest the problem is with our library. The console window should not open.
Anyway I was unable to reproduce the problem that time. Is it possible for you to create a minimal reproduction?
So create a new project with the same configuration as yours and call InvokeFromFileAsync
on a dummy js file. Then push the repro to Github.
Would be more than happy to look at it and figure this out.
from javascript.nodejs.
No the email wasn't me, I'll let you know when I get a sample repo up to more easily showcase the problem.
Thank you for the quick response!
from javascript.nodejs.
After some digging, I think the following change to this library may fix the issue:
Changed to:
var startInfo = new ProcessStartInfo("node")
{
Arguments = $"{_nodeJSProcessOptions.NodeAndV8Options} -e \"{nodeServerScript}\" -- --parentPid {currentProcessPid} --port {_nodeJSProcessOptions.Port}",
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
WorkingDirectory = _nodeJSProcessOptions.ProjectPath,
/*** Possible solution for console window issue ***/
CreateNoWindow = true
};
Not 100% sure if this fixes the issue, but worth trying. If you could test it out I'd appreciate it. Steps:
-
Add the following
CustomNodeJSProcessFactory.cs
file to your project. It's identical to the original class that creates NodeJS processes except it sets the property mentioned above. You might have to add several packages to your project temporarily and you'll have to enter your namespace:using Jering.Javascript.NodeJS; using Microsoft.Extensions.Options; using System; using System.Diagnostics; using System.Text; namespace <your namespace> { /// <summary> /// Custom <see cref="INodeJSProcessFactory"/> implementation. /// </summary> public class CustomNodeJSProcessFactory : INodeJSProcessFactory { private readonly NodeJSProcessOptions _nodeJSProcessOptions; /// <summary> /// Creates a <see cref="NodeJSProcessFactory"/>. /// </summary> /// <param name="optionsAccessor"></param> public CustomNodeJSProcessFactory(IOptions<NodeJSProcessOptions> optionsAccessor) { _nodeJSProcessOptions = optionsAccessor?.Value ?? new NodeJSProcessOptions(); } /// <inheritdoc /> public INodeJSProcess Create(string serverScript) { Console.WriteLine("Creating process using custom NodeJSProcessFactory"); ProcessStartInfo startInfo = CreateStartInfo(serverScript); return new NodeJSProcess(CreateProcess(startInfo)); } internal ProcessStartInfo CreateStartInfo(string nodeServerScript) { nodeServerScript = EscapeCommandLineArg(nodeServerScript); // TODO can we escape before embedding? Would avoid an allocation every time we start a NodeJS process. int currentProcessPid = Process.GetCurrentProcess().Id; var startInfo = new ProcessStartInfo("node") { Arguments = $"{_nodeJSProcessOptions.NodeAndV8Options} -e \"{nodeServerScript}\" -- --parentPid {currentProcessPid} --port {_nodeJSProcessOptions.Port}", UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, WorkingDirectory = _nodeJSProcessOptions.ProjectPath, /*** Possible solution for console window issue ***/ CreateNoWindow = true }; // Append environment Variables if (_nodeJSProcessOptions.EnvironmentVariables != null) { foreach (var envVarKey in _nodeJSProcessOptions.EnvironmentVariables.Keys) { string envVarValue = _nodeJSProcessOptions.EnvironmentVariables[envVarKey]; if (envVarValue != null) { startInfo.Environment[envVarKey] = envVarValue; } } } return startInfo; } internal Process CreateProcess(ProcessStartInfo startInfo) { try { Process process = Process.Start(startInfo); // On Mac at least, a killed child process is left open as a zombie until the parent // captures its exit code. We don't need the exit code for this process, and don't want // to use process.WaitForExit() explicitly (we'd have to block the thread until it really // has exited), but we don't want to leave zombies lying around either. It's sufficient // to use process.EnableRaisingEvents so that .NET will grab the exit code and let the // zombie be cleaned away without having to block our thread. process.EnableRaisingEvents = true; return process; } catch (Exception exception) { throw new InvalidOperationException("Failed to start NodeJS process", exception); } } internal string EscapeCommandLineArg(string arg) { var stringBuilder = new StringBuilder(); int slashSequenceLength = 0; for (int i = 0; i < arg.Length; i++) { char currentChar = arg[i]; if (currentChar == '\\') { slashSequenceLength++; // If the last character in the argument is \, it must be escaped, together with any \ that immediately preceed it. // This prevents situations like: SomeExecutable.exe "SomeArg\", where the quote meant to demarcate the end of the // argument gets escaped. if (i == arg.Length - 1) { for (int j = 0; j < slashSequenceLength; j++) { stringBuilder. Append('\\'). Append('\\'); } } } else if (currentChar == '"') { // Every \ or sequence of \ that preceed a " must be escaped. for (int j = 0; j < slashSequenceLength; j++) { stringBuilder. Append('\\'). Append('\\'); } slashSequenceLength = 0; stringBuilder. Append('\\'). Append('"'); } else { for (int j = 0; j < slashSequenceLength; j++) { stringBuilder.Append('\\'); } slashSequenceLength = 0; stringBuilder.Append(currentChar); } } return stringBuilder.ToString(); } } }
-
When you add
Jering.Javascript.NodeJS
to your services, overwrite the defaultINodeJSProcessFactory
service:ServiceCollection services = new ServiceCollection(); services.AddNodeJS(); // Override the default service services.AddSingleton<INodeJSProcessFactory, CustomNodeJSProcessFactory>();
If you're using the static API you'd do it like this:
ServiceCollection services = new ServiceCollection(); services.AddNodeJS(); // Override the default service services.AddSingleton<INodeJSProcessFactory, CustomNodeJSProcessFactory>(); StaticNodeJSService.SetServices(services); // Subsequent calls to the static API will use CustomNodeJSProcessFactory
Let me know if this fixes the issue. If it does there's no need for a repro!
from javascript.nodejs.
Just got back to this, have not tried it out yet but just set up a sample repo. I will look to see if this fixes it but for now here's the sample repo. https://github.com/hansooms999/JeringConsoleSample/
I'll let you know if the issue is fixed. Thank you!
from javascript.nodejs.
Just tested your repro with the fix and it works properly now! Will publish a new version of Jering.Javascript.NodeJS
today.
from javascript.nodejs.
@hansooms999 Fixed version: 5.4.4 🎉. Thanks for reporting the issue. Let me know if you have any trouble with the new version.
from javascript.nodejs.
@JeremyTCD This fixed the issue perfectly. Thanks for your help! 🎉
from javascript.nodejs.
Related Issues (20)
- Call the same instance?
- Has anyone used this with React/JSX?
- Facing issue with Jering.Javascript.NodeJS HOT 2
- Next.JS instead of Node.js
- Microsoft.AspNetCore.Hosting.Abstractions is obsolete HOT 2
- Delayed FileWatching: Maybe a OutOfProcessNodeJSServiceOptions property? HOT 2
- Suitable constructor for Jering.Javascript.NodeJS.HttpClientService Exception HOT 2
- NodeJS server is not recognised when invoked HOT 15
- Jering.Javascript.NodeJS.HttpNodeJSService[0]. An invocation attempt failed
- running the cypress via node in C# giving error "Could not find Cypress test run results" HOT 1
- Exception: "The semaphore has been disposed" on release 7.0.0 HOT 2
- ConnectionException: Process with ID 83312 exited before connecting. HOT 28
- Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.. HOT 1
- require cache update, concurrent problem HOT 2
- Only URLs with a scheme in: file, data, and node are supported by the default ESM loader. HOT 4
- InvocationException: Unexpected reserved word HOT 3
- SocketException - An existing connection was forcibly closed by the remote host HOT 1
- Jering.Javascript.NodeJS.InvocationException - resolvedPath.replaceAll is not a function HOT 3
- Similar to Microsoft/node-api-dotnet project?
- InvokeExportAsync?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from javascript.nodejs.