Trying to pass stdin to a main method to evaluate code online - c#

I am trying to build a web application to evaluate .Net code online (like http://ideone.com/)
I have managed to compile code with CodeDomProvider.
But I don't know how to pass stdin parameters to this function.
If a user writes this code in the textarea of my web application:
using System;
public class Test {
static void Main()
{
String t = "";
while (t != null){
t = Console.ReadLine();
Console.WriteLine(t+"OK");
}
}
}
I can Compile it with this code
CompilerInfo[] allCompilerInfo = CodeDomProvider.GetAllCompilerInfo();
//Tell the compiler what language was used
CodeDomProvider CodeProvider = CodeDomProvider.CreateProvider("C#");
//Set up our compiler options...
CompilerParameters CompilerOptions = new CompilerParameters();
var _with1 = CompilerOptions;
_with1.ReferencedAssemblies.Add("System.dll");
_with1.GenerateInMemory = true;
_with1.TreatWarningsAsErrors = true;
//Compile the code that is to be evaluated
CompilerResults Results = CodeProvider.CompileAssemblyFromSource(CompilerOptions, strCode);
Now I would like to manage generic parameters:
If I pass a sample parameter like this:
53
12
09
I would like the result of the compilation:
53OK
12OK
09OK
Do you know how to do this?

As I interpret the question, you are asking how to run and pass stdin command line data to an application that was compiled on your web server from code that a user typed into a text box. Avoiding the serious security concerns of doing such, what you want to do is launch the application using the System.Diagnostics.Process class, and specify RedirectStandardInput in the StartInfo property. Start by reading the MSDN docs on the Process class: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx

Related

How can I programmatically turn off or on 'Windows Features'

When I try to update Windows features; When I update UseShellExecute to "true"; "The Process object must have the UseShellExecute property set to false in order to redirect IO streams." I get an error. When I set it to False; Unable to update. How can I do it ? Do you have any other suggestions?
static void InstallIISSetupFeature()
{
var featureNames = new List<string>() {
"IIS-WebServerRole",
"IIS-WebServer",
"IIS-CommonHttpFeatures",
"IIS-HttpErrors",
"IIS-HttpRedirect",
"IIS-ApplicationDevelopment",
"IIS-Security",
"IIS-RequestFiltering",
"IIS-NetFxExtensibility",
"IIS-NetFxExtensibility45",
"IIS-HealthAndDiagnostics",
"IIS-HttpLogging",
"IIS-LoggingLibraries",
"IIS-RequestMonitor",
"IIS-HttpTracing",
"IIS-URLAuthorization",
"IIS-IPSecurity",
"IIS-Performance",
"IIS-HttpCompressionDynamic",
"IIS-WebServerManagementTools",
"IIS-ManagementScriptingTools",
"IIS-IIS6ManagementCompatibility",
"IIS-Metabase",
"IIS-HostableWebCore","IIS-StaticContent",
"IIS-DefaultDocument",
"IIS-DirectoryBrowsing",
"IIS-WebDAV",
"IIS-WebSockets",
"IIS-ApplicationInit",
"IIS-ASPNET",
"IIS-ASPNET45",
"IIS-ASP",
"IIS-CGI",
"IIS-ISAPIExtensions",
"IIS-ISAPIFilter",
"IIS-ServerSideIncludes",
"IIS-CustomLogging",
"IIS-BasicAuthentication",
"IIS-HttpCompressionStatic",
"IIS-ManagementConsole",
"IIS-ManagementService",
"IIS-WMICompatibility",
"IIS-LegacyScripts",
"IIS-LegacySnapIn",
"IIS-FTPServer",
"IIS-FTPSvc",
"IIS-FTPExtensibility",
"IIS-CertProvider",
"IIS-WindowsAuthentication",
"IIS-DigestAuthentication",
"IIS-ClientCertificateMappingAuthentication",
"IIS-IISCertificateMappingAuthentication",
"IIS-ODBCLogging",
"NetFx4-AdvSrvs",
"NetFx4Extended-ASPNET45",
"NetFx3",
"WAS-WindowsActivationService",
"WCF-HTTP-Activation",
"WCF-HTTP-Activation45",
"WCF-MSMQ-Activation45",
"WCF-NonHTTP-Activation",
"WCF-Pipe-Activation45",
"WCF-TCP-Activation45",
"WCF-TCP-PortSharing45",
"WCF-Services45",
};
ManagementObjectSearcher obj = new ManagementObjectSearcher("select * from Win32_OperatingSystem");
foreach (ManagementObject wmi in obj.Get())
{
string Name = wmi.GetPropertyValue("Caption").ToString();
Name = Regex.Replace(Name.ToString(), "[^A-Za-z0-9 ]", "");
if (Name.Contains("Server 2008 R2") || Name.Contains("Windows 7"))
{
featureNames.Add("IIS-ASPNET");
featureNames.Add("IIS-NetFxExtensibility");
featureNames.Add("WCF-HTTP-Activation");
featureNames.Add("WCF-MSMQ-Activation");
featureNames.Add("WCF-Pipe-Activation");
featureNames.Add("WCF-TCP-Activation");
featureNames.Add("WCF-TCP-Activation");
}
string Version = (string)wmi["Version"];
string Architecture = (string)wmi["OSArchitecture"];
}
foreach (var featureName in featureNames)
{
Run(string.Format("dism/online/Enable-Feature:{0}", featureName));
}
}
static void Run(string arguments)
{
try
{
string systemPath = Path.Combine(Environment.ExpandEnvironmentVariables("%windir%"), "system32");
var dism = new Process();
dism.StartInfo.WorkingDirectory = systemPath;
dism.StartInfo.Arguments = arguments;
dism.StartInfo.FileName = "dism.exe";
dism.StartInfo.Verb = "runas";
dism.StartInfo.UseShellExecute = true;
dism.StartInfo.RedirectStandardOutput = true;
dism.Start();
var result = dism.StandardOutput.ReadToEnd();
dism.WaitForExit();
}
catch (Exception ex)
{
}
}`
I tried to update the feature with dism.exe and cmd.exe, when it gave an authorization error, I used the Verb property
`
Since the use of .Verb = "RunAs" requires .UseShellExecute = true, and since the latter cannot be combined with RedirectStandardOutput = true, you cannot directly capture the elevated process' output in memory.
It seems that the system itself, by security-minded design, prevents a non-elevated process from directly capturing an elevated process' output.
The workaround is to launch the target executable (dism.exe, in your case) indirectly, via a shell, and then use the latter's redirection feature (>) to capture the target executable's output (invariably) in a file, as shown below.
string systemPath = Path.Combine(Environment.ExpandEnvironmentVariables("%windir%"), "system32");
// Create a temp. file to capture the elevated process' output in.
string tempOutFile = Path.GetTempFileName();
var dism = new Process();
dism.StartInfo.WorkingDirectory = systemPath;
// Use cmd.exe as the executable, and pass it a command line via /c
dism.StartInfo.FileName = "cmd.exe" ;
// Use a ">" redirection to capture the elevated process' output.
// Use "2> ..." to also capture *stderr* output.
// Append "2>&1" to capture *both* stdout and stderr in the file targeted with ">"
dism.StartInfo.Arguments =
String.Format(
"/c {0} {1} > \"{2}\"",
"dism.exe", arguments, tempOutFile
);
dism.StartInfo.Verb = "RunAs";
dism.StartInfo.UseShellExecute = true;
dism.Start();
dism.WaitForExit();
// Read the temp. file in which the output was captured...
var result = File.ReadAllText(tempOutFile);
// ... and delete it.
File.Delete(tempOutFile);
First, you can use WindowsPrincipal::IsInRole() to check if you're running elevated.
See Microsoft Learn for details.
Second, this may be one of those cases where using native PS is easier than the cmdlet approach (admittedly, still not great).
If the script is supposed to run on clients as well as server operating systems: use Get-WmiObject or Get-CimInstance to get a reference to what you're running on. ActiveDirectory also has that information (in operatingSystem attribute).
For servers use Get-WindowsFeature in ServerManager module.
For clients use Get-WindowsOptionalFeature with switch -Online in DISM module which, if you indeed need to support OSes older than 6.3.xxxx, can be copied over from a machine that has it and added to $Env:Path before C:\Windows and C:\Windows\System32.
For either platform just pass the list of features to configure.
If in a (binary) cmdlet you have to call external tools then the advantage of them is mostly gone. It may be possible to access Windows CBS using a managed API to avoid this but even then the script based approach gets more results faster, especially since you can just just put together a quick wrapper around dism.exe .

what are the best practices to use python in c# application?

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?

Why is it not possible to invoke Powershell as a regular process in C#

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;

execute a python script in C#

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.

Execute a command line utility in ASP.NET

I need some advice regarding the use of a command line utility from a C#/ASP.NET web application.
I found a 3rd party utility for converting files to CSV format. The utility works perfectly and it can be used from the command line.
I have been looking on the web for examples on how to execute the command line utility and found this example.
The problem is this is not very good. When I try to us the example code with my utility, I get a prompt asking me to install the utility on the client machine. This is not what I want. I do not want the user to see what is going on in the background.
Is it possible to execute the command server side and processing the file from there?
Any help would be greatly appreciated.
I've done something like this several times in the past, and here's what's worked for me:
Create an IHttpHandler implementation (easiest to do as an .ashx file) to handle a convert. Within the handler, use System.Diagnostics.Process and ProcessStartInfo to run your command line utility. You should be able to redirect the standard output to the output stream of your HTTP response. Here's some code:
public class ConvertHandler : IHttpHandler
{
#region IHttpHandler Members
bool IHttpHandler.IsReusable
{
get { return false; }
}
void IHttpHandler.ProcessRequest(HttpContext context)
{
var jobID = Guid.NewGuid();
// retrieve the posted csv file
var csvFile = context.Request.Files["csv"];
// save the file to disk so the CMD line util can access it
var filePath = Path.Combine("csv", String.Format("{0:n}.csv", jobID));
csvFile.SaveAs(filePath);
var psi = new ProcessStartInfo("mycsvutil.exe", String.Format("-file {0}", filePath))
{
WorkingDirectory = Environment.CurrentDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
using (var process = new Process { StartInfo = psi })
{
// delegate for writing the process output to the response output
Action<Object, DataReceivedEventArgs> dataReceived = ((sender, e) =>
{
if (e.Data != null) // sometimes a random event is received with null data, not sure why - I prefer to leave it out
{
context.Response.Write(e.Data);
context.Response.Write(Environment.NewLine);
context.Response.Flush();
}
});
process.OutputDataReceived += new DataReceivedEventHandler(dataReceived);
process.ErrorDataReceived += new DataReceivedEventHandler(dataReceived);
// use text/plain so line breaks and any other whitespace formatting is preserved
context.Response.ContentType = "text/plain";
// start the process and start reading the standard and error outputs
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
// wait for the process to exit
process.WaitForExit();
// an exit code other than 0 generally means an error
if (process.ExitCode != 0)
{
context.Response.StatusCode = 500;
}
}
}
#endregion
}
The command is running server side. Any code is running on the server. The code in the example that you give works. You just need to make sure that the utility is set up properly on the server and that you have permissions to the directory/file.

Categories