Using Command line application with my asp.net application - c#

I doing my final year project by implementing learning web application using ASP.NET Core
however, in some page i need the user to interact with some command line application where these commands need to be sent based on the given output from the command line application. I have no issue with sending on command, but when it comes to the second command i got several issues. here is the code
public static Process process = new Process()
{
StartInfo = new ProcessStartInfo
FileName = "cmd",
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
This is my definition for my process i have created outside the function because i do need to use the same process several time until the user leave the page.
For the process.Start(); I have putted with the function of viewing the page, so the process is started already and no issue with it.
public IActionResult acceptingInputFromUser(string input)
{
string result;
try
{
StreamWriter sw = process.StandardInput;
StreamReader rd = process.StandardOutput;
using (process.StandardInput)
{
sw.WriteLine(input);
sw.Flush();
sw.Close();
result = process.StandardOutput.ReadToEnd();
}
}catch (Exception ex)
{
result = ex.ToString();
}
return Json(result);
}
Here where is the issue, once the user submit any input the the first time will accept and give the result, however when he send another request it says
Cannot write to a closed TextWriter
I have tried several ways but so far i couldn't find solution. Can anyone help me with this error like how I can open the Textwriter again or if there is any other efficient way to where I can use CMD freely.

Related

Calling WSL bash.exe from C#

Mostly just as a curiosity, I wrote a little app to start up Terminator shell on Windows, using Ubuntu/WSL and Xming window server.
Doing things manually from the shell, I can run Firefox, gedit, Terminator, etc on Windows, it's pretty cool.
So I checked the location of bash.exe using where bash and it returned...
C:\Windows\System32\bash.exe
However when I tried to run this code...
using (var xminProc = new Process())
{
xminProc.StartInfo.FileName = #"C:\Program Files (x86)\Xming\Xming.exe";
xminProc.StartInfo.Arguments = ":0 -clipboard -multiwindow";
xminProc.StartInfo.CreateNoWindow = true;
xminProc.Start();
}
using (var bashProc = new Process())
{
bashProc.StartInfo.FileName = #"C:\Windows\System32\bash.exe";
bashProc.StartInfo.Arguments = "-c \"export DISPLAY=:0; terminator; \"";
bashProc.StartInfo.CreateNoWindow = true;
bashProc.Start();
}
I get the error...
System.ComponentModel.Win32Exception: 'The system cannot find the file specified'
And checking my entire system for bash.exe reveals it really be in another place altogether...
I'm not sure if this location is one that I can rely on, I'm worried it's ephemeral and can change during a Windows Store update, although I may be wrong about that.
Why does the command prompt show bash.exe to be in System32 but it's really in another location altogether?
Can I get C# to also use the System32 location?
As #Biswapriyo stated first set the platafrom to x64 on your solution:
Then you may run on your ubuntu machine from c# as:
Console.WriteLine("Enter command to execute on your Ubuntu GNU/Linux");
var commandToExecute = Console.ReadLine();
// if command is null use 'ifconfig' for demo purposes
if (string.IsNullOrWhiteSpace(commandToExecute))
{
commandToExecute = "ifconfig";
}
// Execute wsl command:
using (var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = #"cmd.exe",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
CreateNoWindow = true,
}
})
{
proc.Start();
proc.StandardInput.WriteLine("wsl " + commandToExecute);
System.Threading.Thread.Sleep(500); // give some time for command to execute
proc.StandardInput.Flush();
proc.StandardInput.Close();
proc.WaitForExit(5000); // wait up to 5 seconds for command to execute
Console.WriteLine(proc.StandardOutput.ReadToEnd());
Console.ReadLine();
}

How to restart dotnetcore 2 C# Console app

How should I restart a dotnetcore C# console app?
I have tried suggestions found for C# console apps, but doesnt work for dotnetcore.
(This is not asp.net, which is where so many dotnetcore answers point)
OK, so im going to assume in this answer that it is ok with you if your program will start a new instance of your program and then close itself.
Here we go:
Since a dotnet console app can be started from the console, I think the best way to start a new instance of your console application would be thorugh using shell commands. To run shell commands from your program, add this helper class to your application: (If you are using windows instead of mac/linux, please see the end of this post)
using System;
using System.Diagnostics;
public static class ShellHelper
{
public static string Shell(this string cmd)
{
var escapedArgs = cmd.Replace("\"", "\\\"");
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"-c \"{escapedArgs}\"",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return result;
}
}
Then since this is a extension method, just import it and then create a string with the command to restart your app and then use the Shell() method.
So if you are in development and you normally start your app by running dotnet run then make sure you are in the proper directory and then just use this line of code "dotnet run".Shell();
If you want to get the feedback from running the command then just assign the return value like this string result = "dotnet run".Shell();
Then once you have started the new process you just exit your current program by either returning on your main method etc.
Please Note: The above code is for mac/linux, If you are on windows, then the following two lines of the above code:
FileName = "/bin/bash",
Arguments = $"-c \"{escapedArgs}\"",
Should be replaced with:
FileName = "cmd.exe",
Arguments = $"/c \"{escapedArgs}\"",

