Trying to automatically rebuild and restart .NET console application on linux - c#

I'm making a small webserver .NET console application on my windows machine that will run on a linux server (amazon os), and I'd like to make it automatically update itself when I push new code to github.
Automatically pulling from github already works by waiting for a webhook and then creating a Process which, as I understand it, practically lets me run a command line from the code.
using System.Diagnostics;
public static class GitApi
{
public static void Pull(string path)
{
Process process = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = "git",
Arguments = "pull",
UseShellExecute = false,
RedirectStandardOutput = true,
WorkingDirectory = path
}
};
process.Start();
}
}
What I'd then like to do is to automatically rebuild and restart after pulling from git, by using the dotnet run command in a similar way.
using System.Diagnostics;
public static class Restarter
{
public static void Restart(string path)
{
Process process = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = "dotnet",
Arguments = "run",
UseShellExecute = false,
WorkingDirectory = path
}
};
process.Start();
Environment.Exit(0);
}
}
While this seems to work fine on windows, when I try on linux it seems to exit the main process and then start the new one in the background somehow. It still writes in the same screen, but I can't kill it with Ctrl + C. Instead I have to find the process by checking the port that it's using and then use the kill command.
Could I fix this somehow or is there another simple way to rebuild and restart a .NET console application?

Related

Common usage of static array in two different console applications

I've got a problem with a .NET Core 2.2 console application.
I want to start an console app with an static array. This one connects to an TCP/IP partner.
On start up, I start an second console application, which should use the same static array, and the same connection as the first console application.
I want to split both apps, cause it is an 'option package'. Both apps are running as background services with timed async functions.
Both apps share the same namespace and are configured in the same project.
The child app have an dependency of the parent app.
Until now, I can start both apps in the same console (as child-process), but the child-console can't use the static array.
How can I solve it?
Here is my Program.cs Main Method:
static async Task Main(string[] args) {
Portal_Connect.PLC = new Class_PLC[11];
if ((Configuration.Diagnostic))
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "dotnet ",
Arguments = Directory.GetCurrentDirectory() + \\Diagnostic.dll",
WorkingDirectory = Directory.GetCurrentDirectory(),
UseShellExecute = false,
RedirectStandardOutput = false,
RedirectStandardError = false,
CreateNoWindow = false
}
};
process.Start();
process.PriorityClass = ProcessPriorityClass.High;
process.ProcessorAffinity = (IntPtr)6;
}
}

Log file is not created for console application if it is called through Process in C#

I have two applications: one WPF and one console application.
On both applications I installed log4net libraries (same version) but with separate logging.config files for each application, and they are initialized like:
for WPF (App.xaml.cs):
protected override void OnStartup(StartupEventArgs e)
{
var repo = LogManager.CreateRepository(Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy));
log4net.Config.XmlConfigurator.Configure(repo, new FileInfo("logging.config"));
base.OnStartup(e);
}
logging.config stores log file as wpf_debug.log.
for Console:
static void Main(string[] args)
{
var repo = LogManager.CreateRepository(Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy));
log4net.Config.XmlConfigurator.Configure(repo, new FileInfo("logging.config"));
}
logging.config stores log file as console_debug.log.
Ok then, if I run from WPF application a process
var startInfo = new ProcessStartInfo();
startInfo.FileName = "PathToConsoleExe";
...
using (Process pr = new Process())
{
pr.StartInfo = startInfo;
pr.Start();
pr.WaitForExit();
}
The problem is that I don't see any .log file for console application. I don't know why. Only for WPF, the logs are created fine.
If I run console app through command prompt, it works fine.
My guess is that it tries to load the logging.config file from the wrong folder. Try setting the startInfo.WorkingDirectory property before starting the process

Run bat file with UWP C#

