L’oggetto Xrm.WebApi è l’API client-side ufficiale per operare su Dataverse dalle form model-driven, dai web resource e dai controlli PCF. Rispetto a una chiamata fetch diretta all’endpoint Web API, gestisce automaticamente autenticazione, URL dell’organizzazione, versione dell’API e serializzazione: è la scelta di default in ogni contesto client.

I metodi principali

Xrm.WebApi (tramite Xrm.WebApi.online) espone cinque operazioni fondamentali:

  • createRecord(entityLogicalName, data) — crea un record; la Promise restituisce l’id (GUID) del nuovo record.
  • retrieveRecord(entityLogicalName, id, options) — recupera un singolo record per GUID (o chiave alternativa), passando le opzioni OData come stringa.
  • retrieveMultipleRecords(entityLogicalName, options, maxPageSize) — recupera un set di record via query OData o FetchXML.
  • updateRecord(entityLogicalName, id, data) — aggiorna; invia solo i campi presenti in data (PATCH, non sovrascrive il record intero).
  • execute(request) / executeMultiple — invoca Action, Function o messaggi custom/bound (es. WhoAmI, CalculateRollupField).

Per i lookup valgono due convenzioni chiave: in lettura il valore arriva come _nomelookup_value, in scrittura si imposta con la sintassi @odata.bind (es. "parentcustomerid@odata.bind": "/accounts(GUID)").

Query OData vs FetchXML

Le opzioni OData si concatenano in un’unica stringa che inizia con ?:

  • $select — colonne da restituire. Ometterlo significa over-fetching: Dataverse ritorna tutte le colonne, penalizzando performance e banda.
  • $filter — condizioni (eq, ne, contains, operatori logici and/or).
  • $expand — carica le navigation property correlate in un’unica chiamata (evita round-trip aggiuntivi). Va combinato con un $select interno per non over-fetchare le entità espanse.
  • $orderby e $top — ordinamento e limite di righe.
Xrm.WebApi.retrieveMultipleRecords("account",
  "?$select=name,revenue&$filter=revenue gt 100000&$orderby=name asc")

FetchXML si passa a retrieveMultipleRecords con ?fetchXml=... (URL-encoded) ed è preferibile quando servono aggregazioni, join complessi tra più entità o link-entity che OData esprime a fatica. Per query relazionali semplici, OData con $expand è più leggero.

Paging

retrieveMultipleRecords restituisce solo la prima pagina. Il parametro maxPageSize (terzo argomento) fissa la dimensione pagina (default 5000, cioè il massimo per chiamata); il risultato include result.nextLink, da ripassare come options per ottenere la pagina successiva finché è valorizzato. Attenzione: usare $top disattiva il cookie di paging lato server — $top serve per un tetto assoluto di righe, non per paginare.

Online, offline, PCF

  • Xrm.WebApi.online — chiamate verso il server, comportamento standard.
  • Xrm.WebApi.offline — nelle app mobile in offline mode opera sui dati sincronizzati localmente; supporta un sottoinsieme di operazioni (create/retrieve/retrieveMultiple/update/delete) e non execute. Va usato solo quando Xrm.WebApi.offline.isAvailableOffline(entity) conferma il supporto della tabella.
  • PCF — si usa context.webAPI, non Xrm.WebApi. Espone createRecord, deleteRecord, retrieveRecord, retrieveMultipleRecords, updateRecord, ma non execute/executeMultiple, ed è disponibile solo nei contesti che lo supportano (tipicamente le model-driven app; storicamente non nelle canvas app).

Xrm.WebApi vs chiamata REST diretta

Una fetch diretta a .../api/data/v9.2/... è tecnicamente possibile ma va evitata dal contesto form: dovresti gestire manualmente token, header (OData-MaxVersion, OData-Version, Prefer), URL base e versione. La REST diretta ha senso solo in scenari fuori dal contesto client (es. codice server-side con token proprio) — ma lato plug-in/server si usa IOrganizationService, non Xrm.WebApi, che semplicemente non esiste in quel contesto.

Trappole tipiche d’esame

  • Query senza $select → hai over-fetching. La risposta corretta impone $select con le sole colonne necessarie, anche dentro $expand.
  • Serve la seconda pagina di molti record → non aumentare $top, ma iterare su result.nextLink (o impostare maxPageSize e seguire il nextLink).
  • Codice server-side / plug-in che deve leggere dati → non Xrm.WebApi ma IOrganizationService; Xrm.WebApi vale solo client-side.
  • PCF che deve invocare una Action customcontext.webAPI non ha execute: serve un approccio diverso (o chiamata dove il contesto lo consente), non aspettarti executeMultiple.
  • App mobile che deve funzionare offline → usare Xrm.WebApi.offline previa verifica isAvailableOffline, ricordando che non tutte le operazioni (es. execute) sono supportate.
  • Impostare un lookup in create/update → usare campo@odata.bind con il path /entitàplurale(GUID), non il semplice GUID nel campo _value.