I've been struggling with this for a few days, and can't seem to get a straight-forward way of achieving this. I don't have too much experience with .Net and Mono, but enough to be able to build an application.

The problem i'm having is that i want to write a c# application, and run python processes in the background. These python processes also have imports, and thus i need to be able to run them in their anaconda environment.

I've read and experimented with IronPython and PythonNet, but have had only limited success. As IronPython is in fact capable of running my python scripts, it can't find the imports. Pythonnet on the other hand has been a pain in the *** as i can't seem to be able to get it running, neither by installing from Nuget, nor Anaconda, nor building from source. I believe pythonNet would be best for achieving this, but have been unable to get it to work, since the setup always complains about my .Net version, or my mono application using Python.Runtime cannot find the right python installation.

I'm using an Anaconda2 (local installation) on an Ubuntu 18.04 64bit machine with monodevelop/visual studio code. Just to be clear, i have in fact looked for solutions on both stackexchange, as the pythonnet github pages.

2

There are 2 answers

5
Spixy On BEST ANSWER

I didnt work with *conda so much but I have two ideas:

  1. write your python programs in a way that you just launch them with some arguments and wait for their results:

    string progToRun = "C:\\Dev\\hello.py";
    int param1 = 42; float param2 = 0.25f;
    
    Process proc = new Process();
    proc.StartInfo.FileName = "python.exe";
    proc.StartInfo.RedirectStandardOutput = true;
    proc.StartInfo.UseShellExecute = false;
    proc.StartInfo.Arguments = string.Concat(progToRun, " ", param1.ToString(), " ", param2.ToString());
    proc.Start();
    
    StreamReader sReader = proc.StandardOutput;
    string[] output = sReader.ReadToEnd().Split({'\r'});
    
    foreach (string s in output)
        Console.WriteLine(s);
    
    proc.WaitForExit();
    
  2. there is new ML.NET machine learning framework from Microsoft, so you can check it

  3. edit: as Steve said, instead of stdout you can use also sockets, if you want to use it interactively

0
Glenn van Acker On

Allthough the above answer is what i was looking for in the first place, i found out another way to achieve this, and thought it was a good idea to post it here as an alternative way: It's possible to use the OutputDataReceived event from the process class, and have it invoke a method. This way you can trigger multiple method eachs time the the python process outputs something to it's console or stdout. usage:

proc.OutputDataReceived += OnOutputDataReceived

the OnOutputDataReceived is a method with an eventhandler signature, thus taking a sender, and EventArgs parameter. You could add multiple methods, or raise another event in the OnOutputDataReceived method with a custom EventArgs object, and handle the output from the process in several ways. i.e. A logger.

private void OnOutputDataReceived(sender e, EventArgs args) 
{
    Console.WriteLine(args.Data);
    using(Logger){
        Logger.log("python output: "+args.Data);
    }
}

the event will trigger whenever something is written to the python output stream, and can be used throughout the assembly, causing it to be losely coupled to the process itself.