I'm trying to build UWP app and I'm struggling with an issue:
I have noticed there is now way to launch external executable, but I can open file with its default application using LaunchFile (Like mentioned here https://learn.microsoft.com/en-us/uwp/api/Windows.System.Launcher#Windows_System_Launcher_LaunchFileAsync_Windows_Storage_IStorageFile_).
Should it work for a .bat file too? Where should i place the .bat file if it is.? Because i tried to give a path to a .bat file i wrote and I got an exception.
Thanks!!
Its not going to work. If you can get some 3rd party application to open and handle bat files by default then maybe, but otherwise nothing the OS handles like cmd or vbscript will run. Not sure what your goal is, but a 3rd party scripting app like Autohotkey does work.
From .NET 4 there is and Process and ProcessStartInfo
classes under the System.Diagnostics namespace which allow you
to Win32 applications from C#.
public static Task<bool> ExecuteBatchFile(string BatchFilePath, string BatchFileDirectory)
{
try
{
Task<bool> executeBatchFileTask = Task.Run<bool>(() =>
{
bool hasProcessExited = false;
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = BatchFilePath,
CreateNoWindow = false,
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Normal,
WorkingDirectory = BatchFileDirectory
};
// Start the process with the info we specified.
// Call WaitForExit and then the using-statement will close.
using (System.Diagnostics.Process exeProcess = System.Diagnostics.Process.Start(startInfo))
{
while (!exeProcess.HasExited)
{
//Do nothing
}
hasProcessExited = true;
}
return hasProcessExited;
});
return executeBatchFileTask;
}
catch (Exception ex)
{
throw;
}
}
And call this method in your code by:
bool hasBatchFileExecuted = await ExecuteBatchFile(BatchFilePath, BatchFilePathDirectory);
Create your own batch file like:
1) Create a text file in notepad and save it as run.bat under save as category and all files.
2) Write the following code to execute a C# program/However you can write your own commands also:
csc someRandomCode.cs
pause
3) Save and quit.

Embed Python in C# Windows Application [duplicate]

This sort of question has been asked before in varying degrees, but I feel it has not been answered in a concise way and so I ask it again.
I want to run a script in Python. Let's say it's this:
if __name__ == '__main__':
with open(sys.argv[1], 'r') as f:
s = f.read()
print s
Which gets a file location, reads it, then prints its contents. Not so complicated.
Okay, so how do I run this in C#?
This is what I have now:
private void run_cmd(string cmd, string args)
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = cmd;
start.Arguments = args;
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
Console.Write(result);
}
}
}
When I pass the code.py location as cmd and the filename location as args it doesn't work. I was told I should pass python.exe as the cmd, and then code.py filename as the args.
I have been looking for a while now and can only find people suggesting to use IronPython or such. But there must be a way to call a Python script from C#.
Some clarification:
I need to run it from C#, I need to capture the output, and I can't use IronPython or anything else. Whatever hack you have will be fine.
P.S.: The actual Python code I'm running is much more complex than this, and it returns output which I need in C#, and the C# code will be constantly calling the Python code.
Pretend this is my code:
private void get_vals()
{
for (int i = 0; i < 100; i++)
{
run_cmd("code.py", i);
}
}
The reason it isn't working is because you have UseShellExecute = false.
If you don't use the shell, you will have to supply the complete path to the python executable as FileName, and build the Arguments string to supply both your script and the file you want to read.
Also note, that you can't RedirectStandardOutput unless UseShellExecute = false.
I'm not quite sure how the argument string should be formatted for python, but you will need something like this:
private void run_cmd(string cmd, string args)
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "my/full/path/to/python.exe";
start.Arguments = string.Format("{0} {1}", cmd, args);
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using(Process process = Process.Start(start))
{
using(StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
Console.Write(result);
}
}
}
If you're willing to use IronPython, you can execute scripts directly in C#:
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
private static void doPython()
{
ScriptEngine engine = Python.CreateEngine();
engine.ExecuteFile(#"test.py");
}
Get IronPython here.
Execute Python script from C
Create a C# project and write the following code.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
run_cmd();
}
private void run_cmd()
{
string fileName = #"C:\sample_script.py";
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"C:\Python27\python.exe", fileName)
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);
Console.ReadLine();
}
}
}
Python sample_script
print "Python C# Test"
You will see the 'Python C# Test' in the console of C#.
I ran into the same problem and Master Morality's answer didn't do it for me. The following, which is based on the previous answer, worked:
private void run_cmd(string cmd, string args)
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = cmd;//cmd is full path to python.exe
start.Arguments = args;//args is path to .py file and any cmd line args
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using(Process process = Process.Start(start))
{
using(StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
Console.Write(result);
}
}
}
As an example, cmd would be #C:/Python26/python.exe and args would be C://Python26//test.py 100 if you wanted to execute test.py with cmd line argument 100. Note that the path the .py file does not have the # symbol.
Actually its pretty easy to make integration between Csharp (VS) and Python with IronPython. It's not that much complex... As Chris Dunaway already said in answer section I started to build this inegration for my own project. N its pretty simple.
Just follow these steps N you will get your results.
step 1 : Open VS and create new empty ConsoleApp project.
step 2 : Go to tools --> NuGet Package Manager --> Package Manager Console.
step 3 : After this open this link in your browser and copy the NuGet Command.
Link: https://www.nuget.org/packages/IronPython/2.7.9
step 4 : After opening the above link copy the PM>Install-Package IronPython -Version 2.7.9
command and paste it in NuGet Console in VS.
It will install the supportive packages.
step 5 : This is my code that I have used to run a .py file stored in my Python.exe
directory.
using IronPython.Hosting;//for DLHE
using Microsoft.Scripting.Hosting;//provides scripting abilities comparable to batch files
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
class Hi
{
private static void Main(string []args)
{
Process process = new Process(); //to make a process call
ScriptEngine engine = Python.CreateEngine(); //For Engine to initiate the script
engine.ExecuteFile(#"C:\Users\daulmalik\AppData\Local\Programs\Python\Python37\p1.py");//Path of my .py file that I would like to see running in console after running my .cs file from VS.//process.StandardInput.Flush();
process.StandardInput.Close();//to close
process.WaitForExit();//to hold the process i.e. cmd screen as output
}
}
step 6 : save and execute the code
Set WorkingDirectory or specify the full path of the python script in the Argument
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "C:\\Python27\\python.exe";
//start.WorkingDirectory = #"D:\script";
start.Arguments = string.Format("D:\\script\\test.py -a {0} -b {1} ", "some param", "some other param");
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
Console.Write(result);
}
}
I am having problems with stdin/stout - when payload size exceeds several kilobytes it hangs. I need to call Python functions not only with some short arguments, but with a custom payload that could be big.
A while ago, I wrote a virtual actor library that allows to distribute task on different machines via Redis. To call Python code, I added functionality to listen for messages from Python, process them and return results back to .NET.
Here is a brief description of how it works.
It works on a single machine as well, but requires a Redis instance. Redis adds some reliability guarantees - payload is stored until a worked acknowledges completion. If a worked dies, the payload is returned to a job queue and then is reprocessed by another worker.
had same issure and this worked for me:
using IronPython.Hosting;
var engine = Python.CreateEngine();
engine.ExecuteFile("") //put the directory of the program in the quote marks

