Use PowerShell y Visual Studio Code con la API web de Dataverse
Este artículo amplía el artículo Inicio rápido de API web con PowerShell para describir capacidades avanzadas usando PowerShell y Visual Studio Code con la API web de Dataverse para:
- Crear funciones reutilizables
- Administrar excepciones
- Administrar límites de protección de servicio de Dataverse
- Corregir errores usando Fiddler
- Descargar el documento $metadata CSDL de la API web de Dataverse
Nota
Las instrucciones de este artículo deberían funcionar para Windows, Linux y macOS, pero estos pasos solo se han probado en Windows. Si se necesitan cambios, háganoslo saber utilizando la sección Comentario al final de este artículo.
Requisitos previos
El contenido de este artículo tiene los mismos requisitos previos que el artículo Inicio rápido de API web con Powershell.
Instale o verifique que lo siguiente esté instalado
Instale Visual Studio Code. Consulte Descargar Visual Studio Code
Instalar la extensión de PowerShell para Visual Studio Code. Consulte PowerShell para Visual Studio Code
Instale PowerShell 7.4 o superior. Consulte Instalar PowerShell en Windows, Linux y macOS
Instale el módulo Az PowerShell versión 11.1.0 o superior. Consulte Instalar Azure PowerShell
Para actualizar una instalación existente a la última versión, use
Update-Module -Name Az -Force
Verificar instalación
Abra Visual Studio Code.
En el menú Terminal, seleccione Nueva terminal.
En el panel de navegación de Visual Studio Code, seleccione el icono para la extensión de PowerShell.
Copie y pegue el script siguiente en la ventana de la terminal de Visual Studio Code:
Write-Host 'PowerShell Version:'$PSVersionTable.PSVersion.ToString() Write-Host 'PowerShell Az version:'(Get-InstalledModule Az).Version
Presione Entrar. El resultado debería similar al siguiente:
PowerShell Version: 7.4.0 PowerShell Az version: 11.1.0
Si no ve resultados como este, instale o actualice los requisitos previos.
También necesitará
- Una cuenta de usuario válida para un entorno de Dataverse
- La dirección URL al entorno de Dataverse al que quiere conectarse. Consulte Ver recursos para desarrolladores para saber cómo encontrarlo. Se parece a esto:
https://yourorg.crm.dynamics.com/
, dondeyourorg.crm
es diferente. - Comprensión básica de lenguaje de scripting PowerShell
Crear funciones reutilizables
Inicio rápido de API web con PowerShell presentó cómo autenticar y llamar a la función WhoAmI con Visual Studio Code. Este enfoque podría ser todo lo que necesita para una prueba ad hoc de una o más operaciones. Sin embargo, a medida que sus scripts se vuelven más complejos, es posible que se encuentre escribiendo el mismo código una y otra vez.
En esta sección, comenzamos a crear un conjunto de funciones reutilizables en archivos separados a los que podemos acceder usando dot sourcing. Utilice el origen de puntos para cargar un archivo que contenga scripts de PowerShell que puedan contener funciones y variables que pasen a formar parte del alcance del script local.
Sugerencia
Puede encontrar definiciones completamente documentadas de estas funciones y más en nuestro GitHub PowerApps- Repositorio de muestras en PowerApps-Samples/dataverse/webapi/PS/
Crear una función Connect
Pongamos el código para autenticarnos en Dataverse en una función llamada Connect
dentro de un archivo llamado Core.ps1
para que podamos reutilizarlo en una sola línea de código.
Cree una carpeta. En este ejemplo, creamos una carpeta en
C:\scripts
.Cree un archivo de texto en la carpeta de scripts denominada
Core.ps1
.Copie y pegue la siguiente función
Connect
en el archivoCore.ps1
.function Connect { param ( [Parameter(Mandatory)] [String] $uri ) ## Login interactively if not already logged in if ($null -eq (Get-AzTenant -ErrorAction SilentlyContinue)) { Connect-AzAccount | Out-Null } # Get an access token $token = (Get-AzAccessToken -ResourceUrl $uri).Token # Define common set of headers $global:baseHeaders = @{ 'Authorization' = 'Bearer ' + $token 'Accept' = 'application/json' 'OData-MaxVersion' = '4.0' 'OData-Version' = '4.0' } # Set baseURI $global:baseURI = $uri + 'api/data/v9.2/' }
Nota
El script agrega las variables
baseURI
ybaseHeaders
al contexto global usando el modificador de ámbito$global
para que estén disponibles para otros scripts. en la misma sesión.Cree otro archivo de texto usando Visual Studio Code llamado
test.ps1
en su carpetascripts
.Copie y pegue el siguiente script en el archivo
test.ps1
:. $PSScriptRoot\Core.ps1 Connect 'https://yourorg.crm.dynamics.com/' # change this # Invoke WhoAmI Function Invoke-RestMethod -Uri ($baseURI + 'WhoAmI') -Method Get -Headers $baseHeaders | ConvertTo-Json
. $PSScriptRoot\Core.ps1
en la parte superior del archivo se muestra el uso de fuentes de puntos para indicar al script que cargue el contenido de ese archivo.Recuerde cambiar el valor
https://yourorg.crm.dynamics.com/
para que coincida con la URL de su entorno.Pulse F5 para ejecutar el script.
El resultado deberá ser ahora similar a esto:
PS C:\scripts> . 'C:\scripts\test.ps1' { "@odata.context": "https://yourorg.crm.dynamics.com/api/data/v9.2/$metadata#Microsoft.Dynamics.CRM.WhoAmIResponse", "BusinessUnitId": "3a277578-5996-ee11-be36-002248227994", "UserId": "2c2e7578-5996-ee11-be36-002248227994", "OrganizationId": "97bf0e8b-aa99-ee11-be32-000d3a106c3a" }
Crear una función WhoAmI
Pongamos el código para invocar la función WhoAmI en una función llamada Get-WhoAmI
dentro de un archivo llamado CommonFunctions.ps1
para que podamos escribir solo 11 caracteres en lugar de 100 cada vez que desee utilizar la función WhoAmI
Cree un archivo de texto nuevo llamado
CommonFunctions.ps1
en su carpetascripts
.Copie y pegue la siguiente definición de función en
CommonFunctions.ps1
.function Get-WhoAmI{ $WhoAmIRequest = @{ Uri = $baseURI + 'WhoAmI' Method = 'Get' Headers = $baseHeaders } Invoke-RestMethod @WhoAmIRequest }
Nota
Esta definición de función utiliza una técnica llamada splatting. Splatting hace que sus comandos sean más cortos y más fáciles de leer porque pasa una colección de valores de parámetros a un comando como una unidad.
Guarde el archivo
CommonFunctions.ps1
.Edite el archivo
test.ps1
, cambie el contenido para que se parezca al siguiente script:. $PSScriptRoot\Core.ps1 . $PSScriptRoot\CommonFunctions.ps1 Connect 'https://yourorg.crm.dynamics.com/' # change this # Invoke WhoAmI Function Get-WhoAmI | ConvertTo-Json
Recuerde cambiar el valor
https://yourorg.crm.dynamics.com/
para que coincida con la URL de su entorno.Pulse F5 para ejecutar el script.
La salida debería verse exactamente como antes.
Crear funciones de operaciones de tabla
Coloquemos funciones para realizar operaciones de tabla comunes en un archivo llamado TableOperations.ps1
para que podamos reutilizarlas.
Cree un archivo de texto nuevo llamado
TableOperations.ps1
en su carpetascripts
.Copie y pegue las siguientes definiciones de función en
TableOperations.ps1
.function Get-Records { param ( [Parameter(Mandatory)] [String] $setName, [Parameter(Mandatory)] [String] $query ) $uri = $baseURI + $setName + $query # Header for GET operations that have annotations $getHeaders = $baseHeaders.Clone() $getHeaders.Add('If-None-Match', $null) $getHeaders.Add('Prefer', 'odata.include-annotations="*"') $RetrieveMultipleRequest = @{ Uri = $uri Method = 'Get' Headers = $getHeaders } Invoke-RestMethod @RetrieveMultipleRequest } function New-Record { param ( [Parameter(Mandatory)] [String] $setName, [Parameter(Mandatory)] [hashtable] $body ) $postHeaders = $baseHeaders.Clone() $postHeaders.Add('Content-Type', 'application/json') $CreateRequest = @{ Uri = $baseURI + $setName Method = 'Post' Headers = $postHeaders Body = ConvertTo-Json $body } Invoke-RestMethod @CreateRequest -ResponseHeadersVariable rh | Out-Null $url = $rh['OData-EntityId'] $selectedString = Select-String -InputObject $url -Pattern '(?<=\().*?(?=\))' return [System.Guid]::New($selectedString.Matches.Value.ToString()) } function Get-Record { param ( [Parameter(Mandatory)] [String] $setName, [Parameter(Mandatory)] [Guid] $id, [String] $query ) $uri = $baseURI + $setName $uri = $uri + '(' + $id.Guid + ')' + $query $getHeaders = $baseHeaders.Clone() $getHeaders.Add('If-None-Match', $null) $getHeaders.Add('Prefer', 'odata.include-annotations="*"') $RetrieveRequest = @{ Uri = $uri Method = 'Get' Headers = $getHeaders } Invoke-RestMethod @RetrieveRequest } function Update-Record { param ( [Parameter(Mandatory)] [String] $setName, [Parameter(Mandatory)] [Guid] $id, [Parameter(Mandatory)] [hashtable] $body ) $uri = $baseURI + $setName $uri = $uri + '(' + $id.Guid + ')' # Header for Update operations $updateHeaders = $baseHeaders.Clone() $updateHeaders.Add('Content-Type', 'application/json') $updateHeaders.Add('If-Match', '*') # Prevent Create $UpdateRequest = @{ Uri = $uri Method = 'Patch' Headers = $updateHeaders Body = ConvertTo-Json $body } Invoke-RestMethod @UpdateRequest } function Remove-Record { param ( [Parameter(Mandatory)] [String] $setName, [Parameter(Mandatory)] [Guid] $id ) $uri = $baseURI + $setName $uri = $uri + '(' + $id.Guid + ')' $DeleteRequest = @{ Uri = $uri Method = 'Delete' Headers = $baseHeaders } Invoke-RestMethod @DeleteRequest }
Para obtener información acerca de cómo crear estas solicitudes, vea los artículos siguientes:
Guarde el archivo
TableOperations.ps1
.Copie el siguiente código y péguelo en el cuadro archivo
test.ps1
.. $PSScriptRoot\Core.ps1 . $PSScriptRoot\CommonFunctions.ps1 . $PSScriptRoot\TableOperations.ps1 Connect 'https://yourorg.crm.dynamics.com/' # change this # Retrieve Records Write-Host 'Retrieve first three account records:' (Get-Records ` -setName accounts ` -query '?$select=name&$top=3').value | Format-Table -Property name, accountid # Create a record Write-Host 'Create an account record:' $newAccountID = New-Record ` -setName accounts ` -body @{ name = 'Example Account'; accountcategorycode = 1 # Preferred } Write-Host "Account with ID $newAccountID created" # Retrieve a record Write-Host 'Retrieve the created record:' Get-Record ` -setName accounts ` -id $newAccountID.Guid '?$select=name,accountcategorycode' | Format-List -Property name, accountid, accountcategorycode, accountcategorycode@OData.Community.Display.V1.FormattedValue # Update a record Write-Host 'Update the record:' $updateAccountData = @{ name = 'Updated Example account'; accountcategorycode = 2; #Standard } Update-Record ` -setName accounts ` -id $newAccountID.Guid ` -body $updateAccountData Write-Host 'Retrieve the updated the record:' Get-Record ` -setName accounts ` -id $newAccountID.Guid ` -query '?$select=name,accountcategorycode' | Format-List -Property name, accountid, accountcategorycode, accountcategorycode@OData.Community.Display.V1.FormattedValue # Delete a record Write-Host 'Delete the record:' Remove-Record ` -setName accounts ` -id $newAccountID.Guid Write-Host "The account with ID $newAccountID was deleted"
Recuerde cambiar el valor
https://yourorg.crm.dynamics.com/
para que coincida con la URL de su entorno.Pulse F5 para ejecutar el script.
El resultado deberá ser ahora similar a esto:
PS C:\scripts> . 'C:\scripts\test.ps1' Retrieve first three account records: name accountid ---- --------- Fourth Coffee (sample) d2382248-cd99-ee11-be37-000d3a9b7981 Litware, Inc. (sample) d4382248-cd99-ee11-be37-000d3a9b7981 Adventure Works (sample) d6382248-cd99-ee11-be37-000d3a9b7981 Create an account record: Account with ID a2c3ebc2-39a8-ee11-be37-000d3a8e8e07 created Retrieve the created record: name : Example Account accountid : a2c3ebc2-39a8-ee11-be37-000d3a8e8e07 accountcategorycode : 1 accountcategorycode@OData.Community.Display.V1.FormattedValue : Preferred Customer Update the record: Retrieve the updated the record: name : Updated Example account accountid : a2c3ebc2-39a8-ee11-be37-000d3a8e8e07 accountcategorycode : 2 accountcategorycode@OData.Community.Display.V1.FormattedValue : Standard Delete the record: The account with ID a2c3ebc2-39a8-ee11-be37-000d3a8e8e07 was deleted
Administrar excepciones
Hasta ahora en este artículo ha estado copiando y pegando el código que se le proporcionó. Pero cuando empiece a escribir sus propias funciones y a usarlas, encontrará errores. Cuando ocurren estos errores, pueden ser de Dataverse o de su script.
Agreguemos una función auxiliar que pueda ayudar a detectar el origen de los errores y extraer detalles relevantes de los errores devueltos por Dataverse.
Edite el archivo
Core.ps1
para agregar la siguiente funciónInvoke-DataverseCommands
:function Invoke-DataverseCommands { param ( [Parameter(Mandatory)] $commands ) try { Invoke-Command $commands } catch [Microsoft.PowerShell.Commands.HttpResponseException] { Write-Host "An error occurred calling Dataverse:" -ForegroundColor Red $statuscode = [int]$_.Exception.StatusCode; $statusText = $_.Exception.StatusCode Write-Host "StatusCode: $statuscode ($statusText)" # Replaces escaped characters in the JSON [Regex]::Replace($_.ErrorDetails.Message, "\\[Uu]([0-9A-Fa-f]{4})", {[char]::ToString([Convert]::ToInt32($args[0].Groups[1].Value, 16))} ) } catch { Write-Host "An error occurred in the script:" -ForegroundColor Red $_ } }
La función
Invoke-DataverseCommands
utiliza el cmdlet Invoke-Command para procesar un conjunto de comandos dentro de un bloque try/catch. Cualquier error devuelto por Dataverse son errores HttpResponseException, por lo que el primer bloquecatch
escribe un mensajeAn error occurred calling Dataverse:
en la terminal con los datos de error JSON.Los datos JSON en
$_.ErrorDetails.Message
contienen algunos caracteres Unicode escapados. Por ejemplo:\u0026
en lugar de&
y\u0027
en lugar de'
. Esta función incluye código que reemplaza esos caracteres con caracteres sin escape para que coincidan exactamente con los errores que ve en otros lugares.De lo contrario, los errores se escriben en la ventana del terminal con un mensaje:
An error occurred in the script:
Guarde el archivo
Core.ps1
.Edite el archivo
test.ps1
para utilizar el siguiente script que utiliza un valor de parámetrosetName
no válido.account
debe seraccounts
. Es un error común. $PSScriptRoot\Core.ps1 . $PSScriptRoot\CommonFunctions.ps1 . $PSScriptRoot\TableOperations.ps1 Connect 'https://yourorg.crm.dynamics.com/' # change this Invoke-DataverseCommands { # Retrieve Records Write-Host 'Retrieve first three account records:' (Get-Records ` -setName account ` -query '?$select=name&$top=3').value | Format-Table -Property name, accountid }
Recuerde cambiar el valor
https://yourorg.crm.dynamics.com/
para que coincida con la URL de su entorno.Pulse F5 para ejecutar el script.
El resultado deberá ser ahora similar a esto:
PS C:\scripts> . 'C:\scripts\test.ps1' Retrieve first three account records: An error occurred calling Dataverse: StatusCode: 404 (NotFound) { "error": { "code": "0x80060888", "message": "Resource not found for the segment 'account'." } }
Edite el archivo
test.ps1
para generar un error de secuencia de comandos dentro del bloqueInvoke-DataverseCommands
:Invoke-DataverseCommands { throw 'A script error' }
Pulse F5 para ejecutar el script.
El resultado debería ser casi el mismo que si no estuviera incluido en el bloque
Invoke-DataverseCommands
:PS C:\scripts> . 'C:\scripts\test.ps1' An error occurred in the script: Exception: C:\scripts\test.ps1:8:4 Line | 8 | throw 'A script error' | ~~~~~~~~~~~~~~~~~~~~~~ | A script error
Administrar límites de protección de servicio de Dataverse
Límites de API de protección de servicios de Dataverse ayudar a garantizar que Dataverse proporcione disponibilidad y rendimiento constantes. Cuando las aplicaciones cliente exigen de forma extraordinaria los recursos del servidor utilizando la API web, Dataverse devuelve errores 429 Demasiadas solicitudes y la aplicación cliente debe pausar las operaciones durante el tiempo especificado en el Encabezado Reintentar después.
El PowerShell Cmdlet Invoke-RestMethod Parámetro MaximumRetryCount especifica cuántas veces PowerShell reintenta una solicitud cuando se recibe un código de error entre 400 y 599, inclusive o 304. Esto significa que PowerShell reintenta errores de protección de servicio 429 de Dataverse cuando se incluye un valor para este parámetro. El parámetro MaximumRetryCount
se puede utilizar con RetryIntervalSec para especificar el número de segundos de espera. El valor predeterminado es de 5 segundos. Si la respuesta de error incluye un encabezado Retry-After
para un error 429, como hacen los errores de protección del servicio de Dataverse, en su lugar se utiliza ese valor.
Es posible que nunca encuentre un error de límite de protección del servicio mientras aprende a utilizar la API web de Dataverse con PowerShell. Los scripts que escriba pueden usarse para enviar la gran cantidad de solicitudes necesarias para encontrar estos errores, por lo que debe saber que pueden ocurrir y cómo puede administrarlos usando PowerShell.
Si agrega el parámetro MaximumRetryCount
a cada llamada a Dataverse usando Invoke-RestMethod
, PowerShell reintenta una amplia gama de errores. Reintentar cada error hace que los scripts sean lentos, especialmente durante el desarrollo y las pruebas. Deberá esperar de 10 a 15 segundos cada vez que ocurra un error, dependiendo de cuántos reintentos especifique. Un enfoque alternativo es encapsular el Invoke-RestMethod
en su propio método que gestiona los reintentos para errores específicos.
La siguiente función Invoke-ResilientRestMethod
toma un objeto de tabla hash request
como parámetro obligatorio y una bandera booleana returnHeader
para indicar si se debe devolver el encabezado de respuesta o no. Cuando $returnHeader
es verdadero, envía la solicitud usando el comando Invoke-RestMethod
con el parámetro ResponseHeadersVariable para capturar los encabezados devueltos y usa Out-Null para que la salida que representa el cuerpo de respuesta vacío no se devuelva con la función. De lo contrario, la función envía la solicitud usando Invoke-RestMethod
usando el objeto request
y devuelve el cuerpo de la respuesta.
Si el Invoke-RestMethod
falla con un error 429, verifica si el objeto request
tiene una propiedad MaximumRetryCount
. Si no, agrega uno con valor 3. Luego vuelve a intentar Invoke-RestMethod
utilizando el objeto de solicitud y el valor del encabezado de respuesta Retry-After
. Si el indicador returnHeader
es verdadero, devuelve el encabezado de respuesta. Si Invoke-RestMethod
falla con cualquier otro error, vuelve a lanzar la excepción.
function Invoke-ResilientRestMethod {
param (
[Parameter(Mandatory)]
$request,
[bool]
$returnHeader
)
try {
if ($returnHeader) {
Invoke-RestMethod @request -ResponseHeadersVariable rhv | Out-Null
return $rhv
}
Invoke-RestMethod @request
}
catch [Microsoft.PowerShell.Commands.HttpResponseException] {
$statuscode = $_.Exception.Response.StatusCode
# 429 errors only
if ($statuscode -eq 'TooManyRequests') {
if (!$request.ContainsKey('MaximumRetryCount')) {
$request.Add('MaximumRetryCount', 3)
# Don't need - RetryIntervalSec
# When the failure code is 429 and the response includes the Retry-After property in its headers,
# the cmdlet uses that value for the retry interval, even if RetryIntervalSec is specified
}
# Will attempt retry up to 3 times
if ($returnHeader) {
Invoke-RestMethod @request -ResponseHeadersVariable rhv | Out-Null
return $rhv
}
Invoke-RestMethod @request
}
else {
throw $_
}
}
catch {
throw $_
}
}
Puede utilizar una función como esta en sus funciones reutilizables. Cuando las funciones necesitan devolver valores del encabezado de la respuesta, deben establecer el valor returnHeader
en $true
. Por ejemplo, la siguiente función New-Record
modifica la función de ejemplo en Crear funciones de operaciones de tabla para usar Invoke-ResilientRestMethod
en lugar de Invoke-RestMethod
directamente.
function New-Record {
param (
[Parameter(Mandatory)]
[String]
$setName,
[Parameter(Mandatory)]
[hashtable]
$body
)
$postHeaders = $baseHeaders.Clone()
$postHeaders.Add('Content-Type', 'application/json')
$CreateRequest = @{
Uri = $environmentUrl + 'api/data/v9.2/' + $setName
Method = 'Post'
Headers = $postHeaders
Body = ConvertTo-Json $body
}
# Before:
# Invoke-RestMethod @CreateRequest -ResponseHeadersVariable rh | Out-Null
# After:
$rh = Invoke-ResilientRestMethod -request $CreateRequest -returnHeader $true
$url = $rh['OData-EntityId']
$selectedString = Select-String -InputObject $url -Pattern '(?<=\().*?(?=\))'
return [System.Guid]::New($selectedString.Matches.Value.ToString())
}
De lo contrario, Invoke-ResilientRestMethod
puede reemplazar el Invoke-RestMethod
como se muestra en este ejemplo de Get-Record
:
function Get-Record {
param (
[Parameter(Mandatory)]
[String]
$setName,
[Parameter(Mandatory)]
[Guid]
$id,
[String]
$query
)
$uri = $environmentUrl + 'api/data/v9.2/' + $setName
$uri = $uri + '(' + $id.Guid + ')' + $query
$getHeaders = $baseHeaders.Clone()
$getHeaders.Add('If-None-Match', $null)
$getHeaders.Add('Prefer', 'odata.include-annotations="*"')
$RetrieveRequest = @{
Uri = $uri
Method = 'Get'
Headers = $getHeaders
}
# Before:
# Invoke-RestMethod @RetrieveRequest
# After:
Invoke-ResilientRestMethod $RetrieveRequest
}
La única diferencia es que pasa la tabla hash ($RetrieveRequest
) al método en lugar de usar splatting (@RetrieveRequest
). De lo contrario, obtendrá un error de secuencia de comandos: A parameter cannot be found that matches parameter name 'Headers'.
Corregir errores usando Fiddler
Fiddler es un proxy de depuración web que se utiliza para ver el tráfico HTTP en su ordenador. Ver estos datos es útil al depurar scripts. De forma predeterminada, las solicitudes y respuestas HTTP enviadas mediante el cmdlet Invoke-RestMethod no serán visibles con Fiddler.
Para ver el tráfico HTTP usando Fiddler, establezca el parámetro Proxy Invoke-RestMethod
en la URL configurada como proxy de Fiddler en su computadora local. De forma predeterminada, la URL es http://127.0.0.1:8888
. El suyo puede ser diferente.
Por ejemplo, si invoca la función WhoAmI con el parámetro -Proxy
establecido mientras Fiddler está capturando tráfico:
Invoke-RestMethod `
-Uri ($environmentUrl + 'api/data/v9.2/WhoAmI') `
-Method Get `
-Headers $baseHeaders `
-Proxy 'http://127.0.0.1:8888'
En Fiddler podrá ver todos los detalles:
GET https://yourorg.api.crm.dynamics.com/api/data/v9.2/WhoAmI HTTP/1.1
Host: yourorg.api.crm.dynamics.com
OData-MaxVersion: 4.0
Accept: application/json
Authorization: Bearer [REDACTED]
OData-Version: 4.0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.22631; en-US) PowerShell/7.4.0
Accept-Encoding: gzip, deflate, br
HTTP/1.1 200 OK
Cache-Control: no-cache
Allow: OPTIONS,GET,HEAD,POST
Content-Type: application/json; odata.metadata=minimal
Expires: -1
Vary: Accept-Encoding
x-ms-service-request-id: 7341c0c1-3343-430b-98ea-292567ed4776
Set-Cookie: ARRAffinity=f60cbee43b7af0a5f322e7ce57a018546ed978f67f0c11cbb5e15b02ddb091a915134d20c556b0b34b9b6ae43ec3f5dcdad61788de889ffc592af7aca85fc1c508DC0FC94CB062A12107345846; path=/; secure; HttpOnly
Set-Cookie: ReqClientId=4fc95009-0b3d-4a19-b223-0d80745636ac; expires=Sun, 07-Jan-2074 21:10:42 GMT; path=/; secure; HttpOnly
Set-Cookie: orgId=648e8efd-db86-466e-a5bc-a4d5eb9c52d4; expires=Sun, 07-Jan-2074 21:10:42 GMT; path=/; secure; HttpOnly
x-ms-service-request-id: 1ee13aa7-47f3-4a75-95fa-2916775a1f79
Strict-Transport-Security: max-age=31536000; includeSubDomains
REQ_ID: 1ee13aa7-47f3-4a75-95fa-2916775a1f79
CRM.ServiceId: framework
AuthActivityId: 0b562cc3-56f6-44f0-a26e-4039cfc4be6a
x-ms-dop-hint: 48
x-ms-ratelimit-time-remaining-xrm-requests: 1,200.00
x-ms-ratelimit-burst-remaining-xrm-requests: 5999
OData-Version: 4.0
X-Source: 110212218438874147222728177124203420477168182861012399121919014511175711948418152
Public: OPTIONS,GET,HEAD,POST
Set-Cookie: ARRAffinity=f60cbee43b7af0a5f322e7ce57a018546ed978f67f0c11cbb5e15b02ddb091a915134d20c556b0b34b9b6ae43ec3f5dcdad61788de889ffc592af7aca85fc1c508DC0FC94CB062A12107345846; path=/; secure; HttpOnly
X-Source: 2302101791355821068628523819830862152291172232072372448021147103846182145238216119
Date: Sun, 07 Jan 2024 21:10:42 GMT
Content-Length: 277
{"@odata.context":"https://yourorg.api.crm.dynamics.com/api/data/v9.2/$metadata#Microsoft.Dynamics.CRM.WhoAmIResponse","BusinessUnitId":"1647bf36-e90a-4c4d-9b61-969d57ce7a66","UserId":"24e34f5e-7f1a-43fe-88da-7e4b862d51ad","OrganizationId":"648e8efd-db86-466e-a5bc-a4d5eb9c52d4"}
Si Fiddler no se está ejecutando, recibirá un error como este:
Invoke-RestMethod: C:\scripts\test.ps1:8:1
Line |
8 | Invoke-RestMethod `
| ~~~~~~~~~~~~~~~~~~~
| No connection could be made because the target machine actively refused it.
Si elige enrutar todas sus llamadas Invoke-RestMethod
a través de una única función, como la Invoke-ResilientRestMethod
que se describe en Administrar límites de protección del servicio Dataverse, puede establecer algunas variables en el archivo Core.ps1
para configurar esta opción en una sola ubicación.
# <a name="set-to-true-only-while-debugging-with-fiddler"></a>Set to true only while debugging with Fiddler
$debug = $true
# <a name="set-this-value-to-the-fiddler-proxy-url-configured-on-your-computer"></a>Set this value to the Fiddler proxy URL configured on your computer
$proxyUrl = 'http://127.0.0.1:8888'
Luego, dentro de su función centralizada puede configurar el parámetro -Proxy
usando splatting con la tabla hash $request
solo al depurar con Fiddler.
function Invoke-ResilientRestMethod {
param (
[Parameter(Mandatory)]
$request,
[bool]
$returnHeader
)
if ($debug) {
$request.Add('Proxy', $proxyUrl)
}
...
Obtenga más información sobre cómo capturar tráfico web con Fiddler
Descargar el documento $metadata CSDL de la API web de Dataverse
El $metadata CSDL es la fuente de verdad sobre las capacidades de la API web Dataverse. Puede verlo en un navegador, pero puede que le resulte más fácil descargar el archivo y verlo dentro de Visual Studio Code. El siguiente script es una versión modificada del script introducido en Inicio rápido de API web con PowerShell. La diferencia es que utiliza el cmdlet Invoke-WebRequest, que es más apropiado para descargar un documento XML.
$environmentUrl = 'https://yourorg.crm.dynamics.com/' # change this
$writeFileTo = 'C:\temp\yourorg.xml' # change this
## <a name="login-if-not-already-logged-in"></a>Login if not already logged in
if ($null -eq (Get-AzTenant -ErrorAction SilentlyContinue)) {
Connect-AzAccount | Out-Null
}
# <a name="get-an-access-token"></a>Get an access token
$token = (Get-AzAccessToken -ResourceUrl $environmentUrl).Token
# <a name="common-headers"></a>Common headers
$xmlHeaders = @{
'Authorization' = 'Bearer ' + $token
'Accept' = 'application/xml'
'OData-MaxVersion' = '4.0'
'OData-Version' = '4.0'
}
$doc = [xml](Invoke-WebRequest `
-Uri ($environmentUrl + 'api/data/v9.2/$metadata?annotations=true') `
-Method 'Get' `
-Headers $xmlHeaders ).Content
$StringWriter = New-Object System.IO.StringWriter
$XmlWriter = New-Object System.XMl.XmlTextWriter $StringWriter
$xmlWriter.Formatting = 'indented'
$xmlWriter.Indentation = 2
$doc.WriteContentTo($XmlWriter)
$XmlWriter.Flush()
$StringWriter.Flush()
Set-Content -Path $writeFileTo -Value $StringWriter.ToString()
code $writeFileTo
- Copie el script.
- Edite las variables
$environmentUrl
y$writeFileTo
para satisfacer sus necesidades. - Ejecute el script en Visual Studio Code.
El $metadata CSDL de la API web de Dataverse se abrirá en Visual Studio Code.
Probablemente recibirá una notificación que diga:
Por motivos de rendimiento, los símbolos de los documentos se han limitado a 5000 elementos. Si se establece un nuevo límite, cierre y vuelva a abrir este archivo para volver a calcular los símbolos del documento.
La notificación ofrece la opción de cambiar el límite de Visual Studio extensión XML xml.symbols.maxItemsComputed
. Para la mayoría de los documentos Dataverse Web API CSDL $metadata, establecer el límite en 500 000 debería ser suficiente.
Solución de problemas
Esta sección contiene algunas pautas para los problemas que pueda encontrar.
Cuadro de diálogo de error: conecte ENOENT\\.\pipe\<RANDOM_text> con el botón Abrir 'launch.json'
Este error puede ocurrir en ocasiones al depurar usando Visual Studio Code. Para resolverlo:
- Seleccione Ver > Paleta de comandos... en el menú Visual Studio Code, o presione Ctrl+Mayús+P.
- Escriba
restart
y seleccionePowershell: Restart session
. Consulte PowerShell/vscode-powershell GitHub Problema 4332 para obtener más información.
Pasos siguientes
Aprender más acerca de las Capacidades de API web de Dataverse mediante la comprensión de los documentos de servicio.
Revisar y ejecutar código de muestra.
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de