1

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.

Glenn van Acker
  • 317
  • 1
  • 14
  • what exactly are you trying to do ?? run python code inside c#? why not just run them separately and find a way to communicate. I.E. socket – Steve May 25 '18 at 19:23
  • that's exactly what i'm looking for :) this is getting answerred soon, just how do those sockets work? – Glenn van Acker May 26 '18 at 12:27

2 Answers2

0

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

Spixy
  • 303
  • 4
  • 11
  • thank you for your quick answer, I indeed think this would be best, but i'm not going to run ML.Net, because i'm on ubuntu atm. Could you change your answer with an example, and maybe a link about how to use those sockets? – Glenn van Acker May 26 '18 at 12:28
  • Also, if you'd know a way to get the correct environment variable for the python path, that would be awesome. i keep getting the wrong results, even when setting the EnvironmentVariableTarget, it gives me the wrong ones with every target – Glenn van Acker May 26 '18 at 14:59
  • never mind the last comment, i found out that monodevelop only loads the right environment variables if run from the command line. i'm hoping that a release build will do this automatically – Glenn van Acker May 26 '18 at 15:28
  • on C# (client) you can use https://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient(v=vs.110).aspx#Examples and for python (server) for example https://gist.github.com/majek/1763628 – Spixy May 27 '18 at 14:47
  • thank you, my python server is running, and i'm learning to make a connection to it's socket in C#. i'm going to mark this as solved because of the great information, and edit my post with the answer as soon as i solve the connection refused problem. I know what the problem is, but just not yet how to solve it. – Glenn van Acker May 28 '18 at 18:48
0

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.

Glenn van Acker
  • 317
  • 1
  • 14