Upgrading

Move to 3.10 without guessing why findings changed

Diagnostic IDs and default severities are stable. Releases can still remove findings when a rule is narrowed to avoid a proven false positive.

Upgrading

The analyzer package follows SemVer. Diagnostic IDs, default severities, and code-fix behavior are the stable contract; releases can still remove findings when a rule is narrowed to avoid a proven false positive. This page records the behavior changes that can move a build from green to clean, or from noisy to quiet.

3.9.x

3.9.0 — DI001 and DI019 scope wrappers

canonical if (scope is IAsyncDisposable alias) await alias.DisposeAsync(); else scope.Dispose(); shape plus scopes stored in a field and disposed by the owning type.

the singleton's own or inherited provider properties, known host properties, and real scope providers qualify.

  • DI001 treats a scope wrapped in a directly returned object as caller-owned, and recognizes the
  • DI019 no longer treats a custom wrapper's ServiceProvider property as the root provider. Only

If a previously reported finding disappeared, check whether the scope is now proven caller-owned or the provider is a custom wrapper. If the new result is wrong, open a false-negative report.

3.10.1 — test and mutation hardening

assignability, constructor selection, and keyed-service extraction.

changes.

  • The shared-resolution-helper mutation gate rises from 80.00% to 94.92%, with direct tests for
  • The nullable assignability check is expressed as explicit guards. No analyzer or scanner behavior

3.10.0 — scanner UX and maintenance

second mutation shard.

  • di-scan --fix applies safe code fixes with dotnet format.
  • di-scan --update-baseline <file> writes a text baseline that --baseline reads back.
  • Windows/macOS scanner CI, false-positive/negative issue forms, Dependabot, CODEOWNERS, and a
  • No analyzer behavior changes.

3.9.1–3.9.3 — packaging and discoverability

No analyzer behavior changes. These releases shipped the concise NuGet README, the scanner docs page, NuGet metadata, and GitHub topics.

3.8.0 — scanner, profiles, and test-code suppression

directories, type/namespace names, base types, and test attributes. Findings in test projects disappear by design. If a production project is named or laid out like a test project, override the suppressor with a narrow #pragma or an .editorconfig severity.

DbContextOptions<TContext> as satisfying a non-generic DbContextOptions dependency.

docs/rules/.

  • Test code is suppressed using the HttpClient analyzer conventions: test project names,
  • DI001 recognizes conditional async disposal and field-owned scopes.
  • DI006 skips custom, stateless IServiceProvider null-object providers.
  • DI015 skips type parameters and closed generics containing them, and treats any registered
  • The package now ships starter profiles under profiles/ and one page per rule under

Keeping the previous behavior

Pin the last version that matched your policy:

<PackageReference Include="DependencyInjection.Lifetime.Analyzers" Version="3.7.8">
  <PrivateAssets>all</PrivateAssets>
</PackageReference>

Or keep the newer analyzer and lower one rule:

[*.cs]
dotnet_diagnostic.DI015.severity = none

For DI015's framework-service assumption, use the documented option:

[*.cs]
dotnet_code_quality.DI015.assume_framework_services_registered = false

Regenerating a scanner baseline

When a reviewed behavior change intentionally removes findings, regenerate only the affected baseline and review the diff:

di-scan ./MyApp.slnx --update-baseline di.baseline
git diff di.baseline

For the pinned repository corpus:

pwsh ./scripts/Invoke-ScanRegression.ps1 -UpdateBaselines
git diff tests/scan-corpus/baselines

Never hand-edit a baseline to make a failing scan pass.

Cross-project composition

DI015 analyzes one compilation at a time. A library cannot see a registration added by a downstream web project, so a partial composition root can report a missing dependency that the application actually registers. Run the scanner against the composition-root project, or lower DI015 for the library, and record the target as a partial composition root.

Reporting a change

Use the dedicated false-positive or false-negative form. Include the rule ID, package or scanner version, the smallest repro, and the expected lifetime or activation result.