$npx -y skills add wshaddix/dotnet-skills --skill dotnet-agent-gotchasGenerating or modifying .NET code. Common agent mistakes: async, NuGet, deprecated APIs, DI.
| 1 | # dotnet-agent-gotchas |
| 2 | |
| 3 | ## Overview / Scope Boundary |
| 4 | |
| 5 | Common mistakes AI agents make when generating or modifying .NET code, organized by category. Each category provides a brief warning, anti-pattern code, corrected code, and a cross-reference to the canonical skill that owns the deep guidance. This skill does NOT provide full implementation walkthroughs -- it surfaces the mistake and points to the right skill. |
| 6 | |
| 7 | **Out of scope:** Deep async/await patterns (owned by [skill:dotnet-csharp-async-patterns]), full dependency injection guidance (owned by [skill:dotnet-csharp-dependency-injection]), NRT usage patterns (owned by [skill:dotnet-csharp-nullable-reference-types]), source generator authoring (owned by [skill:dotnet-csharp-source-generators]), test framework features (owned by [skill:dotnet-testing-strategy]), security vulnerability mitigation (owned by [skill:dotnet-security-owasp]). |
| 8 | |
| 9 | ## Prerequisites |
| 10 | |
| 11 | .NET 8.0+ SDK. Familiarity with SDK-style projects and C# language features. |
| 12 | |
| 13 | Cross-references: [skill:dotnet-csharp-async-patterns], [skill:dotnet-csharp-dependency-injection], [skill:dotnet-csharp-nullable-reference-types], [skill:dotnet-csharp-source-generators], [skill:dotnet-testing-strategy], [skill:dotnet-security-owasp]. |
| 14 | |
| 15 | --- |
| 16 | |
| 17 | ## Category 1: Async/Await Misuse |
| 18 | |
| 19 | **Warning:** Agents frequently block on async methods using `.Result` or `.Wait()`, causing deadlocks in ASP.NET Core and UI contexts. Another common mistake is fire-and-forget calls that silently swallow exceptions. |
| 20 | |
| 21 | ### Anti-Pattern |
| 22 | |
| 23 | ```csharp |
| 24 | // WRONG: blocking on async -- deadlock risk in synchronization contexts |
| 25 | public Order GetOrder(int id) |
| 26 | { |
| 27 | var order = _repository.GetOrderAsync(id).Result; // DEADLOCK |
| 28 | return order; |
| 29 | } |
| 30 | |
| 31 | // WRONG: fire-and-forget with no error handling |
| 32 | public void ProcessOrder(Order order) |
| 33 | { |
| 34 | _ = _emailService.SendConfirmationAsync(order); // exception silently lost |
| 35 | } |
| 36 | ``` |
| 37 | |
| 38 | ### Corrected |
| 39 | |
| 40 | ```csharp |
| 41 | // CORRECT: async all the way |
| 42 | public async Task<Order> GetOrderAsync(int id, CancellationToken ct = default) |
| 43 | { |
| 44 | var order = await _repository.GetOrderAsync(id, ct); |
| 45 | return order; |
| 46 | } |
| 47 | |
| 48 | // CORRECT: background work via IHostedService or explicit error handling |
| 49 | public async Task ProcessOrderAsync(Order order, CancellationToken ct = default) |
| 50 | { |
| 51 | await _emailService.SendConfirmationAsync(order, ct); |
| 52 | } |
| 53 | ``` |
| 54 | |
| 55 | See [skill:dotnet-csharp-async-patterns] for full async/await guidance including `ValueTask`, `ConfigureAwait`, and cancellation propagation. |
| 56 | |
| 57 | --- |
| 58 | |
| 59 | ## Category 2: NuGet Package Errors |
| 60 | |
| 61 | **Warning:** Agents generate incorrect package names, reference pre-release versions without opt-in, or add packages that have been deprecated/replaced. ASP.NET Core shared-framework packages must match the project TFM major version. |
| 62 | |
| 63 | ### Anti-Pattern |
| 64 | |
| 65 | ```xml |
| 66 | <!-- WRONG: package name does not exist (correct: Microsoft.EntityFrameworkCore) --> |
| 67 | <PackageReference Include="EntityFrameworkCore" Version="9.0.0" /> |
| 68 | |
| 69 | <!-- WRONG: hardcoded version for shared-framework package -- must match TFM --> |
| 70 | <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" /> |
| 71 | <!-- This breaks on net8.0 projects --> |
| 72 | |
| 73 | <!-- WRONG: agents add Swashbuckle by default; .NET 9+ templates use built-in OpenAPI --> |
| 74 | <PackageReference Include="Swashbuckle.AspNetCore" Version="7.0.0" /> |
| 75 | <!-- Swashbuckle is still valid when Swagger UI is needed, but not the default choice --> |
| 76 | ``` |
| 77 | |
| 78 | ### Corrected |
| 79 | |
| 80 | ```xml |
| 81 | <!-- CORRECT: exact package ID --> |
| 82 | <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" /> |
| 83 | |
| 84 | <!-- CORRECT: use version variable or central package management to match TFM --> |
| 85 | <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" /> |
| 86 | <!-- Version managed via Directory.Packages.props matching project TFM --> |
| 87 | |
| 88 | <!-- CORRECT: .NET 9+ templates prefer built-in OpenAPI support --> |
| 89 | <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" /> |
| 90 | <!-- Swashbuckle remains a valid choice when Swagger UI features are needed --> |
| 91 | ``` |
| 92 | |
| 93 | See [skill:dotnet-csproj-reading] for project file conventions and central package management guidance. |
| 94 | |
| 95 | --- |
| 96 | |
| 97 | ## Category 3: Deprecated API Usage |
| 98 | |
| 99 | **Warning:** Agents generate code using deprecated and insecure APIs: `BinaryFormatter` (CVE-prone deserialization), `WebClient` (replaced by `HttpClient`), and older cryptography APIs (`RNGCryptoServiceProvider`, `SHA1CryptoServiceProvider`). |
| 100 | |
| 101 | ### Anti-Pattern |
| 102 | |
| 103 | ```csharp |
| 104 | // WRONG: BinaryFormatter is banned in .NET 8+ (SYSLIB0011) |
| 105 | var formatter = new BinaryFormatter(); |
| 106 | formatter.Serialize(stream, data); |
| 107 | |
| 108 | // WRONG: WebClient is obsolete -- use HttpClient via IHttpClientFactory |
| 109 | var client = new WebClient(); |
| 110 | var html = client.DownloadString("https://example.com"); |
| 111 | |
| 112 | // WRONG: obsolete crypto API (SYSLIB0023) |
| 113 | using var rng = new RNGCryptoServiceProvider(); |
| 114 | rng.GetBytes(buffer); |
| 115 | ``` |
| 116 | |
| 117 | ### Corrected |
| 118 | |
| 119 | ```csharp |
| 120 | // CORRECT: use |