Skip to content

Fix Auto-injection packaging for release artifacts - #18

Closed
miloszkukla wants to merge 5 commits into
faze79:mainfrom
miloszkukla:agent/fix-auto-injection-packaging
Closed

miloszkukla wants to merge 5 commits into
faze79:mainfrom
miloszkukla:agent/fix-auto-injection-packaging

Conversation

@miloszkukla

@miloszkukla miloszkukla commented Aug 13, 2026

Copy link
Copy Markdown

Important

This PR is stacked after #20. Merge #20 first, then this PR, using merge commits. Because GitHub cannot use a contributor-fork branch as the base of an upstream PR, this diff is temporarily cumulative; the shared commits have identical IDs and will disappear from this PR after #20 is merged. PR #19 follows this PR, then #21.

Summary

  • build the x64 and Win32 native bootstrapper before CI and release packaging
  • package the complete .NET Framework Inspector dependency closure under both architecture directories
  • resolve the Inspector's co-located private dependencies when the target app has no matching binding redirects
  • use the standard CoreCLR runtimeconfig filename so it remains below MAX_PATH in a NuGet tool installation
  • fail publish/pack and CI artifact verification when required Auto-injection files are missing

Root cause

The native .vcxproj is not part of WpfVisualTreeMcp.sln, so dotnet build never produced WpfInspectorBootstrapper.dll. The Server project then silently omitted it through Condition="Exists(...)".

The package also copied only WpfVisualTreeMcp.Inspector.dll and WpfVisualTreeMcp.Shared.dll, excluding the .NET Framework Inspector's runtime dependencies. Copying those dependencies exposed an assembly-version mismatch normally handled by application binding redirects, which cannot be assumed for injection into arbitrary target processes.

Finally, the custom CoreCLR runtimeconfig filename exceeded the legacy Win32 path limit inside the deeply nested NuGet tool store.

Validation

  • dotnet build WpfVisualTreeMcp.sln --configuration Release — 0 errors (existing cross-TFM warnings unchanged)
  • dotnet test WpfVisualTreeMcp.sln --no-build --configuration Release — 74/74 passed before stacking Add .NET Framework 4.7.2 Inspector support #20
  • built and verified x64 and Win32 WpfInspectorBootstrapper.dll PE outputs
  • verified publish and NuGet payloads contain both bootstrappers, both CoreCLR runtimeconfigs, and all 11 .NET Framework Inspector DLLs under x64 and x86
  • installed the generated .nupkg into an isolated tool directory
  • Auto-injected a clean, non-self-hosted .NET Framework WPF app and retrieved its visual tree
  • Auto-injected a clean, non-self-hosted modern .NET WPF app and retrieved its visual tree

@miloszkukla
miloszkukla marked this pull request as ready for review August 14, 2026 05:13
Copilot AI lite review requested due to automatic review settings August 14, 2026 05:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the reliability of Auto-injection when publishing/packing the server by ensuring the native bootstrapper and the full .NET Framework Inspector dependency closure are built, included in artifacts, and validated in CI. It also extends the Shared/Inspector target framework matrix (net472 + tests) and adjusts runtime dependency resolution behavior for injected .NET Framework scenarios.

Changes:

  • Build x64/Win32 native bootstrappers in CI and fail artifact/package creation if required Auto-injection payload files are missing.
  • Package the full .NET Framework Inspector dependency closure under both native/x64 and native/x86, and add an MSBuild validation target to prevent silent omission during Publish/Pack.
  • Expand multi-targeting to include net472 and add Shared-level regression tests (Shared models + IPC serializer envelope).

Reviewed changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
WpfVisualTreeMcp.sln Adds the new Shared test project to the solution.
tests/WpfVisualTreeMcp.Shared.Tests/WpfVisualTreeMcp.Shared.Tests.csproj New multi-targeted (net8/net472/net48) test project for Shared.
tests/WpfVisualTreeMcp.Shared.Tests/SharedModelsTests.cs Adds basic Shared model shape/regression tests.
tests/WpfVisualTreeMcp.Shared.Tests/IpcSerializerTests.cs Adds regression tests for IPC envelope serialization/deserialization.
src/WpfVisualTreeMcp.Shared/WpfVisualTreeMcp.Shared.csproj Adds net472 and ensures System.Text.Json package is included for .NET Framework TFMs.
src/WpfVisualTreeMcp.Server/WpfVisualTreeMcp.Server.csproj Packages full net48 Inspector dependency closure per-arch and validates required injection payload before Publish/Pack; standardizes runtimeconfig name in package layout.
src/WpfVisualTreeMcp.Inspector/WpfVisualTreeMcp.Inspector.csproj Adds net472 target and aligns explicit WPF references for net472/net48.
src/WpfVisualTreeMcp.Inspector/InspectorService.cs Adds .NET Framework private dependency resolver hook for injected scenarios.
src/WpfVisualTreeMcp.Injector/WpfVisualTreeMcp.Injector.csproj Simplifies Injector to target net8.0 only.
README.md Updates docs to reflect Inspector multi-targeting and project structure.
CHANGELOG.md Adds Unreleased entries describing Auto-injection packaging fixes.
.github/workflows/release.yml Builds native bootstrapper and verifies publish + NuGet payload completeness in release workflow.
.github/workflows/build.yml Builds native bootstrapper and verifies publish + NuGet payload completeness in CI build workflow.
Suppressed comments (2)

src/WpfVisualTreeMcp.Inspector/InspectorService.cs:126

  • Initialize() registers the dependency resolver only for NET48. With net472 now supported, this should be enabled for all .NET Framework builds so injected/self-hosted net472 Inspectors can resolve their co-located dependencies in processes without binding redirects.
#if NET48
                RegisterDependencyResolver();
#endif

src/WpfVisualTreeMcp.Inspector/InspectorService.cs:141

  • RegisterDependencyResolver() is guarded by #if NET48, which prevents the resolver (and its supporting fields) from being available to the net472 Inspector build. Guarding by NETFRAMEWORK keeps the behavior consistent across .NET Framework targets.
#if NET48

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

private bool _disposed;

private static readonly object _initLock = new();
#if NET48

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in consolidated PR #22 (commit 35c1177): the resolver, its fields, and System.Reflection import now use NETFRAMEWORK, so both net472 and net48 receive the co-located dependency resolver.

Comment thread README.md
Comment on lines +474 to 475
│ ├── WpfVisualTreeMcp.Inspector/ # Injected DLL (.NET Framework 4.7.2/4.8 and .NET 8)
│ ├── WpfVisualTreeMcp.Injector/ # Managed injection logic (CreateRemoteThread; net48 + net8.0)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already corrected in consolidated PR #22: the root README describes WpfVisualTreeMcp.Injector as .NET 8 only. #22 supersedes this stacked PR.

@miloszkukla

Copy link
Copy Markdown
Author

Superseded by #22, which consolidates the full change set and incorporates the applicable review feedback. Closing this stacked PR to avoid duplicate review threads and workflow ambiguity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants