I am trying to execute a python code in C#. Normally it should be done using IronPython and after installing PTVS (I'm using VS 2010).
var pyEngine = Python.CreateEngine();
var pyScope = pyEngine.CreateScope();
try
{
pyEngine.ExecuteFile("plot.py", pyScope);
}
catch (Exception ex)
{
Console.WriteLine("There is a problem in your Python code: " + ex.Message);
}
The problem is that it seems that IronPython doesn't recognize some libraries like numpy, pylab or matplotlib. I took a look a little bit and found some people talking about Enthought Canopy or Anaconda, which i have both installed without fixing the problem.
What should I do to get the problem solved?
In order to execute a Python script which imports some libraries such as numpy and pylab, it is possible to make this:
string arg = string.Format(#"C:\Users\ayed\Desktop\IronPythonExamples\RunExternalScript\plot.py"); // Path to the Python code
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"D:\WinPython\WinPython-64bit-2.7.5.3\python-2.7.5.amd64\python.exe", arg);
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true; // Hide the command line window
p.StartInfo.RedirectStandardOutput = false;
p.StartInfo.RedirectStandardError = false;
Process processChild = Process.Start(p.StartInfo);
If you execute your code, IronPython will only look for the script in the current working directory. You need to add some more search paths. This is a part of some old integration code in my application using ironpython:
var runtimeSetup = Python.CreateRuntimeSetup(null);
runtimeSetup.DebugMode = false;
runtimeSetup.Options["Frames"] = true;
runtimeSetup.Options["FullFrames"] = true;
var runtime = new ScriptRuntime(runtimeSetup);
var scriptEngine = runtime.GetEngineByTypeName(typeof(PythonContext).AssemblyQualifiedName);
// Set default search paths
ICollection<string> searchPaths = scriptEngine.GetSearchPaths();
searchPaths.Add("\\Scripts\\Python");
scriptEngine.SetSearchPaths(searchPaths);
The trick is to add all paths in this code line: scriptEngine.SetSearchPaths(searchPaths);. If you add the directory which contains plot.py here, all should work.
Hope this helps.
Related
I have a requirement for using Python analytics into c# application.
To be precise: c# should call a python script and get the output back into c# application for further processing.
I have tried using IronPython as recommend by many.
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
engine.ExecuteFile(#"DemoPythonApplication\SentimentAnalysis.py", scope);
dynamic testFunction = scope.GetVariable("create_sentiment_analysis"); //calling a function from python script file
var result = testFunction(); //This function is returning a dynamic dictionary, which I can use in my c# code further
But the limitation with IronPython is, it is not providing support for many python libraries like pandas, numpy, nltk etc, These libraries are getting used in python scripts. (since we have a different team working on python I don't have control over them for using specific libraries.)
Another option i tried is to run the python process and calling the script
private static readonly string PythonLocation = #"Programs\Python\Python37\python.exe"; //Location of Python.exe
private static readonly string PythonScript = #"DemoPythonApplication\SentimentAnalysis.py"; //Location of Python Script
private static void ProcessInPython(int a, int b)
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = PythonLocation;
start.Arguments = string.Format("{0} {1} {2}", PythonScript, a, b);
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
var result = reader.ReadToEnd();
Console.Write(result);
}
}
}
There are limitations of using this approach though, I am only able to get whatever is getting printed on the console as a string, and could not get the output that python functions are returning.
Also if I use the 2nd approach, I don't know how to call a specific function from the python script file.
Can someone help with the best practices of using python in c# for this kind of situation?
I'm not sure what the correct question for my case would be but I'll try to describe as good as I can. I have to mention that I don't have much knowledge of this language, I'm using it strictly for the executable of my appplication, mainly I mess around with Java. So I have an app that only starts up if it finds java in my PC. I'm using something like this:
ProcessStartInfo startJava = new ProcessStartInfo("java", JavaProcessArguments());
startJava.CreateNoWindow = !client.ShowConsole;
startJava.UseShellExecute = false;
But, let's say I want to use openJDK, then I would have to change "java" to something like this:
ProcessStartInfo startJava = new ProcessStartInfo
(#"C:\Program Files (x86)\Java\openJDK_1.7\bin\java.exe", JavaProcessArguments());
Moving on, I wanted to start openJDK FIRST, even if java is present, so I wrote a condition that does that:
private void StartTheProcess()
{
string pathJDK = #"C:\Program Files (x86)\Java\openJDK_1.7\bin\";
bool isDirJDK7 = Directory.Exists(pathJDK);
if (isDirJDK7)
{
ProcessStartInfo startJava = new ProcessStartInfo(#"C:\Program Files (x86)\Java\openJDK_1.7\bin\java.exe", JavaProcessArguments());
startJava.CreateNoWindow = !client.ShowConsole;
startJava.UseShellExecute = false;
try
{
using (Process p = Process.Start(startJava))
{
p.WaitForExit();
}
}
catch (Win32Exception ex)
{
some error...
}
catch (Exception e)
{
some error...
}
}
else
{
ProcessStartInfo startJava = new ProcessStartInfo("java", JavaProcessArguments());
startJava.CreateNoWindow = !client.ShowConsole;
startJava.UseShellExecute = false;
try
{
using (Process p = Process.Start(startJava))
{
p.WaitForExit();
}
}
catch (Win32Exception ex)
{
some error...
}
catch (Exception e)
{
some error...
}
}
}
Now let's suppose I have more openJDK versions in the "C:\Program Files (x86)\Java\" folder: openJDK_1.7, openJDK_1.7_u1, openJDK_1.8, so on, and I want to start the latest one. How should I accomplish this? I think one method would be to compare the subfolders names found there but I don't really know how to. The content of all the subfolders is identical and the names of the subfolders have the same construction (openJDK_1.X / openJDK_1.X_uYZ). Could you help me, based on this poorly (most likely) code? :D
There are a few things you could try,
Split the directory name string by
var version = string.split('_'), and then the version would be version[1] = "1.7", you can convert all of these into doubles/decimals/floats,etc and just sort the data out, get the latest version (the one with the highest number and get its directory back
The second thing you can try is checking the Directory.GetLastWriteTime(String), which you can compare, and find the last one, please not that this is not reliable at all since the folder can be changed by anything.
Wanted to know if there is a reason that Powershell needs a special library (in System.Management.Automation NS) to be invoked from C# code? I have this code:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
string trackerPath = "C:\\Users\\bernam\\Downloads\\test_scripts\\test_scripts\\Mindaugas_Scripts\\test.ps1";
p.StartInfo.FileName = "Powershell.exe";
p.StartInfo.Arguments = " -file " + trackerPath;
Console.WriteLine(p.StartInfo.FileName + p.StartInfo.Arguments);
p.Start();
string output = p.StandardOutput.ReadToEnd();
And it does not seem to be working - output is not returned back. However all these scenarios work fine (produce desired output):
p.StartInfo.FileName = "Powershell.exe"; p.StartInfo.Arguments = "get-service"; - works fine.
Invoking the PS script from the command line works fine as well (invocation from CMD):
>Powershell.exe -file "C:\Users\<shortened>\test.ps1"
1
2
The powershell code inside the script:
1..10 | % { Write-Host $_ ; sleep -m 500}
I know that there is a recommendation to use PowerShell class in System.Management.Automation namespace. What is interesting to me - is why? And is it possible to use PS without that Class? Maybe my code is simply wrong?
Yes this is certainly possible.
Try replacing Write-Host with Write-Output in the script you are calling.
Write-Host does not write to the standard streams, it writes to a console host. If you are not running a console host (cmd/powershell console), the output will just disappear. In general it is best to avoid using Write-Host all together.
The reason most people recommend using the System.Management.Automation method, is it simplifies many interactions that you may wish to use with powershell, rather than trying to parse the returns from powershell.exe, there are however valid reasons for calling the exe directly, for example if you are using .net core, which doesn't currently fully support System.Management.Automation.
You should invoke PS scripts from System.Management.Automation NS, because then you can work with results and exceptions having type-safe environment.
EDIT also, you can use asynchronous execution or you can execute PS scripts on a Remote server. Generally, you have much more possibilities using that library.
You can take a look at my example below.
string script = ""; // PS script content
List<ScriptParameter> ExecParamList; // parameters
var result = new ExecPSResult(); // Class with list of outputs and errors
using (var powerShellInstance = PowerShell.Create())
{
powerShellInstance.AddScript(script);
foreach (var execParamModel in ExecParamList)
{
powerShellInstance.AddParameter(execParamModel.ParamName,
execParamModel.ParamValue ?? "$null");
}
var psOutput = powerShellInstance.Invoke();
result.Errors =
powerShellInstance.Streams.Error.Select(e =>
ExecException.MakeFromException(e.Exception) // just make models for exeptions
).ToList();
result.OutputItems =
psOutput.Where(
outputItem =>
outputItem != null &&
outputItem.TypeNames[0] != "System.ServiceProcess.ServiceController")
.Select(e => new ExecOutput
{
ObjectTypeFullName = e.BaseObject.GetType().FullName,
ObjectValue = e.BaseObject //This is typeof(Object)
}).ToList();
}
return result;
I'm trying to do a virus scan on uploaded files.
I have no control over the installed virus scanner, the product hosted by multiple parties with different scanners.
I tried the following library but it always returns VirusNotFound on the eicar file.
https://antivirusscanner.codeplex.com/
Do you know any other solutions?
ClamAV has pretty bad detection scores.
VirusTotal is not on premises.
I decided to create CLI wrappers for multiple scanners, nuget packages can be found here: https://www.nuget.org/packages?q=avscan
And its documentation and source code available at https://github.com/yolofy/AvScan
I used this library for .net (It uses the VirusTotal public api):
https://github.com/Genbox/VirusTotal.NET
A little example from github :
static void Main(string[] args)
{
VirusTotal virusTotal = new VirusTotal("INSERT API KEY HERE");
//Use HTTPS instead of HTTP
virusTotal.UseTLS = true;
FileInfo fileInfo = new FileInfo("testfile.txt");
//Create a new file
File.WriteAllText(fileInfo.FullName, "This is a test file!");
//Check if the file has been scanned before.
Report fileReport = virusTotal.GetFileReport(fileInfo).First();
bool hasFileBeenScannedBefore = fileReport.ResponseCode == 1;
if (hasFileBeenScannedBefore)
{
Console.WriteLine(fileReport.ScanId);
}
else
{
ScanResult fileResults = virusTotal.ScanFile(fileInfo);
Console.WriteLine(fileResults.VerboseMsg);
}
}
A full example can be found here :
https://github.com/Genbox/VirusTotal.NET/blob/master/VirusTotal.NET%20Client/Program.cs
Clam AV is pretty good.
https://www.clamav.net/downloads
C# Api here:
https://github.com/michaelhans/Clamson/
I just tried various ways, But some didn't work.
Then I decided to use ESET NOD32 command line tools .
It works fine for me:
public bool Scan(string filename)
{
var result = false;
try
{
Process process = new Process();
var processStartInfo = new ProcessStartInfo(#"C:/Program Files/ESET/ESET Security/ecls.exe")
{
Arguments = $" \"{filename}\"",
CreateNoWindow = true,
ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false
};
process.StartInfo = processStartInfo;
process.Start();
process.WaitForExit();
if (process.ExitCode == 0) //if it doesn't exist virus ,it returns 0 ,if not ,it returns 1
{
result = true;
}
}
catch (Exception)
{ //nothing;
}
return result;
}
I am generating C++ code via C#, for some reason after applying astyle my generated code compiles. So is there a way I can invoke astyle from within my C# windows application?
Astyle is a command line tool, so using Process class you can call it externally and ask it to format the C++ source file.
I have done similar projects in the past, such as
http://alex.codeplex.com
I finally figured it out a few days ago, so thought i would share my function to astyle via c#
'
private void astyleDirectory(string target_path)
{
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
//Enter Path to get Astyle.exe here
pProcess.StartInfo.FileName=System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + #"\Astyle.exe";
pProcess.StartInfo.Arguments = "--options=none --style=ansi --recursive *.h *.cpp";
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.StartInfo.RedirectStandardError = true;
pProcess.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(target_path);
try
{
pProcess.Start();
string strOutput = pProcess.StandardOutput.ReadToEnd();
string strError = pProcess.StandardError.ReadToEnd();
pProcess.WaitForExit();
}
catch { }
}
'