Quiero ejecutar el proceso en SQL Server CLR este es mi código:
[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); } } y se ejecuta ipconfig.exe (veo en los resultados "proceso WaitForExit"), pero el evento OutputDataReceived no se activa.
El ensamblado se creó en SQL Server 2019 Enterprise con PERMISSION_SET = UNSAFE; . Si ejecuto el mismo código que la aplicación de consola estándar, todo funciona bien
Eso requerirá un subproceso en segundo plano para ejecutar el evento mientras bloquea el subproceso de la sesión en WaitForExit . No me sorprende que no funcione en SQLCLR, que es un host de .NET Framework muy diferente a una aplicación de consola.
E incluso si se activa el evento, no podría acceder a SqlContext.Pipe desde un subproceso que no sea el subproceso que llamó al método.
En su lugar, realice lecturas de bloqueo de StandardOutput usando el hilo que llamó a su método, así:
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(); }+1 a David por responder a la pregunta general de cómo capturar y devolver mejor la salida de la línea de comandos.
Sin embargo, para su escenario específico de ejecutar ipconfig.exe y devolver todo el resultado, creo que sería mucho mejor simplemente usar:
NetworkInterface.GetAllNetworkInterfaces()
Yo probaría eso primero. Esto puede requerir que cargue la biblioteca del marco System.Net.NetworkInformation.dll como UNSAFE en la misma base de datos, pero ya está realizando operaciones "inseguras" al pagar al sistema operativo, por lo que al menos esto se maneja en código administrado.