From 3ac4999d0a996c32be4fa4842ce34812ac34f418 Mon Sep 17 00:00:00 2001 From: Tomas Prokop Date: Fri, 3 Jul 2026 15:12:05 +0200 Subject: [PATCH] fix(shim): resolve real org version instead of hardcoded 9.2.0.0 fallback CrmServiceClient's ConnectedOrgVersion hardcoded a 9.2.0.0 fallback whenever the base ServiceClient returned its own default of 9.0.0.0, which happens under the token-provider (ExternalTokenManagement) constructor path. That constant is below CMT's UpsertMultiple batch-mode version gate (9.2.23083.00120), so CMT silently fell back to slow, one-by-one Create/Update calls through our shim regardless of how modern the real connected org actually is. Confirmed live against a current Dataverse online environment (real version 9.2.26061.150, SDK 1.2.10): - ConnectedOrgVersion initially reports the SDK's stub default 9.0.0.0. - ServiceClient.OrganizationDetail (public property, forces a real RefreshInstanceDetails) correctly returns the real version. - Execute(new RetrieveVersionRequest()) also correctly returns the real version, as a further fallback. Replaced the hardcoded constant with a cascade using only public SDK APIs: base property -> OrganizationDetail -> RetrieveVersionRequest, falling back to the honest SDK default only if every mechanism fails. Filed upstream: microsoft/PowerPlatform-DataverseServiceClient#538 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CrmServiceClient.cs | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/TALXIS.CLI.Platform.XrmShim/CrmServiceClient.cs b/src/TALXIS.CLI.Platform.XrmShim/CrmServiceClient.cs index dc2daea..84ca41b 100644 --- a/src/TALXIS.CLI.Platform.XrmShim/CrmServiceClient.cs +++ b/src/TALXIS.CLI.Platform.XrmShim/CrmServiceClient.cs @@ -1,3 +1,4 @@ +using Microsoft.Crm.Sdk.Messages; using Microsoft.PowerPlatform.Dataverse.Client; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Messages; @@ -157,12 +158,26 @@ public CrmServiceClient(Uri instanceUrl, bool useUniqueInstance) /// Hides the base which /// returns the hardcoded default 9.0.0.0 when the token-provider /// constructor path is used (the SDK's ExternalTokenManagement path - /// skips GetServerVersion/RefreshInstanceDetails). + /// sets OrganizationVersion = 9.0.0.0 at connect time and skips the + /// normal server-version discovery — see + /// ConnectionService.cs in the Dataverse SDK source). /// - /// When the base property still returns 9.0.0.0 this property falls back - /// to 9.2.0.0 — the minimum version of any modern Power Platform - /// environment — so Package Deployer's SolutionPackageVersion - /// compatibility check does not reject solutions built against the 9.1 schema. + /// Rather than guessing a constant, this recovers the real org version + /// using public SDK APIs, in order of cost: + /// + /// + /// The base property, in case it is already populated. + /// , whose getter + /// triggers the SDK's internal RefreshInstanceDetails and is confirmed + /// (via live testing) to return the real version even on the + /// ExternalTokenManagement path. + /// , a strongly-typed + /// SOAP request confirmed (via live testing) to succeed and return the real + /// version as a last resort. + /// + /// + /// If every mechanism still returns the SDK default, the base value is + /// returned as-is rather than substituting a hardcoded lie. /// /// public new Version ConnectedOrgVersion @@ -172,19 +187,36 @@ public CrmServiceClient(Uri instanceUrl, bool useUniqueInstance) if (_cachedOrgVersion != null) return _cachedOrgVersion; + var sdkDefault = new Version(9, 0, 0, 0); + var baseVersion = base.ConnectedOrgVersion; - if (baseVersion > new Version(9, 0, 0, 0)) + if (baseVersion > sdkDefault) + return _cachedOrgVersion = baseVersion; + + // Base returned the SDK's hardcoded default — this happens because + // the ExternalTokenManagement path skips server version discovery at + // connect time. Accessing OrganizationDetail forces the SDK to + // actually retrieve it. + if (Version.TryParse(base.OrganizationDetail?.OrganizationVersion, out var detailVersion) + && detailVersion > sdkDefault) + { + return _cachedOrgVersion = detailVersion; + } + + baseVersion = base.ConnectedOrgVersion; + if (baseVersion > sdkDefault) + return _cachedOrgVersion = baseVersion; + + // Last resort: explicitly ask the server via a strongly-typed request. + if (base.Execute(new RetrieveVersionRequest()) is RetrieveVersionResponse retrieveVersionResponse + && Version.TryParse(retrieveVersionResponse.Version, out var requestVersion) + && requestVersion > sdkDefault) { - _cachedOrgVersion = baseVersion; - return baseVersion; + return _cachedOrgVersion = requestVersion; } - // Base returned the SDK's hardcoded default (9.0.0.0) — this happens - // because the ExternalTokenManagement path skips server version discovery. - // All modern Power Platform environments are at least 9.2; return that - // so Package Deployer's SolutionPackageVersion compatibility check passes. - _cachedOrgVersion = new Version(9, 2, 0, 0); - return _cachedOrgVersion; + // Give up honestly rather than hardcoding a fallback constant. + return base.ConnectedOrgVersion; } }