src/_Internals/Invoke-XrmWebApiRequestInternal.ps1
|
<# Send one request to the Dataverse Web API (api/data/v9.2/<Path>) with the authentication of the client (ServiceClient.ExecuteWebRequest). Returns the body of the response as text, or as a JObject with AsJson (dates kept as text, so a definition read is sent back unchanged); $null when the body is empty, or when -WhatIf skips a write. Used where the organization service ignores a setting: the requirement level of an existing column (known issue K17). GET always runs; any other method writes and asks ShouldProcess, as Invoke-XrmRequest does for the SDK requests. StrongConsistency adds "Consistency: Strong": metadata read past the cache, which answers the previous definition for a while after a change. A failure raises an error naming the method, the path, the status and the message of the service. #> function Invoke-XrmWebApiRequestInternal { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] param( [Parameter(Mandatory = $true)] [Microsoft.PowerPlatform.Dataverse.Client.ServiceClient] $XrmClient, [Parameter(Mandatory = $true)] [ValidateSet("GET", "POST", "PATCH", "PUT", "DELETE")] [string] $Method, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Mandatory = $false)] [string] $Body, [Parameter(Mandatory = $false)] [Hashtable] $Headers = @{}, [Parameter(Mandatory = $false)] [switch] $StrongConsistency, [Parameter(Mandatory = $false)] [switch] $AsJson ) if ($Method -ne "GET" -and -not $PSCmdlet.ShouldProcess($Path, "Web API $Method")) { return $null; } $requestHeaders = @{} + $Headers; if ($StrongConsistency) { $requestHeaders["Consistency"] = "Strong"; } $customHeaders = [System.Collections.Generic.Dictionary[string, System.Collections.Generic.List[string]]]::new(); foreach ($name in $requestHeaders.Keys) { $values = [System.Collections.Generic.List[string]]::new(); $values.Add([string]$requestHeaders[$name]); $customHeaders[$name] = $values; } $content = $(if ($PSBoundParameters.ContainsKey('Body')) { $Body } else { $null }); try { $response = Protect-XrmCommand -ScriptBlock { $XrmClient.ExecuteWebRequest([System.Net.Http.HttpMethod]::new($Method), $Path, $content, $customHeaders, "application/json", [System.Threading.CancellationToken]::None) }; } catch { # HttpOperationException: the message of the service is in the body of the response $failure = $_.Exception; while ($null -ne $failure -and -not ($failure.PSObject.Properties["Response"] -and $null -ne $failure.Response -and $failure.Response.PSObject.Properties["StatusCode"])) { $failure = $failure.InnerException; } if ($null -eq $failure) { throw; } $serviceMessage = [string]$failure.Response.Content; try { $serviceMessage = ($serviceMessage | ConvertFrom-Json).error.message; } catch { # Not a Web API error body: keep it as is } throw [System.InvalidOperationException]::new("Web API $Method $Path failed ($([int]$failure.Response.StatusCode) $($failure.Response.StatusCode)): $serviceMessage", $failure); } if ($null -eq $response) { throw "Web API $Method $Path failed: no response ($($XrmClient.LastError))."; } $text = $response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); if (-not $response.IsSuccessStatusCode) { throw "Web API $Method $Path failed ($([int]$response.StatusCode) $($response.StatusCode)): $text"; } if ([string]::IsNullOrEmpty($text)) { return $null; } if (-not $AsJson) { return $text; } $reader = [Newtonsoft.Json.JsonTextReader]::new([System.IO.StringReader]::new($text)); $reader.DateParseHandling = [Newtonsoft.Json.DateParseHandling]::None; # A JObject is enumerable: the comma keeps PowerShell from writing its properties one by one return , [Newtonsoft.Json.Linq.JObject]::Load($reader); } |