DYN-10444: Fix PathManager version resolution for host integrations and Sandbox#17083
Conversation
Restore host-aware stack fallback when PathManager is created before host path is assigned (C3D/Revit early startup order). Remove executable-version based fallback that could pick host process version (for example 32.0) and create wrong folders. Keep Sandbox behavior stable by preferring DynamoCore version fallback, so AppData stays on the Dynamo version folder (for example 4.1). Preserve the Sandbox regression fix intent while avoiding dual folder creation across launches.
There was a problem hiding this comment.
See the ticket for this pull request: https://jira.autodesk.com/browse/DYN-10444
|
There was a problem hiding this comment.
Pull request overview
This PR adjusts how PathManager resolves the versioned data-folder path so that host integrations (e.g., Revit/Civil3D) and Sandbox resolve versions consistently even when PathManager is created before host context is fully assigned.
Changes:
- Ensure
PathManager.Initializeis called with host context earlier duringDynamoModelstartup. - Update
PathManager’s assembly-selection logic to include an additional stack-walk fallback when no host directory is configured. - Update inline documentation describing the version-resolution order.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/DynamoCore/Models/DynamoModel.cs |
Always initializes the PathManager singleton with HostPath before first access. |
src/DynamoCore/Configuration/PathManager.cs |
Adds a “no host directory configured” stack-walk fallback and updates the documented resolution order. |
| /// 3) If no host directory is configured, first non-system, non-test assembly | ||
| /// on the current managed call stack that resides outside the DynamoCore directory. | ||
| /// 4) DynamoCore assembly location (preferred over external process assemblies). | ||
| /// 5) Entry assembly location. | ||
| /// 6) Current process main module path. |
There was a problem hiding this comment.
The updated resolution-order XML doc for step (3) says it returns the first non-system, non-test assembly outside the DynamoCore directory, but the new implementation additionally filters to assemblies whose name contains "Dynamo". Please update the doc to reflect this constraint (or relax the filter) so behavior matches documentation.
| // Option 3: When there is no configured host directory yet, still try | ||
| // to discover a likely host integration assembly on the current call stack. | ||
| if (string.IsNullOrEmpty(hostApplicationDirectory)) | ||
| { | ||
| var currentAssembly = typeof(PathManager).Assembly; | ||
| var stackTrace = new StackTrace(skipFrames: 1, fNeedFileInfo: false); | ||
|
|
||
| foreach (var frame in stackTrace.GetFrames() ?? Array.Empty<StackFrame>()) | ||
| { | ||
| var assembly = frame.GetMethod()?.DeclaringType?.Assembly; | ||
| if (assembly == null || assembly == currentAssembly || assembly.IsDynamic) | ||
| continue; | ||
|
|
||
| var assemblyName = assembly.GetName().Name; | ||
| if (string.IsNullOrEmpty(assemblyName)) | ||
| continue; | ||
|
|
||
| if (assemblyName.StartsWith("System", StringComparison.OrdinalIgnoreCase) || | ||
| assemblyName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase) || | ||
| assemblyName.Equals("mscorlib", StringComparison.OrdinalIgnoreCase) || | ||
| assemblyName.Equals("netstandard", StringComparison.OrdinalIgnoreCase) || | ||
| assemblyName.IndexOf("test", StringComparison.OrdinalIgnoreCase) >= 0) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| // Without a configured host directory, only consider likely | ||
| // Dynamo integration assemblies to avoid selecting framework | ||
| // assemblies (e.g. WPF/.NET) that can carry unrelated versions | ||
| // such as 10.0 for Sandbox startup. | ||
| if (assemblyName.IndexOf("Dynamo", StringComparison.OrdinalIgnoreCase) < 0) | ||
| continue; | ||
|
|
||
| var candidatePath = assembly.Location; | ||
|
|
||
| // Skip assemblies that live in the same directory as DynamoCore. | ||
| if (IsPathUnderDirectory(candidatePath, dynamoCoreDir)) | ||
| continue; | ||
|
|
||
| if (HasNonZeroFileVersion(candidatePath)) | ||
| return candidatePath; | ||
| } | ||
| } |
There was a problem hiding this comment.
The newly added Option 3 stack-walk logic is central to the version-resolution behavior change, but there doesn’t appear to be test coverage that exercises this path (hostApplicationDirectory unset + host integration assembly on the call stack). Consider adding an NUnit test that validates the chosen version source in this scenario (or refactoring to make the selection logic testable without relying on the real call stack).
| foreach (var frame in stackTrace.GetFrames() ?? Array.Empty<StackFrame>()) | ||
| { | ||
| var assembly = frame.GetMethod()?.DeclaringType?.Assembly; | ||
| if (assembly == null || assembly == currentAssembly || assembly.IsDynamic) | ||
| continue; | ||
|
|
||
| var assemblyName = assembly.GetName().Name; | ||
| if (string.IsNullOrEmpty(assemblyName)) | ||
| continue; | ||
|
|
||
| if (assemblyName.StartsWith("System", StringComparison.OrdinalIgnoreCase) || | ||
| assemblyName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase) || | ||
| assemblyName.Equals("mscorlib", StringComparison.OrdinalIgnoreCase) || | ||
| assemblyName.Equals("netstandard", StringComparison.OrdinalIgnoreCase) || | ||
| assemblyName.IndexOf("test", StringComparison.OrdinalIgnoreCase) >= 0) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| // Without a configured host directory, only consider likely | ||
| // Dynamo integration assemblies to avoid selecting framework | ||
| // assemblies (e.g. WPF/.NET) that can carry unrelated versions | ||
| // such as 10.0 for Sandbox startup. | ||
| if (assemblyName.IndexOf("Dynamo", StringComparison.OrdinalIgnoreCase) < 0) | ||
| continue; | ||
|
|
||
| var candidatePath = assembly.Location; | ||
|
|
||
| // Skip assemblies that live in the same directory as DynamoCore. | ||
| if (IsPathUnderDirectory(candidatePath, dynamoCoreDir)) | ||
| continue; | ||
|
|
||
| if (HasNonZeroFileVersion(candidatePath)) | ||
| return candidatePath; | ||
| } |
|
/cherrypick |
|
/cherrypick |
|
Only merged pull requests can be backported. |
|
Rerun SelfServ - success: https://c007.cloudbees-ci.autodesk.com/job/DYNCI/job/Dynamo/job/DynamoSelfServe/job/pullRequestValidation/148/ Rerun SonarQube - Success: https://c007.cloudbees-ci.autodesk.com/job/DYNCI/job/Dynamo/job/DynamoCACoverage/job/SonarPrScan/129/ Rerun SmokeTest - success: https://c007.cloudbees-ci.autodesk.com/job/DYNCI/job/Dynamo/job/DynamoAGTTests/job/smoke/138/ Merging |
|
/cherrypick |
|
Successfully created backport PR for |





Purpose
Restore host-aware stack fallback when PathManager is created before host path is assigned (C3D/Revit early startup order). Remove executable-version based fallback that could pick host process version (for example 32.0) and create wrong folders. Keep Sandbox behavior stable by preferring DynamoCore version fallback, so AppData stays on the Dynamo version folder (for example 4.1). Preserve the Sandbox regression fix intent while avoiding dual folder creation across launches.
Declarations
Check these if you believe they are true
Release Notes
Fix PathManager version resolution for host integrations and Sandbox
Reviewers
@aparajit-pratap @jasonstratton
FYIs
@johnpierson