I am creating a web application using ASP NET that runs on Windows Server 2012 using IIS 10. This application exposes a service at www.domain.com/service/execute which uses a python script executed using Python 3.9.13. Below I report the C# and Python code:
main.py
import pprint
pprint.pprint("Hello World!!")
ServiceController.cs
public class ServiceController : Controller {
public IActionResult Execute() {
var FileName = $#"C:\\path\\to\\python.exe";
var Arguments = $#"C:\\path\\to\\main.py";
var processStartInfo = new ProcessStartInfo() {
FileName = FileName,
Arguments = Arguments,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
using(var process = Process.Start(processStartInfo)) {
var taskError = process.StandardError.ReadToEndAsync();
var taskOutput = process.StandardOutput.ReadToEndAsync();
taskError.Wait();
taskOutput.Wait();
var errors = taskError.Result.Trim();
var output = taskOutput.Result.Trim();
return Ok(
$"FileName={FileName}" +
$"\n" +
$"Arguments={Arguments}" +
$"\n" +
$"errors={errors}" +
$"\n" +
$"output={output}"
);
}
}
}
Calling this service I don't get any errors or exceptions but the output is empty:
FileName=C:/path/to/python.exe
Arguments=C:/path/to/main.py
errors=
output=
If in the C# script I insert as Arguments a totally invented path to a non-existent python script I don't get any error/exception and the output is still empty.
I would expect an output like this:
FileName=C:/path/to/python.exe
Arguments=C:/path/to/main.py
errors=
output=Hello World!!
I would like to call a python script in my C# project , I'm using this function to do the job but unfortunately I didn't get any result and the result variable shows always an empty output. I would like to know what's the reason of this
public string RunFromCmd(string rCodeFilePath, string args)
{
string file = rCodeFilePath;
string result = string.Empty;
try
{
var info = new ProcessStartInfo(pythonPath);
info.Arguments = #"C:\Users\MyPc\ExternalScripts\HelloWorld.py" + " " + args;
info.RedirectStandardInput = false;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.CreateNoWindow = true;
using (var proc = new Process())
{
proc.StartInfo = info;
proc.Start();
proc.WaitForExit();
if (proc.ExitCode == 0)
{
result = proc.StandardOutput.ReadToEnd();
}
}
return result;
}
catch (Exception ex)
{
throw new Exception("R Script failed: " + result, ex);
}
}
Click Event ( Calling funtion )
private void Button1_Click(object sender, RoutedEventArgs e)
{
pythonPath = Environment.GetEnvironmentVariable("PYTHON_PATH");
RunFromCmd(pythonPath, "");
}
Python Script :
import sys
def main():
text = "Hello World"
return text
result = main()
I've fixed the issue by setting Copy if newer instead of Do Not Copy to HelloWorld.py Script
I am calling my python file from Windows Service
the code is working fine by itself
and the service works fine too
but when I call the python code from the windows service I get this error
my python code is this
import pyodbc
import pandas as pd
ConnectionString = "Driver={SQL Server};Server=XYZ;Database=ABCD;Trusted_Connection=yes;"
conn = pyodbc.connect(ConnectionString)
df_results = pd.read_sql("EXEC TestService" , conn)
and he is my windows service in c#
Log("In cmd", true);
try
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = PythonPath;
string Script = PythonSuggestedDiagnosesFile;
psi.Arguments = $"\"{Script}\"";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
string Errors = "";
string Results = "";
using (var process = Process.Start(psi))
{
Errors = process.StandardError.ReadToEnd();
Results = process.StandardOutput.ReadToEnd();
}
Log("In cmd : " + "Errors:\n" + Errors + "\n\nResults:\n" + Results);
}
catch (Exception ex)
{
Log("ERROR (cmd) : " + ex.ToString());
}
and the error I get is this
In cmd : Errors:
C:\Users\MyID\AppData\Local\Programs\Python\Python310\python.exe: can't find '__main__' module in ''
Results:
how to fix that?
You should pass proper WorkingDirectory to your ProcessStartInfo. Like this.
I am calling python script from c# using ProcessInfoStart method. As an argument it receives JSON and is input to python script.
It works fine it we pass JSON without having any spaces but if there is any space then original JSON is splitted till space and passes as argument and rest ignored
public static bool ExecutePythonScript(string jRequest, string fileType)
{
string pythonExePath = Convert.ToString(ConfigurationManager.AppSettings["PythonExe"]);
bool bIsExecutionSuccess = true;
try
{
var psi = new ProcessStartInfo();
psi.FileName = pythonExePath;
var script = #"C:Scripts\pdf-to-csv.py";
psi.Arguments = $"\"{script}\" \"{jRequest}\"";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var errors = "";
var results = "";
using (var process = Process.Start(psi))
{
errors = process.StandardError.ReadToEnd();
results = process.StandardOutput.ReadToEnd();
}
if (!string.IsNullOrEmpty(errors))
bIsExecutionSuccess = false;
}
catch(Exception ex)
{
bIsExecutionSuccess = false;
}
return bIsExecutionSuccess;
}
Python script to accept arguments
input_params = sys.argv[1]
input_params = input_params.replace("'",'"')
data_params = json.loads(input_params)
Is there a way i can pass jRequest with spaces to python script.
Python script parameters can be wrapped in single quotes in order to read the whole string including spaces.
Try wrapping the JSON string in single quotes.
I have some very basic gpxlogger code that writes all the data to file quite well. (below)
gpxlogger -d -f /home/pi/Desktop/EPQ/temp_gps/gpslog
However I would like this code to always write to the same file without overwriting it. So if possible when it started logging it would go to the bottom of the file and start logging the data there, below what has already been logged.
Thanks,
Dan.
Javascript to read xml file
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAA7_kD1t_m22HBF9feCaDPZxQwcATY4FXmxYwkk9LNWGtAQdNKTBS1kBsTEqrRPg2kWxuNdmf2JVCIkQ" type="text/javascript"></script>
<script src="http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/src/markermanager.js"> </script><script>
var map;
function initialize () {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(53.423027, -1.523462), 10);
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.addMapType(G_PHYSICAL_MAP);
map.setMapType(G_PHYSICAL_MAP);
addMarkersFromXML();
}
}
function addMarkersFromXML(){
var batch = [];
mgr = new MarkerManager(map);
var request = GXmlHttp.create();
request.open('GET', 'gpslog.xml', true);
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
var xmlDoc = request.responseXML;
var xmlrows = xmlDoc.documentElement.getElementsByTagName("trkpt");
for (var i = 0; i < xmlrows.length; i++) {
var xmlrow = xmlrows[i];
var xmlcellLatitude = parseFloat(xmlrows[i].getAttribute("lat"));
var xmlcellLongitude = parseFloat(xmlrows[i].getAttribute("lon"));
var point = new GLatLng(xmlcellLatitude,xmlcellLongitude);
//get the time of the pin plot
var xmlcellplottime = xmlrow.getElementsByTagName("time")[0];
var celltextplottime = xmlcellplottime.firstChild.data;
//get the elevation of the pin plot
var xmlcellplotelevation = xmlrow.getElementsByTagName("ele")[0];
var celltextplotelevation = xmlcellplotelevation.firstChild.data;
//get the number of satellites at the time of the pin plot
var xmlcellplotsat = xmlrow.getElementsByTagName("sat")[0];
var celltextplotsat = xmlcellplotsat.firstChild.data;
var htmlString = "Time: " + celltextplottime + "<br>" + "Elevation: " + celltextplotelevation + "<br>" + "Satellites: " + celltextplotsat;
//var htmlString = 'yes'
var marker = createMarker(point,htmlString);
batch.push(marker);
}
mgr.addMarkers(batch,10);
mgr.refresh();
}
}
request.send(null);
}
function createMarker(point,html) {
var marker = new GMarker(point);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
return marker;
}
</script>
</head>
<body onload="initialize()" onunload="GUnload()">
<div id="map_canvas" style="width: 1350px; height: 800px"></div>
<div id="message"></div>
</body>
</html>
Here's another option.
Look at gps3.py, put it, and the following script into a directory.
It reads data from the gpsd; creates the gpx log file if it doesn't exist; appends "trackpoint" data to it when data exists; while maintaining the same file and appending "trackpoint" data after a restart.
Place both in the same directory and then have you javascript read the file..or put the entire structure in the same script.
#!/usr/bin/env python
# coding=utf-8
""" gpx logger to create and append a gpx formatted log of gpsd data """
import os
import time
import gps3
from datetime import datetime
the_connection = gps3.GPSDSocket()
the_fix = gps3.Fix()
the_log = '/tmp/gpx3.gpx'
creation = datetime.utcnow()
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
genesis = creation.strftime(fmt)
if not os.path.isfile(the_log):
header = ('<?xml version = "1.0" encoding = "utf-8"?>\n'
'<gpx version = "1.1" '
'creator = "GPSD 3.9 - http://catb.org/gpsd" '
'client = "gps3.py - http://github.com/wadda/gps3"'
'xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"'
'xmlns = "http://www.topografix.com/GPX/1/1"'
'xsi:schemaLocation = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">\n '
'<metadata>\n '
' <time>{}\n'
'</metadata>\n').format(genesis)
f = open(the_log, 'w')
f.write(header)
f.close()
try:
for new_data in the_connection:
if new_data:
the_fix.refresh(new_data)
if not isinstance(the_fix.TPV['lat'], str): # lat determinate of when data is 'valid'
latitude = the_fix.TPV['lat']
longitude = the_fix.TPV['lon']
altitude = the_fix.TPV['alt']
time = the_fix.TPV['time']
mode = the_fix.TPV['mode']
tag = the_fix.TPV['tag']
sats = the_fix.satellites_used()
hdop = the_fix.SKY['hdop']
vdop = the_fix.SKY['vdop']
pdop = the_fix.SKY['pdop']
trackpoint = ('<trkpt lat = {} lon = {}>\n'
' <ele>{}</ele>\n'
' <time>{}</time>\n'
' <src>GPSD tag ="{}"</src>\n'
' <fix>{}</fix >\n'
' <sat>{}</sat>\n'
' <hdop>{}</hdop>\n'
' <vdop>{}</vdop>\n'
' <pdop>{}</pdop>\n'
'</trkpt>\n').format(latitude, longitude, altitude, time, tag, mode, sats[1], hdop, vdop, pdop)
addendum = open(the_log, 'a')
addendum.write(trackpoint)
addendum.close()
except Exception as error:
print('Danger-Danger',error)
You run into the problem of a daemonised gpxlogger requiring a -f flag for a file name and that will overwrite the file. This you know.
I see there are two options. Not run gpxlogger as a daemon
gpxlogger >> /home/pi/Desktop/EPQ/temp_gps/gpslog
or run it as a daemon and cat the file to an append-able file
gpxlogger -d -f /home/pi/Desktop/EPQ/temp_gps/gpslog & cat /home/pi/Desktop/EPQ/temp_gps/gpslog >> /home/pi/Desktop/EPQ/temp_gps/gpslog_concatenated
Another way to look at it would be to create sequential logs, and then concatenate them with gpsbable, but in order to do that you need to have a script, and an index.
Make the index echo 0 > ~/.gpxfilecount
Open a favourite editor and create a file including something like:
#! /usr/bin/bash
COUNT=`cat ~/.gpxfilecount`
echo $(($COUNT + 1 )) > ~/.gpxfilecount
filename="gpxlogfile${COUNT}.gpx"
exec gpxlogger -d -f $filename
Mark the script executable chmod +x ~/bin/gpxer.sh (or favourite name).
Every time you fire up the gpxlogger an incremented filename is created. Those file can then be concatenated without tears by gpsbable gpsbabel -i geo -f gpxlogfile1.gpx -f gpxlogfile2.gpx -f gpxlogfile3.gpx -o gpx -F biglogcat.gpx ...or however gpsbable works.
I was curious what building a gpx file from scratch would look like using only minidom. Unfortunately life intervened, sorry for the delay...
When this script (below) gpex3.py, still a little crude and inefficient (read/write every second), is placed in the same directory as gps3.py it creates an appendable gpx file at /tmp/gpx3.gpx
#! /usr/bin/python3
# coding=utf-8
"""banana"""
import xml.dom.minidom
import gps3
import time
from datetime import datetime, timezone, timedelta
import os
import sys
gps_connection = gps3.GPSDSocket()
gps_fix = gps3.Fix()
the_log = '/tmp/gpx3.gpx'
def start_time():
"""time in the beginning"""
timestart = str(datetime.utcnow().replace(tzinfo=(timezone(timedelta(0)))))
return timestart
def close(doc):
"""write file to disk and close"""
log_write = open(the_log, "w")
doc.writexml(log_write)
log_write.close()
if os.path.isfile(the_log):
doc = xml.dom.minidom.parse(the_log) # opens the pre-existing
gpx_element = doc.firstChild
else:
doc = xml.dom.minidom.Document()
gpx_element = doc.createElement("gpx")
doc.appendChild(gpx_element)
trk_element = doc.createElement("trkseg")
trk_element.setAttribute("began", start_time())
gpx_element.appendChild(trk_element)
utc = alt = hdop = vdop = pdop = mode = sats = tag = 'n/a'
try:
tpv_list = {'time': utc, 'ele': alt, 'tag': tag}
sky_list = {'hdop': hdop, 'vdop': vdop, 'pdop': pdop}
# misc_list = {'sat': sats, 'fix':mode} # just an account
element = {}
x = 1 # for the 'is it working?'
for new_data in gps_connection:
if new_data:
gps_fix.refresh(new_data)
if not isinstance(gps_fix.TPV['lat'], str):
trkpt_element = doc.createElement("trkpt")
trk_element.appendChild(trkpt_element)
trkpt_element.setAttribute('lat', str(gps_fix.TPV['lat']))
trkpt_element.setAttribute('lon', str(gps_fix.TPV['lon']))
# tpv_list[key]
for key in tpv_list:
if key == 'ele':
element[key] = '{}'.format(gps_fix.TPV['alt']) # because consistency with labels is a horrible.
else:
element[key] = '{}'.format(gps_fix.TPV[key])
# sky_list[key]
for key in sky_list:
element[key] = '{}'.format(gps_fix.SKY[key])
# Misc.
element['sat'] = '{}'.format(gps_fix.satellites_used()[1])
element['fix'] = '{}'.format(("ZERO", "NO_FIX", "2D", "3D")[gps_fix.TPV['mode']])
for key in element:
trkpt_data = doc.createElement(key)
trkpt_element.appendChild(trkpt_data)
new_value = doc.createTextNode(element[key])
trkpt_data.appendChild(new_value)
# print(doc.toprettyxml())
close(doc) # write to file with every trackpoint
print('Cycle', x) # Only an "is it working?"
x += 1
time.sleep(1)
except KeyboardInterrupt:
gps_connection.close()
print("\nTerminated by user\nGood Bye.\n")
if __name__ == '__main__':
pass