Azure App Service, run a native EXE to convert a file

I have a native EXE that converts a file based on command line arguments. Provided, I know how to give full path names of the input and output files, can I run such an EXE from my app service when some button is pressed and wait till the output file is created? Converting to DLL is not an option.
As far as I know, we could run a native exe in the azure app service.
But we couldn't directly pass the parameter to the native exe.
You need write a web application or something else for the user to type in the input parameter.
Then you could use Process.Start method to run the exe.
About how to do it , you could refer to this code sample.
I use ASP.NET MVC to get the input parameter then send the parameter to the exe and get the result.
public ActionResult Index()
{
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = Server.MapPath("/exe/Sum.exe"),
//Arguments could be replaced
Arguments = "1 2",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
// do something with line
Response.Write( " The result is : " + line);
}
//await getResultAsync();
return View();
}
Result:

Output data is not full

I need some help. I have a external app (test.exe with some dll files). In cmd i have run command like this: test.exe parmeters and get a lot of data with some needed info.
I have write app which execute this external app and output is not fully as I exec it with cmd. It's just some firstly lines. I don't mind whats wrong. Please help
using(var process = new Process {
StartInfo = new ProcessStartInfo {
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
FileName = orPath,
Arguments = parmeters.ToString(),
}
}) {
process.Start();
process.WaitForExit();
string result = "";
string standard_output;
while ((standard_output = process.StandardOutput.ReadLine()) != null) {
if (standard_output.Contains("xx"))
result = standard_output.Substring(standard_output.Length - 15);
}
Without a concise-but-complete code example that reliably demonstrates the problem, it's hard to say for sure. But it doesn't surprise me that if you try to consume StandardOutput after you have already called WaitForExit(), that not all of the output has been buffered and is available.
Maybe try this instead:
process.Start();
string result = "";
string standard_output;
while ((standard_output = process.StandardOutput.ReadLine())
!= null)
{
if (standard_output.Contains("xx"))
result = standard_output.Substring(
standard_output.Length - 15);
}
Note that I've simply removed the call to WaitForExit(). Reading the StandardOutput TextReader until it returns null will have the same effect as waiting for the end of the process, assuming a normal process (i.e. where the stdout doesn't get closed until the process exits).

How to import large SQL file using mysql.exe through StreamReader -> StandardInput

