Importazione dati da Microsoft Dynamics 365 tramite protocollo oData e autenticazione oAuth2

Tramite uno script è possibile importare dati da Microsoft Dynamics 365 utilizzando il protocollo oData e autenticandosi tramite il protocollo oAuth2.

Queste tecnologie rappresentano lo stato dell’arte per quanto riguarda rispettivamente l’accesso ai dati RESTful e l’autenticazione a servizi in Cloud, e l’esempio sotto riportato è quindi particolarmente importante costituendo un punto di partenza dal quale derivare altre soluzioni facendo uso di tali tecnologie.

Autenticazione oAuth2

Il protocollo oAuth2 viene utilizzato sia da Microsoft che da Google per l’accesso ai rispettivi servizi Cloud. Nel caso di Microsoft, e quindi di Dynamics 365, la gestione degli utenti avviene tramite Azure Active Directory (AAD), che fra le altre cose è in grado di gestire l’appartenenza degli utenti stessi ad un dominio specifico (quello dell’azienda, es. “qualiware.it”). Pertanto ogni azienda potrà usare il proprio dominio e registrare gli utenti sulle varie applicazioni. 

Una applicazione esterna, come ad esempio QualiWare, dovrà effettuare apposite chiamate per autenticarsi e  utilizzare i servizi messi a disposizione dall’applicazione Microsoft, e per fare questo non è sufficiente disporre di un utente e una password, ma sarà necessario registrare l’applicazione esterna stessa all’interno di AAD, per ottenere il cosiddetto Application ID (spesso chiamato anche Client ID) che andrà specificato nelle suddette chiamate. 

L’autenticazione con utente e password è possibile se l’applicazione esterna è registrata come “Native”. Se viene registrata come “Web App/Api”, è necessario utilizzare il cosiddetto “Client Secret”, che viene reperito nella scheda di registrazione dell’app all’interno di Active Directory.

Le immagini seguenti riportano un esempio di maschera di registrazione  “Native” e “Web App/Api” all’interno di AAD.

 

Accesso ai dati tramite protocollo oData

Il protocollo oData è un’implementazione del paradigma REST, e consente di effettuare operazioni di interrogazione e aggiornamento utilizzando il protocollo Web.

Componendo opportunamente una URL, è possibile specificare la tabella da interrogare, i filtri e l’operazione da effettuare. Ad, esempio, per reperire i primi 100 records della tabella Customers, si può utilizzare una URL di questo tipo:

https://<dominio applicazione>.sandbox.ax.dynamics.com/data/CustomersV3?$top=100

Il risultato restituito è un file JSon contenente i dati, che può essere facilmente elaborato utilizzando la libreria Newtonsoft.Json già inclusa nella piattaforma QualiWare, come vedremo nell’esempio successivo.

Per ulteriori informazioni:

  • Sull’utilizzo di oData in Dynamics 365 vedere qui.
  • Sulle differenze fra oData e REST vedere qui.

Esempio di codice

Il seguente codice effettua l’autenticazione a Dynamics 365 utilizzando nome utente e password, e reperisce i primi 1000 clienti visualizzandoli un un oggetto campo testo multiriga.

Dim credential As New Microsoft.IdentityModel.Clients.ActiveDirectory.UserPasswordCredential("<user>", "<password>")
Dim authContext As Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext = New Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext("https://login.windows.net/<dominio azienda>.com", False)
' Il ClientID (secondo parametro) è l'Application ID registrato su Dynamics
' NOTA: per potere usare utente e password, l'AppID deve essere registrata come "Native". 
' Se invece è registrata come Web App/Api, è necessario ricevere “Client Secret” e “ClientID”, e usare queste creare le credenziali
Dim res As Threading.Tasks.Task(Of Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult)
res = Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContextIntegratedAuthExtensions.AcquireTokenAsync(authContext, "https://<dominio applicazione>.sandbox.ax.dynamics.com", "8da6079a-390a-4eb5-9b08-eeda3066cb7b", credential)
res.Wait
Dim token As String = res.Result.AccessToken

Dim url As String = "https://<dominio applicazione>.sandbox.ax.dynamics.com/data/CustomersV3?$top=1000" ' Recupera i primi 1000 clienti
Dim request As System.Net.HttpWebRequest  
Dim response As System.Net.HttpWebResponse = Nothing  
Dim reader As System.IO.StreamReader  

request = DirectCast(System.Net.WebRequest.Create(url), System.Net.HttpWebRequest)
request.Headers.Add("Authorization", "Bearer " + token) ' Usa il token recuperato sopra per l'autenticazione
response = DirectCast(request.GetResponse(), System.Net.HttpWebResponse)
reader = New System.IO.StreamReader(response.GetResponseStream())

Dim json As String
json = reader.ReadToEnd()		

Dim obj As Newtonsoft.Json.linq.JObject=Newtonsoft.Json.linq.JObject.Parse(json)

Dim i As integer
form.findcontrol("Editor1").Text=""
For i=0 To CType(obj("value"), Newtonsoft.Json.Linq.JArray).Count-1
  form.findcontrol("Editor1").text+="Codice: "+ctype(obj("value")(i)("CustomerAccount"),Newtonsoft.Json.Linq.JValue).Value+vbcr
  form.findcontrol("Editor1").text+="Ragione sociale: "+ctype(obj("value")(i)("OrganizationName"),Newtonsoft.Json.Linq.JValue).Value+vbcr
  form.findcontrol("Editor1").text+="E-mail:"+Ctype(obj("value")(i)("PrimaryContactEmail"),Newtonsoft.Json.Linq.JValue).Value+vbcr
  form.findcontrol("Editor1").text+="Indirizzo: "+Ctype(obj("value")(i)("FullPrimaryAddress"),Newtonsoft.Json.Linq.JValue).Value+vbcr
  form.findcontrol("Editor1").text+="Città: "+obj("value")(i)("DeliveryAddressCity").ToString+vbcr
  form.findcontrol("Editor1").text+="Via: "+ctype(obj("value")(i)("DeliveryAddressStreet"),Newtonsoft.Json.Linq.JValue).Value+vbcr
  form.findcontrol("Editor1").text+="Provincia:"+ctype(obj("value")(i)("AddressCounty"),Newtonsoft.Json.Linq.JValue).Value+vbcr+vbcr
Next

Come si può notare, le parti di autenticazione e interrogazione sono costituite da pochissime righe, e, all’atto pratico, risultano molto efficienti. La parte più complessa è l’elaborazione del risultato, che risulta estremamente semplificato dalla libreria Newtonsoft.Json la quale consente di accedere all’array dei records (contenuto in obj(“value”)) e di estrarne i vari campi, che sono rappresentate da proprietà degli oggetti contenuti nei vari elementi dell’array.