mirror of
https://github.com/dotnet/skills.git
synced 2026-09-20 09:49:54 +08:00
042a9d2b2c
* Reorganize plugins per agreed structure (#271) Split the dotnet plugin into domain-specific plugins per discussion in #271: - dotnet: narrowed to common everyday C#/.NET coding tasks - dotnet-diag: perf investigations, debugging, incident analysis - dotnet-data: data access and Entity Framework - dotnet-aspnet, dotnet-wpf, dotnet-winforms, dotnet-maui: scaffolded empty to convey intent for future framework-specific skills Moved skills, tests, and CODEOWNERS entries accordingly. No file content was changed; all skill/test moves are pure renames. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Improve dotnet-diag and dotnet-winforms descriptions - dotnet-diag: add '.NET' qualifier to clarify scope - dotnet-winforms: use official 'Windows Forms (WinForms)' name Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add .NET qualifier to dotnet-data description Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove empty plugins; list them in CONTRIBUTING.md as future options Remove the four empty placeholder plugins (dotnet-aspnet, dotnet-wpf, dotnet-winforms, dotnet-maui) that had only plugin.json and no skills. Add a 'Plugin organization' section to CONTRIBUTING.md that describes the domain-specific plugin groupings introduced in this PR and lists the four removed plugin names as reserved candidates for future contributions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Create dotnet-upgrade plugin with migration/upgrade skills Move migrate-nullable-references, thread-abort-migration, and dotnet-aot-compat from dotnet to the new dotnet-upgrade plugin. Update CODEOWNERS paths (same owners), CONTRIBUTING.md plugin table, and fix the thread-abort-migration SKILL.md link in CONTRIBUTING.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
273 lines
9.8 KiB
YAML
273 lines
9.8 KiB
YAML
scenarios:
|
|
- name: "Worker thread with abort-based cancellation"
|
|
prompt: |
|
|
Migrate this .NET Framework code to .NET 8. Provide complete migration guidance with code and pitfalls.
|
|
|
|
```csharp
|
|
public class BackgroundProcessor
|
|
{
|
|
private Thread _workerThread;
|
|
private volatile bool _running;
|
|
|
|
public void Start()
|
|
{
|
|
_running = true;
|
|
_workerThread = new Thread(ProcessLoop);
|
|
_workerThread.IsBackground = true;
|
|
_workerThread.Start();
|
|
}
|
|
|
|
private void ProcessLoop()
|
|
{
|
|
while (_running)
|
|
{
|
|
try
|
|
{
|
|
var item = GetNextItem(); // may block
|
|
ProcessItem(item);
|
|
}
|
|
catch (ThreadAbortException)
|
|
{
|
|
// Clean up partial work
|
|
RollbackCurrentTransaction();
|
|
Thread.ResetAbort(); // prevent rethrow so finally runs cleanly
|
|
}
|
|
finally
|
|
{
|
|
FlushBuffers();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
_running = false;
|
|
if (_workerThread != null && _workerThread.IsAlive)
|
|
{
|
|
Thread.Sleep(2000); // give it time
|
|
if (_workerThread.IsAlive)
|
|
_workerThread.Abort(); // force stop
|
|
}
|
|
}
|
|
}
|
|
```
|
|
assertions:
|
|
- type: output_contains
|
|
value: "CancellationToken"
|
|
- type: output_contains
|
|
value: "OperationCanceledException"
|
|
- type: exit_success
|
|
rubric:
|
|
- "Replaces Thread.Abort with CancellationTokenSource.Cancel"
|
|
- "Migrates the ThreadAbortException catch block cleanup logic to a proper OperationCanceledException handler or finally block"
|
|
- "Addresses Thread.ResetAbort removal and explains why it is no longer needed"
|
|
- "Warns about passing CancellationToken through the full call chain including to GetNextItem"
|
|
- "Mentions that CancellationToken must be actively checked — it will not interrupt blocking calls like the original Thread.Abort did"
|
|
timeout: 120
|
|
|
|
- name: "Timeout enforcement via Thread.Abort"
|
|
prompt: |
|
|
Migrate this .NET Framework code to .NET 8. Provide complete migration guidance with code and pitfalls.
|
|
|
|
```csharp
|
|
public class TimedExecutor
|
|
{
|
|
public T ExecuteWithTimeout<T>(Func<T> work, TimeSpan timeout)
|
|
{
|
|
T result = default;
|
|
Exception error = null;
|
|
|
|
var thread = new Thread(() =>
|
|
{
|
|
try { result = work(); }
|
|
catch (ThreadAbortException) { Thread.ResetAbort(); }
|
|
catch (Exception ex) { error = ex; }
|
|
});
|
|
|
|
thread.Start();
|
|
|
|
if (!thread.Join(timeout))
|
|
{
|
|
thread.Abort();
|
|
throw new TimeoutException($"Operation exceeded {timeout.TotalSeconds}s timeout");
|
|
}
|
|
|
|
if (error != null)
|
|
throw new AggregateException(error);
|
|
|
|
return result;
|
|
}
|
|
}
|
|
```
|
|
assertions:
|
|
- type: output_contains
|
|
value: "CancellationTokenSource"
|
|
- type: output_contains
|
|
value: "CancelAfter"
|
|
- type: exit_success
|
|
rubric:
|
|
- "Replaces the Thread+Abort timeout pattern with CancellationTokenSource.CancelAfter or Task.WhenAny with Task.Delay"
|
|
- "Warns that the Func<T> work delegate must accept and check a CancellationToken for cancellation to actually work"
|
|
- "Mentions that if the work delegate cannot be modified (uncooperative code), the only safe option is process isolation with Process.Kill"
|
|
- "Does NOT suggest that wrapping in a Task and abandoning the thread is safe — the thread continues running"
|
|
- "Handles the case where the original code caught ThreadAbortException and called ResetAbort"
|
|
timeout: 120
|
|
|
|
- name: "Blocking WaitHandle with Thread.Interrupt"
|
|
prompt: |
|
|
Migrate this .NET Framework code to .NET 8. Provide complete migration guidance with code and pitfalls.
|
|
|
|
```csharp
|
|
public class EventProcessor
|
|
{
|
|
private readonly ManualResetEvent _newEvent = new ManualResetEvent(false);
|
|
private readonly Queue<string> _queue = new Queue<string>();
|
|
private Thread _thread;
|
|
private readonly object _lock = new object();
|
|
|
|
public void Start()
|
|
{
|
|
_thread = new Thread(RunLoop);
|
|
_thread.Start();
|
|
}
|
|
|
|
private void RunLoop()
|
|
{
|
|
while (true)
|
|
{
|
|
_newEvent.WaitOne(); // blocks until signaled
|
|
_newEvent.Reset();
|
|
|
|
string item;
|
|
lock (_lock) { item = _queue.Dequeue(); }
|
|
Handle(item);
|
|
}
|
|
}
|
|
|
|
public void Enqueue(string item)
|
|
{
|
|
lock (_lock) { _queue.Enqueue(item); }
|
|
_newEvent.Set();
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
_thread.Interrupt(); // wake from WaitOne
|
|
_thread.Join(5000);
|
|
if (_thread.IsAlive)
|
|
_thread.Abort();
|
|
}
|
|
}
|
|
```
|
|
assertions:
|
|
- type: output_contains
|
|
value: "CancellationToken"
|
|
- type: output_contains
|
|
value: "WaitHandle"
|
|
- type: exit_success
|
|
rubric:
|
|
- "Replaces Thread.Interrupt with CancellationToken signaling"
|
|
- "Shows how to combine WaitHandle.WaitAny with CancellationToken.WaitHandle to make the WaitOne call cancellable"
|
|
- "Removes Thread.Abort fallback and explains why it cannot be used"
|
|
- "Suggests using a modern alternative like Channel<T> or BlockingCollection<T> with cancellation support"
|
|
- "Warns that Thread.Interrupt only works on threads in WaitSleepJoin state and is not a reliable cancellation mechanism"
|
|
timeout: 120
|
|
|
|
- name: "ASP.NET Response.End and Response.Redirect with Thread.Abort"
|
|
prompt: |
|
|
Migrate this .NET Framework ASP.NET code to ASP.NET Core (.NET 8). Provide complete migration guidance with code and pitfalls.
|
|
|
|
```csharp
|
|
public class ReportController : Controller
|
|
{
|
|
protected void btnExport_Click(object sender, EventArgs e)
|
|
{
|
|
var data = GenerateReport();
|
|
Response.Clear();
|
|
Response.ContentType = "text/csv";
|
|
Response.AddHeader("Content-Disposition", "attachment; filename=report.csv");
|
|
Response.Write(data);
|
|
Response.End(); // throws ThreadAbortException internally
|
|
}
|
|
|
|
protected void btnRedirect_Click(object sender, EventArgs e)
|
|
{
|
|
if (!User.Identity.IsAuthenticated)
|
|
{
|
|
Response.Redirect("/login", true); // true = endResponse, calls Thread.Abort
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
ProcessRequest();
|
|
Response.Redirect("/success", true);
|
|
}
|
|
catch (ThreadAbortException)
|
|
{
|
|
// Expected from Response.Redirect — swallow it
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogError(ex);
|
|
Response.Redirect("/error", true);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
assertions:
|
|
- type: output_contains
|
|
value: "Redirect("
|
|
- type: output_not_matches
|
|
pattern: "Thread\\.Abort\\s*\\("
|
|
- type: exit_success
|
|
rubric:
|
|
- "Explains that Response.End and Response.Redirect(url, true) internally call Thread.Abort in ASP.NET Framework"
|
|
- "Replaces Response.End with returning a FileResult or writing to the response body and returning"
|
|
- "Replaces Response.Redirect(url, true) with a redirect result or Response.Redirect(url) without the endResponse parameter"
|
|
- "Removes the catch (ThreadAbortException) block and explains it is no longer needed"
|
|
- "Mentions HttpContext.RequestAborted as the cancellation mechanism in ASP.NET Core for long-running request work"
|
|
timeout: 120
|
|
|
|
- name: "Thread.Join and Thread.Sleep only — should not migrate"
|
|
prompt: |
|
|
I'm migrating this .NET Framework code to .NET 8 and need to ensure all Thread.Abort
|
|
usage is addressed. Check this code and provide your Thread.Abort migration guidance.
|
|
|
|
```csharp
|
|
public class SimpleWorker
|
|
{
|
|
public void RunBatch(List<WorkItem> items)
|
|
{
|
|
var threads = new List<Thread>();
|
|
|
|
foreach (var item in items)
|
|
{
|
|
var t = new Thread(() => Process(item));
|
|
t.Start();
|
|
threads.Add(t);
|
|
}
|
|
|
|
foreach (var t in threads)
|
|
t.Join();
|
|
}
|
|
|
|
private void Process(WorkItem item)
|
|
{
|
|
// simulate work
|
|
Thread.Sleep(100);
|
|
item.Result = ComputeResult(item.Input);
|
|
}
|
|
}
|
|
```
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "(no|not|don't|doesn't|without).{0,50}(migration|migrat|changes needed|changes required)|(already (compatible|works|supported))"
|
|
- type: exit_success
|
|
rubric:
|
|
- "Correctly identifies that this code does NOT use Thread.Abort, Thread.Interrupt, or ThreadAbortException"
|
|
- "Does NOT fabricate Thread.Abort migration concerns that do not exist in the code"
|
|
- "May suggest modernization to Task.Run or Parallel.ForEach, but does NOT frame it as a Thread.Abort migration"
|
|
- "Does NOT over-migrate — any suggestions should be optional improvements, not required fixes"
|
|
timeout: 120
|