{"id":186,"date":"2023-10-11T09:28:35","date_gmt":"2023-10-11T08:28:35","guid":{"rendered":"https:\/\/daan.wsng.eu\/?p=186"},"modified":"2023-10-11T09:28:35","modified_gmt":"2023-10-11T08:28:35","slug":"monthly-learnings-from-c-october-2023","status":"publish","type":"post","link":"https:\/\/daan.wsng.eu\/index.php\/2023\/10\/11\/monthly-learnings-from-c-october-2023\/","title":{"rendered":"Monthly learnings from C# (October 2023)"},"content":{"rendered":"\nI learned a new thing in C#, so it&#8217;s time to write a (small) blog again. This time it is about starting other programs.\n\n\n\n\n<h2>Starting an executable<\/h2>\n\n\n\n\nSometimes, you need to start an external executable on your server. This can be a PowerShell script, some Python code, or an .exe file. Let&#8217;s not dwell on the security implications, lets assume that we know what we are doing. Usually in C#, you can use <code>System.Diagnostics.Process<\/code> for starting and monitoring processes. An example:\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\nvar psi = new ProcessStartInfo \n{\n    FileName = &quot;D:\/apps\/scripts\/StartUpdate.ps1&quot;,\n    Argument = &quot;--force --silent&quot;,\n    WorkingDirectory = &quot;D:\/apps\/scripts\/&quot;,\n    UseShellExecute = false,\n    RedirectStandardOutput = true\n}\n\nvar process = Process.Start(psi);\n\nvar exitCode = 0;\nif (process != null) \n{\n    await process.WaitForExitCode();\n}\nexitCode = process.ExitCode;\n\n<\/pre><\/div>\n\n\nThe point of this piece of code is to start a script and wait until it is done. No fire-and-forget, because we might need to know the exit code, log the run time or process the results. \n\n\n\nHaving this running in production, we would sometimes come up with the situation that the program above never finishes. It keeps on waiting in the <code>process.WaitForExitCode()<\/code> statement. This was strange, because running the process itself one a local machine with all the same parameters would work flawless every time. Adding some logging did not pinpoint on a specific spot in the process, except that it always happened when an <code>async<\/code> statement was hit. \n\n\n\nReading the documentation on <a rel=\"noreferrer noopener\" href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/system.diagnostics.processstartinfo.redirectstandardoutput\" target=\"_blank\">RedirectStandardOutput<\/a> showed a hint halfway through:\n\n\n\n\n<blockquote class=\"wp-block-quote\">The example avoids a deadlock condition by calling <code>p.StandardOutput.ReadToEnd<\/code> before <code>p.WaitForExit<\/code>. <strong>A deadlock condition can result if the parent process calls <code>p.WaitForExit<\/code> before <code>p.StandardOutput.ReadToEnd<\/code><\/strong> and the child process writes enough text to fill the redirected stream. The parent process would wait indefinitely for the child process to exit. The child process would wait indefinitely for the parent to read from the full <a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/system.diagnostics.process.standardoutput?view=net-7.0\" target=\"_blank\" rel=\"noreferrer noopener\">StandardOutput<\/a> stream.<\/p><cite>Microsoft Learn<\/cite><\/blockquote>\n\n\n\n\n\nSo, to solve the deadlock problem, we need to add one extra line:\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\n\/\/ ...\nif (process != null) \n{\n    _ = await process.StandardOutput.ReadToEndAsync();\n    await process.WaitForExitCode();\n}\n\/\/ ...\n\n<\/pre><\/div>\n\n\nAnd now we don&#8217;t have any more deadlocks.\n","protected":false},"excerpt":{"rendered":"<p>I learned a new thing in C#, so it&#8217;s time to write a (small) blog again. This time it is about starting other programs. Starting an executable Sometimes, you need to start an external executable on your server. This can be a PowerShell script, some Python code, or an .exe file. Let&#8217;s not dwell on&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"twitterCardType":"","cardImageID":0,"cardImage":"","cardTitle":"","cardDesc":"","cardImageAlt":"","cardPlayer":"","cardPlayerWidth":0,"cardPlayerHeight":0,"cardPlayerStream":"","cardPlayerCodec":""},"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/posts\/186"}],"collection":[{"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/comments?post=186"}],"version-history":[{"count":4,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/posts\/186\/revisions"}],"predecessor-version":[{"id":200,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/posts\/186\/revisions\/200"}],"wp:attachment":[{"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/media?parent=186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/categories?post=186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/tags?post=186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}