How to Schedule a Process.Start in WPF

I am trying to restart an application in WPF.
I tried the following:
Process.Start(Application.ExecutablePath);
Process.GetCurrentProcess().Kill();
And it doesn't work because the application is setup as a single instances application.
Then I tired this:
Process.GetCurrentProcess().Kill();
Process.Start(Application.ExecutablePath);
And it doesn't work because once we Kill the process it will not hit line 2
Is there a way to schedule a the .Start so that I don't run into issue #1.
You could launch a secondary application that would then re-launch your main program after the delay. When I wrote a self-updater a few years ago, that was the implementation path that I took. It was just a simple program that took the executable as a command line arg, would sleep for a tenth of a second, then .Start it.
A better implementation path than I took would be to have the newly-launched program wait for the process that launched it to terminate. Waiting the arbitrary length of time could complicate matters. In order to accomplish this, I would probably pass the process ID to the re-launcher so that it would know exactly which process to wait on.
It's not as hard as you think. All you need to do is call the following method, passing in the command line for the restarted instance:
public static void RestartMe(string commandLine)
{
var myId = Process.GetCurrentProcess().Id;
var myPath = Assembly.GetEntryAssembly().CodeBase.Replace("file:///", "");
var systemPath = typeof(object).Assembly.CodeBase.Replace("file:///", "");
var tempPath = Path.GetTempFileName();
File.WriteAllText(tempPath + ".cs", #"
using System;
using System.Diagnostics;
public class App
{
public static void Main(string[] args)
{
try { Process.GetProcessById(" + myId + #").WaitForExit(); } catch {}
Process.Start(""" + myPath + #""", Environment.CommandLine);
}
}");
var compiler = new ProcessStartInfo
{
FileName = Path.Combine(Path.GetDirectoryName(systemPath), "csc.exe"),
Arguments = tempPath + ".cs",
WorkingDirectory = Path.GetDirectoryName(tempPath),
WindowStyle = ProcessWindowStyle.Hidden,
};
var restarter = new ProcessStartInfo
{
FileName = tempPath + ".exe",
Arguments = commandLine,
WindowStyle = ProcessWindowStyle.Hidden,
};
Process.Start(compiler).WaitForExit();
Process.Start(restarter); // No WaitForExit: restarter WaitForExits us instead
File.Delete(tempPath);
File.Delete(tempPath + ".cs");
Environment.Exit(0);
}
How it works: This actually does create another "restarter" program but does it painlessly and automatically. The restarter program has the current process id and the executable filename built right into it. It will always find the compiler because NET Framework version ships with a compatible csc.exe in the same folder as System.dll.

Categories

Resources