-
Notifications
You must be signed in to change notification settings - Fork 414
feat(dotnet11): add process-api-net11 skill for new process APIs #866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
29286e7
2ae8051
0eaf5fd
630086d
fb89d28
d821f78
ab73b73
3eb02b5
77ee4b0
5c789a6
020887a
70ddbff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,179 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||
| name: process-api-net11 | ||||||||||||||||||||||||||||||||||||||||||||||||
| description: > | ||||||||||||||||||||||||||||||||||||||||||||||||
| Provides guidance on the new System.Diagnostics.Process APIs introduced in .NET 11. | ||||||||||||||||||||||||||||||||||||||||||||||||
| It covers high-level convenience methods (Process.Run, Process.RunAndCaptureText, Process.StartAndForget), | ||||||||||||||||||||||||||||||||||||||||||||||||
| reliable deadlock-free output reading (Process.ReadAllText/Bytes/Lines), and lifecycle/handle management | ||||||||||||||||||||||||||||||||||||||||||||||||
| (KillOnParentExit, InheritedHandles, StartDetached). | ||||||||||||||||||||||||||||||||||||||||||||||||
| Use when starting, orchestrating, or capturing output from external processes in .NET 11 applications. | ||||||||||||||||||||||||||||||||||||||||||||||||
| license: MIT | ||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| # Process API Improvements — .NET 11 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| New APIs added to `System.Diagnostics.Process` in .NET 11 simplify process management, eliminate boilerplate, and prevent common deadlock patterns when capturing output. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ## When to Use | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| - Running or orchestrating external processes in a .NET 11 (or later) project. | ||||||||||||||||||||||||||||||||||||||||||||||||
| - Needing to start a process, wait for it to exit, and capture its output/error streams without risking deadlocks (`Process.RunAndCaptureTextAsync`). | ||||||||||||||||||||||||||||||||||||||||||||||||
| - Wanting to ensure child processes are automatically terminated when the parent process exits (`KillOnParentExit`). | ||||||||||||||||||||||||||||||||||||||||||||||||
| - Requiring trimmer-friendly and NativeAOT-compatible process creation via `SafeProcessHandle`. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The wording needs a bit more specific.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarified that |
||||||||||||||||||||||||||||||||||||||||||||||||
| - Requiring fine-grained control over handle inheritance (`InheritedHandles`) or starting detached processes (`StartDetached`). | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ## When Not to Use | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| - The project targets .NET 10 or earlier — these APIs are not available before .NET 11. | ||||||||||||||||||||||||||||||||||||||||||||||||
| - Running simple shells where custom execution code is unnecessary. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not a native speaker, so please take it with a grain of salt. But overall I do believe that the new APIs simplify the code a lot, so I would recommend them even for simple shells.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed the bullet against simple shells. |
||||||||||||||||||||||||||||||||||||||||||||||||
| - The default `Process.Start()` is sufficient and does not require output capturing or advanced lifecycle rules. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ## Target Framework | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ```xml | ||||||||||||||||||||||||||||||||||||||||||||||||
| <TargetFramework>net11.0</TargetFramework> | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ## New APIs & Convenience Methods | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Each of these methods is a new API, some are also convenience methods. I would just call it
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed section heading to |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ### High-Level Convenience APIs (Static Methods) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest we use following separation:
As some of the instance methods are also convenience methods (at least in my opinion).
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reorganized sections under |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| #### `Process.Run` / `Process.RunAsync` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Starts a process and waits for it to exit, returning the exit status. Does not capture standard output or error. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to mention that it also allows the users to discard the output/error by providing
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mentioned that |
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static ProcessExitStatus Run(string fileName, IList<string>? arguments = null, bool silent = false, TimeSpan? timeout = null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static Task<ProcessExitStatus> RunAsync(string fileName, IList<string>? arguments = null, bool silent = false, CancellationToken cancellationToken = default) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static ProcessExitStatus Run(ProcessStartInfo startInfo, TimeSpan? timeout = null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static Task<ProcessExitStatus> RunAsync(ProcessStartInfo startInfo, CancellationToken cancellationToken = default) | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| #### `Process.RunAndCaptureText` / `Process.RunAndCaptureTextAsync` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Starts a process, captures both standard output and error, and waits for it to exit. Extremely useful for avoiding deadlocks on stream redirection. | ||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static ProcessTextOutput RunAndCaptureText(string fileName, IList<string>? arguments = null, TimeSpan? timeout = null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static Task<ProcessTextOutput> RunAndCaptureTextAsync(string fileName, IList<string>? arguments = null, CancellationToken cancellationToken = default) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static ProcessTextOutput RunAndCaptureText(ProcessStartInfo startInfo, TimeSpan? timeout = null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static Task<ProcessTextOutput> RunAndCaptureTextAsync(ProcessStartInfo startInfo, CancellationToken cancellationToken = default) | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| #### `Process.StartAndForget` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Launches a process and immediately releases the system handle resources, returning only the process ID (PID). | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's provide the reasoning behind this method. You can re-use the text from our blog post:
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added the rationale citing |
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| public static int StartAndForget(string fileName, IList<string>? arguments = null) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In .NET 11 Preview 7 we have changed these methods to accept
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
| public static int StartAndForget(ProcessStartInfo startInfo) | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ### Reliable Output Reading APIs (Instance Methods) | ||||||||||||||||||||||||||||||||||||||||||||||||
| These methods are called on a `Process` instance to directly read stdout and stderr, guaranteeing no OS pipe buffer overflow deadlocks. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| public (string StandardOutput, string StandardError) ReadAllText(TimeSpan? timeout = null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public Task<(string StandardOutput, string StandardError)> ReadAllTextAsync(CancellationToken cancellationToken = default) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public (byte[] StandardOutput, byte[] StandardError) ReadAllBytes(TimeSpan? timeout = null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public Task<(byte[] StandardOutput, byte[] StandardError)> ReadAllBytesAsync(CancellationToken cancellationToken = default) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public IEnumerable<ProcessOutputLine> ReadAllLines(TimeSpan? timeout = null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| public IAsyncEnumerable<ProcessOutputLine> ReadAllLinesAsync(CancellationToken cancellationToken = default) | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
| *Note: `ProcessOutputLine` is a readonly struct containing `string Content` and `bool StandardError` properties.* | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We mention what
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added definitions for |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ### ProcessStartInfo Properties | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| #### `KillOnParentExit` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Ensures that the spawned child process is terminated when the current (parent) process exits. Works across both Windows and Unix platforms. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not every Unix is supported. Only Win, Lin and Android.
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated to specify Windows, Linux, and Android. |
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| public bool KillOnParentExit { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| #### `InheritedHandles` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Provides precise control over which file/kernel handles are inherited by the child process, preventing accidental resource leaks. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to describe few important things:
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added details on standard handles inclusion, empty list behavior, supported handle types, and Windows parallel spawning without global lock. |
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| public IList<SafeHandle>? InheritedHandles { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| #### `StartDetached` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Starts the process detached from the parent's terminal or job session, ensuring it survives the parent's exit. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When set to
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added note explaining standard handles redirection to the |
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| public bool StartDetached { get; set; } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ## Examples | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ### 1. One-Line Run and Capture Output | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Run a process and safely read all output text without stream deadlock risks: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System; | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System.Diagnostics; | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System.Threading.Tasks; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Run 'git status' and capture output (arguments passed as list) | ||||||||||||||||||||||||||||||||||||||||||||||||
| ProcessTextOutput result = await Process.RunAndCaptureTextAsync("git", ["status"]); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. People tend to use
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. Updated the example to use the synchronous |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (result.ExitStatus.ExitCode == 0) | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| Console.WriteLine($"Git Output: {result.StandardOutput.Trim()}"); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no need to use
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. Removed |
||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| Console.WriteLine($"Failed with exit code: {result.ExitStatus.ExitCode}"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| Console.WriteLine($"Error: {result.StandardError}"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ### 2. Auto-Killing Child Processes on Parent Exit | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Ensure a long-running background worker process is killed when the main application terminates: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System.Diagnostics; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| var startInfo = new ProcessStartInfo("dotnet", ["run", "--project", "BackgroundWorker.csproj"]) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: subjective: no need to use
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. Updated the snippet to explicitly declare |
||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| KillOnParentExit = true // Auto-teardown when this parent process exits | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. Added OS platform checks: |
||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| using var process = Process.Start(startInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||
| // The background worker is now tied to this process's lifecycle | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ### 3. Read All Lines From Output | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Start a process and read its output lines safely: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System; | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System.Diagnostics; | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System.Threading.Tasks; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| var startInfo = new ProcessStartInfo("ping", ["127.0.0.1"]) | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| RedirectStandardOutput = true, | ||||||||||||||||||||||||||||||||||||||||||||||||
| RedirectStandardError = true | ||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| using var process = Process.Start(startInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (process != null) | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Read all output lines safely and asynchronously | ||||||||||||||||||||||||||||||||||||||||||||||||
| await foreach (ProcessOutputLine line in process.ReadAllLinesAsync()) | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| string prefix = line.StandardError ? "[Err]" : "[Out]"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| Console.WriteLine($"{prefix} > {line.Content}"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ### 4. Start and Forget (Fire & Forget) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Launch a helper tool or browser without holding onto system handle structures: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System; | ||||||||||||||||||||||||||||||||||||||||||||||||
| using System.Diagnostics; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Fire and forget, getting back only the process ID | ||||||||||||||||||||||||||||||||||||||||||||||||
| int pid = Process.StartAndForget("notepad.exe"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| Console.WriteLine($"Notepad started with PID: {pid}"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| scenarios: | ||
| # --- Scenario 1: Run and capture output in .NET 11 --- | ||
| - name: "Run and capture process output in .NET 11" | ||
| prompt: | | ||
| I'm writing a .NET 11 command-line tool that needs to run an external CLI (e.g. 'git status') and capture both stdout and stderr. | ||
| I want to make sure I don't run into any OS pipe deadlock issues, and I want to write it in the cleanest way possible using new .NET 11 features. | ||
| Show me the C# program and the `.csproj` XML targeting `net11.0` for this tool. Print both in your response. | ||
| assertions: | ||
| - type: "exit_success" | ||
| - type: "output_matches" | ||
| pattern: "Process\\.RunAndCaptureText(Async)?" | ||
| - type: "output_matches" | ||
| pattern: "net11\\.0" | ||
| - type: "output_not_matches" | ||
| pattern: "RedirectStandardOutput\\s*=\\s*true" | ||
|
AbhitejJohn marked this conversation as resolved.
|
||
| rubric: | ||
| - "Uses the new built-in Process.RunAndCaptureText or Process.RunAndCaptureTextAsync static method" | ||
| - "Targets net11.0 in the project file" | ||
| - "Avoids manual redirection setup boilerplate (like RedirectStandardOutput = true, BeginOutputReadLine, etc.)" | ||
| timeout: 180 | ||
|
|
||
| # --- Scenario 2: Auto-teardown child processes on parent exit --- | ||
| - name: "Auto-teardown child processes on parent exit in .NET 11" | ||
| prompt: | | ||
| In a .NET 11 application, I need to spawn a background daemon process. | ||
| To prevent orphan processes, I want to ensure that this daemon process is automatically killed by the operating system if my main parent process crashes or exits. | ||
| How do I configure this in .NET 11 using ProcessStartInfo? Show me a minimal example, and show the `.csproj` XML targeting `net11.0` in your response. | ||
| assertions: | ||
| - type: "exit_success" | ||
| - type: "output_matches" | ||
| pattern: "KillOnParentExit\\s*=\\s*true" | ||
| - type: "output_matches" | ||
| pattern: "net11\\.0" | ||
| rubric: | ||
| - "Uses the new KillOnParentExit property on ProcessStartInfo set to true" | ||
| - "Targets net11.0" | ||
| timeout: 180 | ||
|
|
||
|
AbhitejJohn marked this conversation as resolved.
|
||
| # --- Scenario 3: Negative — skill should NOT activate --- | ||
| - name: "Non-activation: Running a process on .NET 8" | ||
| prompt: | | ||
| I have a .NET 8 console app and I need to start a process 'notepad.exe'. | ||
| Show me a minimal C# program and the `.csproj` XML targeting `net8.0` that starts this process using the traditional Process.Start. Print both in your response. | ||
| expect_activation: false | ||
| assertions: | ||
| - type: "exit_success" | ||
| - type: "output_matches" | ||
| pattern: "net8\\.0" | ||
| - type: "output_matches" | ||
| pattern: "Process\\.Start\\(" | ||
| - type: "output_not_matches" | ||
| pattern: "Process\\.RunAndCaptureText" | ||
|
AbhitejJohn marked this conversation as resolved.
Outdated
|
||
| rubric: | ||
| - "Solves the task using standard pre-.NET 11 APIs (Process.Start)" | ||
| - "Does NOT load or reference the process-api-net11 skill" | ||
| - "Targets net8.0" | ||
| timeout: 180 | ||
|
AbhitejJohn marked this conversation as resolved.
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we provide sync and async overloads
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated bullet to mention
Process.RunAndCaptureText[Async].