L’interfaccia IOrganizationService
IOrganizationService è il contratto principale per interagire con Dataverse dal codice .NET, sia all’interno di un plug-in sia da un’applicazione esterna. Espone un insieme fisso di metodi che coprono l’intero ciclo CRUD e le operazioni sui metadati e sulle relazioni.
Le operazioni sui record
- Create — inserisce una nuova Entity e restituisce il
Guiddel record creato. - Retrieve — legge un singolo record dato
entityName,ide unColumnSetche definisce le colonne da caricare (evitaColumnSet(true)per motivi di performance). - Update — aggiorna solo le colonne valorizzate nell’oggetto
Entity(update parziale): non serve rileggere l’intero record. - Delete — elimina il record indicato.
- Associate / Disassociate — creano o rimuovono relazioni tra record tramite un oggetto
Relationship, tipicamente per le relazioni many-to-many. - Execute — il metodo più potente: esegue qualsiasi
OrganizationRequest(es.WhoAmIRequest,ExecuteMultipleRequest, una Custom API o azione). Quando non esiste un metodo dedicato, si passa daExecute.
Le opzioni di query
Per RetrieveMultiple hai tre approcci:
- QueryExpression — modello a oggetti fortemente tipizzato: ideale quando costruisci la query dinamicamente nel codice (filtri,
LinkEntity, ordinamenti). Non supporta le aggregazioni. - FetchXML (
FetchExpression) — query in formato XML: unica opzione per le aggregazioni (count, sum, group by) e per riusare query salvate o costruite nell’editor. - LINQ provider — tramite
OrganizationServiceContext/CreateQuery<T>: più leggibile, ma viene tradotto internamente in QueryExpression, quindi non tutte le espressioni LINQ sono supportate.
Contesto di esecuzione nei plug-in
Dentro un plug-in non istanzi un client: ottieni il servizio dalla IOrganizationServiceFactory recuperata dal IServiceProvider.
var factory = (IOrganizationServiceFactory)serviceProvider
.GetService(typeof(IOrganizationServiceFactory));
var service = factory.CreateOrganizationService(context.UserId);
Il Guid passato a CreateOrganizationService determina il contesto di sicurezza:
- context.UserId — il servizio opera come l’utente sotto cui il plug-in è registrato per l’esecuzione: le operazioni rispettano i suoi security role.
- context.InitiatingUserId — l’utente che ha effettivamente scatenato l’operazione.
- null — il servizio opera come utente SYSTEM, con privilegi pieni che bypassano il controllo di sicurezza. Usalo con cautela, solo quando serve un’operazione privilegiata.
L’impersonation consiste nel passare l’ID di un altro utente: le operazioni vengono valutate con i privilegi di quell’utente. Perché sia consentita, il chiamante deve possedere il privilegio prvActOnBehalfOfAnotherUser (ruolo Delegate). Da client esterno l’equivalente è impostare la proprietà CallerId su ServiceClient.
Operazioni bulk e client esterni
Da un’applicazione esterna il client corrente è ServiceClient (namespace Microsoft.PowerPlatform.Dataverse.Client), autenticato via Microsoft Entra ID con una app registration (client secret o certificato); CrmServiceClient e OrganizationServiceProxy sono ormai legacy.
Per grandi volumi:
- ExecuteMultipleRequest — raggruppa fino a 1000 richieste in una sola chiamata, riducendo i round-trip di rete. Le proprietà
ContinueOnErroreReturnResponsesne controllano il comportamento; non è transazionale. - ExecuteTransactionRequest — esegue più richieste in un’unica transazione atomica (tutto o niente).
La differenza chiave: ExecuteMultiple ha senso dal client esterno, dove il costo dominante è la latenza di rete. Dentro un plug-in giri già in-process sul server, quindi il batching non porta benefici e va evitato; contano invece il limite dei 2 minuti di esecuzione e la profondità (Depth) delle chiamate ricorsive.
Trappole tipiche d’esame
- Serve conteggiare o aggregare i record → usa FetchXML: QueryExpression e il LINQ provider non supportano le aggregazioni.
- Plug-in che deve creare record che l’utente non potrebbe creare →
CreateOrganizationService(null)per girare come SYSTEM; se invece devi rispettare i permessi dell’utente, passacontext.UserId. - Impersonation che fallisce con errore di privilegi → l’utente impersonato non ha i diritti sull’operazione (l’impersonation non aumenta i privilegi) oppure il chiamante non possiede prvActOnBehalfOfAnotherUser.
- Migliaia di record da inserire da un job esterno → ExecuteMultipleRequest per ridurre i round-trip, non un ciclo di singole
Create; ricorri a ExecuteTransactionRequest solo se serve atomicità. - Nuovo client per connettersi a Dataverse → ServiceClient con autenticazione Microsoft Entra ID, non il deprecato
CrmServiceClient.