From 7f0de25377d860b7af6338e2f7d643c461cded9e Mon Sep 17 00:00:00 2001 From: MattB Date: Tue, 19 Jul 2022 11:39:55 -0700 Subject: [PATCH] Resync from Main Branch --- src/Build.Shared.props | 2 +- .../Client/ConnectionService.cs | 48 ++++++++++--------- .../Client/DataverseTelemetryBehaviors.cs | 1 + .../DataverseClient/Client/ServiceClient.cs | 1 + .../DataverseClient/Client/Utils/Utils.cs | 24 +++++++++- ...Platform.Dataverse.Client.ReleaseNotes.txt | 5 ++ 6 files changed, 56 insertions(+), 25 deletions(-) diff --git a/src/Build.Shared.props b/src/Build.Shared.props index 66f3140..90a6744 100644 --- a/src/Build.Shared.props +++ b/src/Build.Shared.props @@ -15,7 +15,7 @@ 4.7.6346-master 13.0.1 2.3.20 - 9.0.2.42 + 9.0.2.45 9.0.2.34 2.0.19 0.4.20 diff --git a/src/GeneralTools/DataverseClient/Client/ConnectionService.cs b/src/GeneralTools/DataverseClient/Client/ConnectionService.cs index 3a322ec..326eaa0 100644 --- a/src/GeneralTools/DataverseClient/Client/ConnectionService.cs +++ b/src/GeneralTools/DataverseClient/Client/ConnectionService.cs @@ -1742,7 +1742,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client { cancellationToken.ThrowIfCancellationRequested(); - if (!Utilities.IsRequestValidForTranslationToWebAPI(req , inLoginFlow)) // THIS WILL GET REMOVED AT SOME POINT, TEMP FOR TRANSTION //TODO:REMOVE ON COMPELTE + if (!Utilities.IsRequestValidForTranslationToWebAPI(req , inLoginFlow)) { logEntry.Log("Execute Organization Request failed, WebAPI is only supported for limited type of messages at this time.", TraceEventType.Error); return null; @@ -1750,15 +1750,16 @@ namespace Microsoft.PowerPlatform.Dataverse.Client HttpMethod methodToExecute = Utilities.RequestNameToHttpVerb(req.RequestName); Entity cReq = null; - if (req.Parameters.ContainsKey("Target") && req.Parameters["Target"] is Entity ent) // this should cover things that have targets. + if (req.Parameters.ContainsKey("Target") && req.Parameters["Target"] is Entity ent) { cReq = ent; } - else if (req.Parameters.ContainsKey("Target") && req.Parameters["Target"] is EntityReference entRef) // this should cover things that have targets. + else if (req.Parameters.ContainsKey("Target") && req.Parameters["Target"] is EntityReference entRef) { cReq = entRef.KeyAttributes.Any() ? new Entity(entRef.LogicalName, entRef.KeyAttributes) : new Entity(entRef.LogicalName, entRef.Id); + cReq.RowVersion = entRef.RowVersion; } EntityMetadata entityMetadata = null; @@ -1861,7 +1862,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client } else { - DataverseOperationException opEx = new DataverseOperationException("Request Failed, RowVersion is missing and is required when ConcurrencyBehavior is set to a value other then Default."); + DataverseOperationException opEx = new DataverseOperationException("Request Failed, RowVersion is missing and is required when ConcurrencyBehavior is set to a value other than Default."); logEntry.Log(opEx); return null; } @@ -2145,9 +2146,16 @@ namespace Microsoft.PowerPlatform.Dataverse.Client foreach (var hrdProp in addedHeaders) { // General handling from here on out. - if (!customHeaders.ContainsKey(hrdProp.Key)) + if (customHeaders.Keys.Contains(hrdProp.Key)) { - customHeaders[hrdProp.Key] = new List() { hrdProp.Value }; + if (customHeaders[hrdProp.Key] == null) + customHeaders[hrdProp.Key] = new List(); + + customHeaders[hrdProp.Key].Add(hrdProp.Value); + } + else + { + customHeaders.Add(hrdProp.Key, new List() { hrdProp.Value }); } } addedHeaders.Clear(); @@ -2359,30 +2367,24 @@ namespace Microsoft.PowerPlatform.Dataverse.Client _httpRequest.RequestUri = new System.Uri(uri); // Set Headers + // Add User Agent and request id to send. + string Agent = "Unknown"; + if (AppDomain.CurrentDomain != null) + { + Agent = AppDomain.CurrentDomain.FriendlyName; + } + Agent = $"{Agent} (DataverseSvcClient:{Environs.DvSvcClientFileVersion})"; + + if (!_httpRequest.Headers.Contains(Utilities.RequestHeaders.USER_AGENT_HTTP_HEADER)) + _httpRequest.Headers.TryAddWithoutValidation(Utilities.RequestHeaders.USER_AGENT_HTTP_HEADER, string.IsNullOrEmpty(Agent) ? "" : Agent); + if (customHeaders != null) { foreach (var _header in customHeaders) { - if (_httpRequest.Headers.Count() > 0) - if (_httpRequest.Headers.Contains(_header.Key)) - { - _httpRequest.Headers.Remove(_header.Key); - } _httpRequest.Headers.TryAddWithoutValidation(_header.Key, _header.Value); } - // Add User Agent and request id to send. - string Agent = "Unknown"; - if (AppDomain.CurrentDomain != null) - { - Agent = AppDomain.CurrentDomain.FriendlyName; - } - Agent = $"{Agent} (DataverseSvcClient:{Environs.DvSvcClientFileVersion})"; - - - if (!_httpRequest.Headers.Contains(Utilities.RequestHeaders.USER_AGENT_HTTP_HEADER)) - _httpRequest.Headers.TryAddWithoutValidation(Utilities.RequestHeaders.USER_AGENT_HTTP_HEADER, string.IsNullOrEmpty(Agent) ? "" : Agent); - if (!_httpRequest.Headers.Contains(Utilities.RequestHeaders.X_MS_CLIENT_REQUEST_ID)) _httpRequest.Headers.TryAddWithoutValidation(Utilities.RequestHeaders.X_MS_CLIENT_REQUEST_ID, RequestId.ToString()); diff --git a/src/GeneralTools/DataverseClient/Client/DataverseTelemetryBehaviors.cs b/src/GeneralTools/DataverseClient/Client/DataverseTelemetryBehaviors.cs index f5e55ad..c430dfd 100644 --- a/src/GeneralTools/DataverseClient/Client/DataverseTelemetryBehaviors.cs +++ b/src/GeneralTools/DataverseClient/Client/DataverseTelemetryBehaviors.cs @@ -279,6 +279,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client } AddExternalHeaders(httpRequestMessage); + Utilities.CleanUpHeaderKeys(httpRequestMessage.Headers); if (httpRequestMessageObject == null) request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage); } diff --git a/src/GeneralTools/DataverseClient/Client/ServiceClient.cs b/src/GeneralTools/DataverseClient/Client/ServiceClient.cs index f4fccfb..1cbb5a4 100644 --- a/src/GeneralTools/DataverseClient/Client/ServiceClient.cs +++ b/src/GeneralTools/DataverseClient/Client/ServiceClient.cs @@ -391,6 +391,7 @@ namespace Microsoft.PowerPlatform.Dataverse.Client else { WhoAmIResponse resp = Task.Run(async () => await _connectionSvc.GetWhoAmIDetails(this).ConfigureAwait(false)).Result; + //WhoAmIResponse resp = _connectionSvc.GetWhoAmIDetails(this).Result; _connectionSvc.CurrentUser = resp; return resp; } diff --git a/src/GeneralTools/DataverseClient/Client/Utils/Utils.cs b/src/GeneralTools/DataverseClient/Client/Utils/Utils.cs index 06ac16a..9291b92 100644 --- a/src/GeneralTools/DataverseClient/Client/Utils/Utils.cs +++ b/src/GeneralTools/DataverseClient/Client/Utils/Utils.cs @@ -562,7 +562,10 @@ namespace Microsoft.PowerPlatform.Dataverse.Client { mselectValueString += $"{opt.Value},"; } - value = mselectValueString.Remove(mselectValueString.Length - 1); + if (!string.IsNullOrEmpty(mselectValueString) && mselectValueString.Last().Equals(',')) + value = mselectValueString.Remove(mselectValueString.Length - 1); + else + value = null; } else if (value is OptionSetValue optionSetValue) { @@ -1212,5 +1215,24 @@ namespace Microsoft.PowerPlatform.Dataverse.Client } #endregion + #region HTTPHeaderCleanupSupport + /// + /// Fix for issue in .net core which is not using proper separators for User-Agent and Server Headers + /// + /// Collection to clean up values for + /// + internal static void CleanUpHeaderKeys(WebHeaderCollection headerCollection) + { + if (headerCollection.AllKeys.Contains(RequestHeaders.USER_AGENT_HTTP_HEADER)) + { + string UserAgentValue = headerCollection[RequestHeaders.USER_AGENT_HTTP_HEADER]; + if (UserAgentValue.Contains(",")) + { + headerCollection[RequestHeaders.USER_AGENT_HTTP_HEADER] = UserAgentValue.Replace(",", " "); + } + } + } + #endregion + } } diff --git a/src/nuspecs/Microsoft.PowerPlatform.Dataverse.Client.ReleaseNotes.txt b/src/nuspecs/Microsoft.PowerPlatform.Dataverse.Client.ReleaseNotes.txt index a2750dd..f25ae0b 100644 --- a/src/nuspecs/Microsoft.PowerPlatform.Dataverse.Client.ReleaseNotes.txt +++ b/src/nuspecs/Microsoft.PowerPlatform.Dataverse.Client.ReleaseNotes.txt @@ -7,6 +7,11 @@ Notice: Note: Only AD on FullFramework, OAuth, Certificate, ClientSecret Authentication types are supported at this time. ++CURRENTRELEASEID++ +Fixed an issue with Custom User Agent headers incorrectly causing a format error when .net core is used. Proper User-Agent format must be used to send requests including the user agent. +Fixed an issue with an Empty OptionSetValue collection causing an ArgumentOutOfRangeException. Empty OptionSetValue collections will now be mapped to Null. Fixes https://github.com/microsoft/PowerPlatform-DataverseServiceClient/issues/292 Thanks for your report! +Fixed an issue where EntityReference based operations do not propagate RowVersion when using WebAPI protocol. Fixes https://github.com/microsoft/PowerPlatform-DataverseServiceClient/issues/296 + +1.0.4: Fixed an issue with External Authentication and Connection and configuration constructor where external auth was not being respected correctly. Fixed a bug on clone where Ilogger was not being propagated to the cloned connection correctly Removed a call to WhoAmI during login flow as process of talking to Dataverse to verify the connection is delt with during get environment information call.