Skip to content

[Bug]: Reflection PropertyInjector double-injects IAsyncInitializer properties #5753

@thomhurst

Description

@thomhurst

Summary

In reflection mode, every test resolves data-source-injected properties twice, and the second injection overwrites the property with a fresh instance whose IAsyncInitializer.InitializeAsync is never called. The bug is masked today by ObjectLifecycleService re-walking the live graph at execution time, but it surfaces immediately if that walk is removed (see closed PR #5748).

Root cause

Two interacting issues:

  1. RegisterTestArgumentsAsync is called twice per test:

  2. PropertyInjector.InjectReflectionPropertyAsync lacks the existingValue != null → skip guard that InjectSourceGeneratedPropertyAsync (PropertyInjector.cs:257-265) has.

Combined effect:

  • 1st injection — instance A — gets tracked + initialised.
  • 2nd injection — instance B — overwrites the property reference. Never tracked, never initialised.
  • Test method reads the property → sees instance B, in uninitialised state.

Source-gen mode is unaffected because of the existing skip-if-set guard.

Why it's invisible today

ObjectLifecycleService.InitializeObjectWithSpanAsync calls InitializeNestedObjectsForExecutionAsync(obj) on the live graph at execution time, re-initialising whatever instance is currently bound. This masks the latent bug.

Reproduction (after removing the masking walk)

Apply the change from PR #5748 and run in reflection mode:

  • Bugs._2955.InheritedDataSourceTests.Test_DirectDataSource_WorksCorrectly
  • CombinedDataSourceTests.CombinedDataSource_WithNestedPropertyInjectionAndMultipleIAsyncInitializers

Both fail because the test reads an uninitialised second-instance property.

Proposed fix

Either or both:

  1. Apply the source-gen "skip if set" guard to InjectReflectionPropertyAsync so a second injection is a no-op.
  2. De-dupe the two RegisterTestArgumentsAsync call sites (TestBuilder + TestFilterService), or make the second one idempotent.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    .NETPull requests that update .net codebugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions