18

I have some code written in Python which can not be transferred to a .NET language. I need to call one of these functions from my .NET WinForms application.

Now, I do it by starting the Python script as a separate process and pass parameters to it as command line arguments. It works, but I don't really like this solution. I'd like to improve it to a better one.

Is there any better way to call a function of a .py script from a .NET application? What is the best way to do it?

Note: IronPython is NOT an option for this Python script

denfromufa
  • 5,610
  • 13
  • 81
  • 138
Tom
  • 3,899
  • 22
  • 78
  • 137
  • 1
    "don't really like this solution" Why not? It works. It's simple and reliable. What's wrong with it? – S.Lott Jul 08 '11 at 12:39
  • 4
    @S.Lott: It's not quite "enterprisy" enough. – Roman Jul 08 '11 at 12:39
  • 2
    Thx for your comment. Starting a process only for calling a function is not the best thing Also when pc is heavily used, starting a new process can take a while (This script is used heavily - 3-5 times a minute whan my app is running and important to be very fast). Installing my app is heavier: python is required on target machines beside .net, installing it not trivial for a regular user. So, for me it is not simple and not a good one. – Tom Jul 08 '11 at 12:44
  • 1
    @Tom: Why aren't you using Pipes to pass data into a Python process? – S.Lott Jul 08 '11 at 13:56

6 Answers6

10

This might be a lot more work than launching the Python process, but here's an alternate solution.

You can embed Python into another program. The API is for C and Interop from .NET will probably be a major pain. If you're into a bit of a safer way to handle the native Python API, you can look into Boost.Python, which, among its less advertised features, has support for embedding.

With these tools, you can write a C++ managed DLL that uses Boost.Python to load the Python interpreter and execute any Python script. Thus, you can execute any Python code directly in the hosting process, eliminating the use of an external process and any form of IPC.

Edit: AFAIK, all you have to add to your installation procedure is the deployment of the Python DLL and Boost.Python DLL.

André Caron
  • 44,541
  • 12
  • 67
  • 125
5

I think you need to re-evaluate Carlos' answer. See the section Implementing COM Objects with Python in Mark Hammond's book Python Programming on Win32.

You should be able to create a COM object, then have .Net interact with it.

From the book the following will create a COM server with a single method.

# SimpleCOMServer.py - A sample COM server - almost as small as they come!
# 
# We expose a single method in a Python COM object.
class PythonUtilities:
    _public_methods_ = [ 'SplitString' ]
    _reg_progid_ = "PythonDemos.Utilities"
    # NEVER copy the following ID 
    # Use "print pythoncom.CreateGuid()" to make a new one.
    _reg_clsid_ = "{41E24E95-D45A-11D2-852C-204C4F4F5020}"

    def SplitString(self, val, item=None):
        import string
        if item != None: item = str(item)
        return string.split(str(val), item)

# Add code so that when this script is run by
# Python.exe, it self-registers.
if __name__=='__main__':
    print "Registering COM server..."
    import win32com.server.register
    win32com.server.register.UseCommandLine(PythonUtilities)

The book goes on to say ".. you can do this by executing the code as a normal Python script. The easiest way to do this is to open the source file in PythonWin and use the Run command from the File menu. "

I think you need the ActivePython distribution from Activestate to do it.

See this question Consuming Python COM Server from .NET

Community
  • 1
  • 1
CarbonMan
  • 4,350
  • 12
  • 54
  • 75
5

Besides the COM option, you could make your Python script instantiate a xmlrpc server - it is quite transparent and you never have to deal with "xml" on your own code.

Then, on .net side, you simply connect to your python app via xmlrpc - if there is no suitable way to do that in C#, just write a client function in IronPython.

The SimpleXMLRPCServer example on Python documentation is enough for that:

http://docs.python.org/library/simplexmlrpcserver.html

jsbueno
  • 99,910
  • 10
  • 151
  • 209
3

PythonNet should help with this one. It enables you to call python code from C#.

A cleaner way is to expose the python script via a Flask REST API and consume that from your .NET Application. Don't forget to put proper authentication in place.

MovGP0
  • 7,267
  • 3
  • 49
  • 42
3

It works, but I don't really like this solution, I'd like to improve it to a better one.

No, AFAIK there isn't a better solution, especially if IronPython is a no-no for you. So you could still keep this as a temporary workaround while waiting for the script to be migrated to .NET or until you find that someone already wrote a library on .NET that provides you with similar functionality.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Sad news. Thx for all answers from everybody, but as I see there is no effecient, widely used way to do it. – Tom Jul 08 '11 at 14:29
  • 2
    @Darin Dimitrov, I recommend looking at Python.NET (Python for .NET) and maybe you can re-consider your answer. – denfromufa Jan 12 '15 at 03:21
3

Create a COM .dll from a .py script and use Interop in your .NET code. Have a look here: http://docs.python.org/faq/windows.html

Carlos Quintanilla
  • 12,937
  • 3
  • 22
  • 25
  • 3
    At first I thought you meant that the Python interpreter is available as a COM object, but the page you linked to says nothing about COM. So it sounds like your answer is actually about *writing your own* COM object, and rolling all the associated infrastructure. – Joe White Jul 08 '11 at 13:15