I have .sql file (550 MB) and I want to import it to running mysql server. I know path to mysql.exe.
My idea is to immitate command line import mysql -u user -ppass db_name < file.sql. This from command line works well (I have set high max_allowed_packet). According to another thread here on Stackoverflow I found this working:
Process process = new Process();
process.StartInfo.FileName = mysqlexepath;
process.StartInfo.Arguments = "-v -u user -ppassworddbname";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
try
{
process.Start();
StreamWriter input = process.StandardInput;
using (StreamReader sr = new StreamReader(sqlfilepath))
{
while ((line = sr.ReadLine()) != null)
{
if (process.HasExited == true)
throw new Exception("DB went away.");
input.WriteLine(line);
input.Flush();
}
}
process.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
I can see how tables are being created in DB. BUT my problem is that in about half the process exits. I was googling for some timeout settings but couldnt find anything.
I also tried to read file first:
var file = FileInfo(sqlfilepath);
StreamReader reader = file.OpenText();
string fileContents = reader.ReadToEnd();
StreamWriter input = process.StandardInput;
input.AutoFlush = true;
input.Write(fileContents);
input.Close();
But I get OutOfMemory exception. So the proper way doesnt lead through string.
I would be very thankful for any advice how to find out where is the problem. I dont even know if its Process timeout or mysql timeout or if the problem is in StreamReader.
I know this isn't a direct answer to your problem, honestly I'm not sure what is wrong with your approach. I can help by sharing how we run very large sql scripts using mysql.exe...
"C:\Program Files (x86)\MySQL\MySQL Server 5.0\bin\mysql.exe" -C -B --password=[password] -P 3306 --user=[username] --host=localhost --database=[database] -e "\. C:\Backups\Mybackup.sql"
Most of these parameters are obvious, connection info, etc.
What isn't obvious is the magical part -e "\. [filename]" the -e parameter specified that mysql should run the following command and exit. The prefix "\. " indicates that an input file should be used and is followed by that file name.
We use this to restore multi-gigabyte databases without issue. So here is the complete 'run a scirpt' with mssql...
public static int RunMySql(string server, int port, string user, string password, string database, string filename)
{
var process = Process.Start(
new ProcessStartInfo
{
FileName = #"C:\Program Files (x86)\MySQL\MySQL Server 5.0\bin\mysql.exe",
Arguments =
String.Format(
"-C -B --host={0} -P {1} --user={2} --password={3} --database={4} -e \"\\. {5}\"",
server, port, user, password, database, filename),
ErrorDialog = false,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
WorkingDirectory = Environment.CurrentDirectory,
}
);
process.OutputDataReceived += (o, e) => Console.Out.WriteLine(e.Data);
process.ErrorDataReceived += (o, e) => Console.Error.WriteLine(e.Data);
// process.Start(); NOTE: NO need to start the process, because Process.Start has already started the process
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.StandardInput.Close();
process.WaitForExit();
return process.ExitCode;
}
I had the same problem and was too stubborn to use the accepted solution, even though it has gone unchallenged for two years. Also, I wanted to import from a .gz without first decompressing it to another file (and didn't want to have to assume a gzip executable was available). So I worked out what was wrong with the original code.
MySQL dump files can have very long lines with no breaks, so my guess is that ReadLine() is filling up a buffer without ever finding a newline character, causing the OutOfMemory exception. So Read() has to be used instead of ReadLine() to avoid this.
The other problem that may occur (which I had) is with binary blobs within a .sql file, which can get messed up by the text re-encoding when moving text strings from a file to stdin, so I've modified the code to avoid using Readers or Writers, instead using bytes and binary.
Here's my solution:
Process process = new Process();
process.StartInfo.FileName = mysqlexepath;
process.StartInfo.Arguments = "-v -u user -ppassworddbname";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
byte[] buffer = new byte[4096];
int count;
try
{
process.Start();
BinaryWriter stdinBinary = new BinaryWriter(process.StandardInput.BaseStream);
Stream fileStream;
if (sqlfilepath.EndsWith(".gz")) {
fileStream = new GZipStream(new FileStream(sqlfilepath, FileMode.Open, FileAccess.Read, FileShare.Read), CompressionMode.Decompress);
} else {
fileStream = new FileStream(sqlfilepath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
using (fileStream)
{
while ((count = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
if (process.HasExited == true)
throw new Exception("DB went away.");
stdinBinary.Write(buffer, 0, count);
stdinBinary.Flush(); // probably not needed
}
}
stdinBinary.Flush();
process.Close();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
I'm importing a 1.1 GB sql.gz database dump (3.5 GB uncompressed) without any problems, but I'd welcome any code improvements.
I have faced so many problems, the issue is not the code, your code is correct, the problem is the limit of virtual memory that the computer does not support working with a file that big on memory per process. The system of Windows processes limits the amount of memory that executes each process to prevent the system crashes.
I do not know the limit because it varies for each computer architecture and the amount of memory, bus, etc. ..
An advice would you from the file, creating tables in sequence, read a piece run, read another run, and so on.
Another idea would be to try to work in parallel on another thread or process, watch this: http://www.codeproject.com/Articles/189374/The-Basics-of-Task-Parallelism-via-C
When debugging .NET application, windbg+SOS is a good tool to choice.
install SOS extension for windbg http://msdn.microsoft.com/en-us/library/bb190764.aspx
start your program by windbg
when exception happens, check the HEAP Objects and CallStack to specific Exception object in HEAP, to find the reason.
http://blogs.msdn.com/b/johan/archive/2007/01/11/i-am-getting-outofmemoryexceptions-how-can-i-troubleshoot-this.aspx
gcroot command can find references to Object in HEAP.
http://blogs.msdn.com/b/tess/archive/2006/01/23/net-memory-leak-case-study-the-event-handlers-that-made-the-memory-baloon.aspx

Categories