General .NET Detectors
These detectors flag common .NET anti-patterns. They work on any .NET codebase.
AP001 — AsyncVoidDetector
Severity: Error
Detects async void methods. These cannot be awaited, swallow exceptions, and cause
unpredictable behavior. Use async Task instead.
// Bad
public async void DoWork() { await Task.Delay(1); }
// Good
public async Task DoWork() { await Task.Delay(1); }
Exception: Event handlers (void OnClick(object sender, EventArgs e)) are excluded.
AP002 — SyncOverAsyncDetector
Severity: Warning
Detects synchronous blocking on async code: .Result, .Wait(), .GetAwaiter().GetResult().
These cause deadlocks in ASP.NET Core.
// Bad
var result = GetDataAsync().Result;
GetDataAsync().Wait();
var result = GetDataAsync().GetAwaiter().GetResult();
// Good
var result = await GetDataAsync();
AP003 — HttpClientInstantiationDetector
Severity: Warning
Detects new HttpClient(). This causes socket exhaustion under load.
Use IHttpClientFactory instead.
// Bad
var client = new HttpClient();
// Good — inject via DI
public MyService(IHttpClientFactory factory)
{
var client = factory.CreateClient();
}
AP004 — DateTimeDirectUseDetector
Severity: Warning
Detects DateTime.Now and DateTime.UtcNow. These are untestable.
Inject TimeProvider (or IClock) instead.
// Bad
var now = DateTime.UtcNow;
// Good
public MyService(TimeProvider timeProvider)
{
var now = timeProvider.GetUtcNow();
}
AP005 — BroadCatchDetector
Severity: Warning
Detects catch (Exception) without a re-throw. Broad catches hide bugs and
swallow critical exceptions like OutOfMemoryException.
// Bad
catch (Exception ex) { logger.LogError(ex, "Failed"); }
// Good
catch (Exception ex) { logger.LogError(ex, "Failed"); throw; }
// Better — catch specific exceptions
catch (HttpRequestException ex) { ... }
AP006 — LoggingInterpolationDetector
Severity: Warning
Detects string interpolation in log calls. Interpolated strings are always allocated, even when the log level is disabled. Use structured logging templates.
// Bad
logger.LogInformation($"User {userId} logged in");
// Good
logger.LogInformation("User {UserId} logged in", userId);
AP007 — PragmaWithoutRestoreDetector
Severity: Info
Detects #pragma warning disable without a matching #pragma warning restore.
Forgotten restores suppress warnings for the rest of the file.
AP008 — MissingCancellationTokenDetector
Severity: Info
Detects async methods that don't accept a CancellationToken parameter.
Without cancellation support, long-running operations cannot be stopped gracefully.
Note: Requires semantic model (full compilation). Skipped in syntax-only mode.
AP009 — EfCoreNoTrackingDetector
Severity: Info
Detects EF Core queries that don't use .AsNoTracking(). Read-only queries
should use AsNoTracking() to avoid change tracker overhead.
Note: Requires semantic model (full compilation). Skipped in syntax-only mode.