【问题标题】:Run process in SQL Server CLR stored procedure but Process.OutputDataReceived not firing在 SQL Server CLR 存储过程中运行进程但 Process.OutputDataReceived 未触发
【发布时间】:2021-07-16 00:48:05
【问题描述】:

我想在我的代码中在 SQL Server CLR 中运行进程:

[SqlProcedure]
private static int RunExecutable()
{
     SqlDataRecord sqlDataRecord = new SqlDataRecord(new SqlMetaData("message", SqlDbType.NVarChar, 1L));
     SqlContext.Pipe.SendResultsStart(sqlDataRecord);
     int lineCount = 0;

     Process process = new Process();
     process.StartInfo.FileName = "ipconfig.exe";
     process.StartInfo.UseShellExecute = false;
     process.StartInfo.RedirectStandardInput = true;
     process.StartInfo.RedirectStandardOutput = true;
     process.StartInfo.CreateNoWindow = true;
     process.EnableRaisingEvents = true;
     process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
            {
                    sqlDataRecord.SetString(0, "OnDataReceived");
                    SqlContext.Pipe.SendResultsRow(sqlDataRecord);

                    if (!String.IsNullOrEmpty(e.Data))
                    {
                        lineCount++;
                        sqlDataRecord.SetString(0, "[" + lineCount + "]: " + e.Data);
                        SqlContext.Pipe.SendResultsRow(sqlDataRecord);
                    }
            });

     process.Start();
     process.BeginOutputReadLine();

     while (!process.HasExited)
     {
         sqlDataRecord.SetString(0, "process WaitForExit ");
         SqlContext.Pipe.SendResultsRow(sqlDataRecord);
         process.WaitForExit(300);
     }
}

并且ipconfig.exe 运行(我在结果中看到“进程WaitForExit”),但未触发OutputDataReceived 事件。

程序集是在 SQL Server 2019 Enterprise 中使用PERMISSION_SET = UNSAFE; 创建的。如果我运行与标准控制台应用程序相同的代码,一切正常

【问题讨论】:

  • 你考虑过使用Ping.Send吗?顺便说一句,您应该使用 using 块处理 process

标签: c# sql-server sqlclr


【解决方案1】:

这将需要一个后台线程来运行事件,而您在 WaitForExit 上阻止会话线程。我并不惊讶它在 SQLCLR 中不起作用,它是一个与控制台应用程序非常不同的 .NET Framework 主机。

即使事件触发,您也无法从调用该方法的线程以外的线程访问SqlContext.Pipe

改为使用调用您的方法的线程对 StandardOutput 执行阻塞读取,如下所示:

static IEnumerable<string> GetOutputLines(string exeName, string args = null)
{ 
    Process process = new Process();
    process.StartInfo.FileName = exeName;
    process.StartInfo.Arguments = args;
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardInput = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.CreateNoWindow = true;
    process.EnableRaisingEvents = true;

    process.Start();
    
    while ( true )
    {
        var line = process.StandardOutput.ReadLine();
        if (line == null)
            break;
        yield return line;
    }

    process.WaitForExit();
}

【讨论】:

  • 谢谢,我发现问题在于将结果发送到 DataReceivedEventHandler。可能是因为 DataReceivedEventHandler 在不同的线程上被调用。
【解决方案2】:

感谢 David 回答了有关如何最好地捕获和返回命令行输出的一般问题。

但是,对于您运行 ipconfig.exe 并返回所有输出的特定场景,我认为您只需使用以下命令会更好:

NetworkInterface.GetAllNetworkInterfaces()

我会先尝试。这可能需要您将 System.Net.NetworkInformation.dll 框架库作为UNSAFE 加载到同一数据库中,但您已经通过向操作系统发起“不安全”操作,所以在至少这是在托管代码中处理的。

【讨论】:

  • ipconfig.exe 只是测试应用程序,在我的情况下,我运行另一个应用程序。
猜你喜欢
  • 1970-01-01
  • 2017-11-06
  • 1970-01-01
  • 2016-04-14
  • 2019-03-25
  • 1970-01-01
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
相关资源
最近更新 更多