I am using PythonNet 3.0.1 in my .Net Core 6C# project. Need is to call a .py file and process a csv and read the results back in C#. Have installed Python 3.11.4 on my machine as well as pandas library.
Now when I call the Api Code, it gives an error whenever I try to call the Api method more than once.
I have added a finally block with the following statement: PythonEngine.Shutdown()
The exception logged on console is:
System.NotSupportedException: BinaryFormatter serialization and deserialization are disabled within this application. See https://aka.ms/binaryformatter for more information.
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
at Python.Runtime.RuntimeData.Stash()
at Python.Runtime.Runtime.Shutdown()
at Python.Runtime.PythonEngine.Shutdown()
How do I fix this error and ensure that the Api can be called more than once?
here is the Code I have in the C# class:
string fileLoc = AppDomain.CurrentDomain.BaseDirectory;
try
{
Runtime.PythonDLL = "python311.dll";
// Initialize the Python engine
PythonEngine.Initialize();
using (Py.GIL())
{
dynamic module = Py.Import("PythonSampleIronPython");
dynamic result = module.calculator.xl2determination(fileLoc);
}
return new Audit();
}
catch (Exception err)
{
_logger.LogError("Unable to evaluate model", err);
throw new Exception("Unable to evaluate model", err);
}
finally{
PythonEngine.Shutdown();
}
I did not find much help using Pythonnet. So appreciate any help from people using Pythonnet with C#
Here is the Python Code saved in file "PythonSampleIronPython.py".
class calculator: def add(x, y): return x + y def increment(x): x += 1 return x
I got this to work by intializing the PythonEngine
on startup in Program.cs
:
Environment.SetEnvironmentVariable("PYTHONNET_PYDLL", "path to python dll");
PythonEngine.PythonHome = "Path to Python installation";
PythonEngine.Initialize();
PythonEngine.BeginAllowThreads();
Then you can test it by using something like this:
using (Py.GIL())
{
PythonEngine.Exec("print('Hello from Python')")
}
This solution doesn't require you to call PrintEngine.Shutdown()
since it's running for the lifecycle of the application.
Using the github solution provided in the other answer:
I created a new class NoopFormatter
that inherits from IFormatter
:
using System.Runtime.Serialization;
namespace YourNameSpace;
public class NoopFormatter : IFormatter
{
public object Deserialize(Stream s) => throw new NotImplementedException();
public void Serialize(Stream s, object o) { }
public SerializationBinder Binder { get; set; }
public StreamingContext Context { get; set; }
public ISurrogateSelector SurrogateSelector { get; set; }
}
Then in my class where I'm using the Python.Runtime
I added this line before PythonEngine.Initialize()
Python.Runtime.RuntimeData.FormatterType = typeof(NoopFormatter);
This allowed PrintEngine.ShutDown()
to execute without throwing the BinaryFormatter serialization exception.
Note: Depending on the use of threading in your application you may need to include PythonEngine.BeginAllowThreads()
after you call PythonEngine.Initialize();
This fixed the issue of it locking up on using (Py.GIL())
when hitting the code a second time.