从 Web 应用控制器中运行外部控制台应用(写入输出文件)

Running an external console app (that writes to the output file) from within web app controller

提问人:rejkid 提问时间:11/10/2023 最后编辑:rejkid 更新时间:11/10/2023 访问量:34

问:

我在服务器端运行 Web 应用程序控制器应用程序 (c#)。当特定的 http 请求传入时,控制器将运行外部控制台应用程序,该应用程序读取数据输入文件并写入包含结果的输出文件。问题是,此外部控制台应用程序始终输出一个空文件。 如果我通过自己执行外部控制台应用程序(将输入和输出文件作为参数传递)手动执行此过程,它会按预期创建非空输出结果文件。 这是一个安全问题吗,是否有任何解决方法?

我启动控制台应用的调用如下所示:

string a2tExePath = Path.Combine(Directory.GetCurrentDirectory(), A2T_EXE);
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append(" ").Append(Path.Combine(uploadFolder, A2T_INPUT)).Append(" ").Append(Path.Combine(uploadFolder, A2T_OUTPUT));
            using (System.Diagnostics.Process pProcess = new System.Diagnostics.Process())
            {
                pProcess.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
                pProcess.StartInfo.FileName = a2tExePath;// a2tExePath;
                pProcess.StartInfo.Arguments = stringBuilder.ToString(); //argument
                
                pProcess.StartInfo.ErrorDialog = true;
                pProcess.StartInfo.UseShellExecute = true;

                pProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                pProcess.StartInfo.CreateNoWindow = true; //not diplay a windows
                
                pProcess.Start();
                //string output = pProcess.StandardOutput.ReadToEnd(); //The output result
                log.Info("Executing " + a2tExePath + " " + pProcess.StartInfo.Arguments);
                pProcess.WaitForExit();
            }

        }
C# .NET Web 应用程序 控制器 控制台应用程序

评论

0赞 C. McCoy IV 11/10/2023
您对a2tExe有多熟悉?如果你有一个可以绑定到的 dll,请考虑使用对 Main learn.microsoft.com/en-us/dotnet/csharp/language-reference/ 的外部调用...
0赞 rejkid 11/10/2023
你能给我一个完整的例子,如何调用Main函数吗?我不熟悉这种技术。

答:

0赞 C. McCoy IV 11/10/2023 #1

我假设你在 Windows 上。这将在 no-show 命令提示符下运行任何一个衬里:

public class Cmd
{
  public CommandLineResult Run(string singleLine)
  {
    var startInfo = new ProcessStartInfo("cmd.exe")
    {
      Arguments = $"/c \"{singleLine}\"",
      UseShellExecute = false,
      CreateNoWindow = true,
      RedirectStandardOutput = true,
      RedirectStandardError = true,
    };

    var process = Process.Start(startInfo);

    var stdErr = string.Empty;
    process!.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => { stdErr += e.Data });
    process.BeginErrorReadLine();
    var stdOut = process?.StandardOutput.ReadToEnd();
    process?.WaitForExit();

    return new CommandLineResult
    {
      ExitCode = process?.ExitCode ?? -1,
      StandardOut = stdOut!,
      StandardErr = stdErr!,
    };
  }
}

public class CommandLineResult
{
  public int ExitCode { get; init; }
  public string StandardOut { get; init; } = null!;
  public string StandardErr { get; init; } = null!;
  public bool IsSuccess => ExitCode == 0;
  public string StandardAll = string.Join(Environment.NewLine, new[] { StandardOut, StandardErr });
}

您可以像这样使用它:

var inputPath = Path.Combine(uploadFolder, A2T_INPUT);
var outputPath = Path.Combine(uploadFolder, A2T_OUTPUT);
var singleLine = $"{a2tExePath} {inputPath} {outputPath}";
var result = new Cmd().Run(singleLine);

或者,如果您有 a2t 的 dll,您可以尝试将 extern 绑定到其 Main 函数并直接调用它(如果可能的话,我认为这更干净,因为您避免启动新进程,因为它只是一个花哨的函数调用)。参考: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern

评论

0赞 rejkid 11/10/2023
此 c# 代码与我的代码类似,不会创建输出文件 - 它始终为空。顺便说一句,你的类没有编译 - 它有一些错误,StandardOut 和 StandardErr 不是静态的。
0赞 rejkid 11/11/2023
你能帮我解决你发给我的代码的问题吗?C# 抱怨变量无法初始化,因为不是静态字段。StandardAllStandardOut StandardErr