Esercitazione: Codifica con Azure Digital Twins SDK
È comune per gli sviluppatori che usano Gemelli digitali di Azure scrivere applicazioni client per interagire con la loro istanza del servizio. Questa esercitazione destinata agli sviluppatori offre un'introduzione alla programmazione per il servizio Gemelli digitali di Azure, usando l'SDK di Gemelli digitali di Azure per .NET (C#). Viene descritta la procedura dettagliata per scrivere un'app client console in C# a partire da zero.
- Configurare il progetto
- Iniziare a scrivere il codice del progetto
- Esempio di codice completo
- Pulire le risorse
- Passaggi successivi
Prerequisiti
Questa esercitazione su Gemelli digitali di Azure usa la riga di comando per il lavoro di installazione e progetto. Pertanto, è possibile usare qualsiasi editor di codice per eseguire gli esercizi.
Per iniziare, è necessario avere:
- Qualsiasi editor di codice
- .NET Core 3.1 nel computer di sviluppo. È possibile scaricare questa versione di .NET Core SDK multipiattaforma dalla pagina di download di .NET Core 3.1.
Preparare un'istanza di Gemelli digitali di Azure
Per usare Gemelli digitali di Azure come descritto in questo articolo, è necessaria un'istanza di Gemelli digitali di Azure e le autorizzazioni necessarie per l'utilizzo. Se in precedenza è stata già configurata un'istanza di Gemelli digitali di Azure, è possibile usare tale istanza e passare alla sezione successiva. In caso contrario, seguire le istruzioni riportate in Configurare un'istanza e l'autenticazione. Le istruzioni contengono informazioni che consentono di verificare che ogni passaggio sia stato completato correttamente.
Dopo aver configurato l'istanza, prendere nota del nome host dell'istanza. È possibile trovare il nome host nel portale di Azure.
Configurare le credenziali di Azure locali
Questo esempio usa DefaultAzureCredential (parte della libreria Azure.Identity
) per l'autenticazione degli utenti con l'istanza di Gemelli digitali di Azure eseguita nel computer locale. Per altre informazioni sui diversi modi con cui un'app client può eseguire l'autenticazione con Gemelli digitali di Azure, vedere Scrivere il codice di autenticazione dell'app.
Con DefaultAzureCredential
, l'esempio cercherà le credenziali nell'ambiente locale, ad esempio un account di accesso di Azure nell'interfaccia della riga di comando di Azure locale o in Visual Studio o Visual Studio Code. Per questo motivo è necessario accedere ad Azure in locale tramite uno di questi meccanismi per configurare le credenziali per l'esempio.
Se si usa Visual Studio o Visual Studio Code per eseguire esempi di codice, assicurarsi di aver eseguito l'accesso a tale editor con le stesse credenziali di Azure che si vogliono usare per accedere all'istanza di Gemelli digitali di Azure. Se si usa una finestra dell'interfaccia della riga di comando locale, eseguire il comando az login
per accedere all'account Azure. In seguito, quando si esegue l'esempio di codice, si dovrebbe essere autenticati automaticamente.
Configurare il progetto
Quando si è pronti ad accedere all'istanza di Gemelli digitali di Azure, iniziare a configurare il progetto dell'app client.
Aprire una finestra della console nel computer e creare una directory di progetto vuota in cui archiviare il lavoro durante questa esercitazione. Assegnare alla directory un nome a scelta (ad esempio DigitalTwinsCodeTutorial).
Passare alla nuova directory.
Nella directory del progetto creare un progetto di app console .NET vuoto. Nella finestra di comando è possibile eseguire il comando seguente per creare un progetto C# minimo per la console:
dotnet new console
Questo comando creerà diversi file nella directory, tra cui uno denominato Program.cs in cui verrà scritta la maggior parte del codice.
Tenere aperta la finestra di comando perché si continuerà a usarla nell'intera esercitazione.
Successivamente, aggiungere due dipendenze al progetto che saranno necessarie per l'uso con Gemelli digitali di Azure. La prima è il pacchetto per Azure Digital Twins SDK per .NET, la seconda fornisce gli strumenti che consentono di eseguire l'autenticazione in Azure.
dotnet add package Azure.DigitalTwins.Core
dotnet add package Azure.Identity
Iniziare a scrivere il codice del progetto
In questa sezione si inizia a scrivere il codice del nuovo progetto di app per l'uso con Gemelli digitali di Azure. Le azioni descritte includono:
- Autenticazione per il servizio
- Caricamento di un modello
- Rilevamento degli errori
- Creazione di gemelli digitali
- Creazione di relazioni
- Esecuzione di query sui gemelli digitali
Alla fine dell'esercitazione è anche disponibile una sezione che mostra il codice completo. È possibile usare questa sezione come riferimento per verificare il programma man mano che si procede.
Per iniziare, aprire il file Program.cs in qualsiasi editor di codice. È visualizzato un modello di codice minimo simile al seguente:
Per prima cosa, aggiungere alcune righe di using
all'inizio del codice per eseguire il pull delle dipendenze necessarie.
using Azure.DigitalTwins.Core;
using Azure.Identity;
In seguito verrà aggiunto codice in questo file per inserire alcune funzionalità.
Autenticazione per il servizio
La prima operazione che dovrà essere eseguita dall'app è l'autenticazione per il servizio Gemelli digitali di Azure. Quindi, è possibile creare una classe client del servizio per accedere alle funzioni dell'SDK.
Per eseguire l'autenticazione, è necessario il nome host dell'istanza di Gemelli digitali di Azure.
In Program.csincollare il codice seguente sotto la riga di stampa "Hello, World!" nel metodo Main
.
Impostare il valore di adtInstanceUrl
sul nome host dell'istanza di Gemelli digitali di Azure.
string adtInstanceUrl = "https://<your-Azure-Digital-Twins-instance-hostName>";
var credential = new DefaultAzureCredential();
var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credential);
Console.WriteLine($"Service client created – ready to go");
Salvare il file.
Nella finestra di comando eseguire il codice con questo comando:
dotnet run
Questo comando ripristinerà le dipendenze alla prima esecuzione ed eseguirà quindi il programma.
- Se non si verificano errori, il programma stampa: "Service client created - ready to go" per indicare che il client del servizio è stato creato ed è possibile continuare.
- Poiché il progetto non include ancora un sistema di gestione degli errori, in caso di problemi il codice genera un'eccezione.
Nota
Attualmente è presente un problema noto che interessa la classe wrapper DefaultAzureCredential
che può causare un errore durante l'autenticazione. Se si verifica questo problema, è possibile provare a creare un'istanza di DefaultAzureCredential
con il parametro facoltativo seguente per risolverlo: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });
Per altre informazioni su questo problema, vedere Problemi noti di Gemelli digitali di Azure.
Caricare un modello
Gemelli digitali di Azure non include un vocabolario di dominio intrinseco. I tipi di elementi dell'ambiente che è possibile rappresentare in Gemelli digitali di Azure vengono definiti dall'utente usando i modelli. I modelli sono simili alle classi nei linguaggi di programmazione orientati a oggetti. Forniscono modelli definiti dall'utente per i gemelli digitali da seguire e di cui creare istanze in seguito. Sono scritti in un linguaggio simile a JSON, DTDL (Digital Twin Definition Language).
Il primo passaggio per la creazione di una soluzione di Gemelli digitali di Azure consiste nel definire almeno un modello in un file DTDL.
Nella directory in cui è stato creato il progetto creare un nuovo file .json denominato SampleModel.json. Incollare il corpo del file seguente:
{
"@id": "dtmi:example:SampleModel;1",
"@type": "Interface",
"displayName": "SampleModel",
"contents": [
{
"@type": "Relationship",
"name": "contains"
},
{
"@type": "Property",
"name": "data",
"schema": "string"
}
],
"@context": "dtmi:dtdl:context;3"
}
Suggerimento
Se per questa esercitazione si usa Visual Studio, è possibile selezionare il nuovo file JSON e impostare la proprietà Copia nella directory di output di Controllo proprietà su Copia se è più recente o su Copia sempre. In questo modo Visual Studio troverà il file JSON con il percorso predefinito quando si eseguirà il programma con F5 durante il resto dell'esercitazione.
Suggerimento
È possibile controllare i documenti del modello per assicurarsi che DTDL sia valido usando la libreria DTDLParser. Per altre informazioni sull'uso di questa libreria, vedere Analizzare e convalidare i modelli.
Successivamente, aggiungere altro codice al file Program.cs per caricare il modello creato nell'istanza di Gemelli digitali di Azure.
Aggiungere prima di tutto alcune istruzioni using
all'inizio del file:
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
using Azure;
Prepararsi quindi a usare i metodi asincroni dell'SDK del servizio C# cambiando la firma del metodo Main
per consentire l'esecuzione asincrona.
static async Task Main(string[] args)
{
Nota
L'uso di async
non è strettamente necessario, in quanto l'SDK fornisce anche versioni sincrone di tutte le chiamate. Questa esercitazione illustra come usare async
.
Quindi aggiungere il primo frammento di codice che interagisce con il servizio Gemelli digitali di Azure. Questo codice carica il file DTDL creato dal disco e quindi lo carica nell'istanza del servizio Gemelli digitali di Azure.
Incollare il codice seguente sotto il codice di autorizzazione aggiunto in precedenza.
Console.WriteLine();
Console.WriteLine($"Upload a model");
string dtdl = File.ReadAllText("SampleModel.json");
var models = new List<string> { dtdl };
// Upload the model to the service
await client.CreateModelsAsync(models);
Nella finestra di comando eseguire il programma con questo comando:
dotnet run
Nell'output verrà stampato il messaggio "Upload a model", a indicare che il codice è stato raggiunto ma non è ancora disponibile un output per confermare se il caricamento è riuscito.
Per aggiungere un'istruzione di stampa che indica che tutti i modelli sono stati caricati correttamente nell'istanza, aggiungere il codice seguente subito dopo la sezione precedente:
// Read a list of models back from the service
AsyncPageable<DigitalTwinsModelData> modelDataList = client.GetModelsAsync();
await foreach (DigitalTwinsModelData md in modelDataList)
{
Console.WriteLine($"Model: {md.Id}");
}
Prima di eseguire di nuovo il programma per testare questo nuovo codice, tenere presente che l'ultima volta in cui è stato eseguito il programma, il modello è già stato caricato. Gemelli digitali di Azure non consentono di caricare lo stesso modello due volte. Se pertanto si tenta di caricare nuovamente lo stesso modello, il programma dovrebbe generare un'eccezione.
Tenendo presente queste informazioni, eseguire di nuovo il programma con questo comando nella finestra di comando:
dotnet run
Il programma dovrà generare un'eccezione. Quando si prova a caricare un modello che è già stato caricato, il servizio restituisce un errore di tipo "richiesta non valida" tramite l'API REST. Di conseguenza, l'SDK del client di Gemelli digitali di Azure genererà a sua volta un'eccezione, per ogni codice restituito dal servizio diverso da success.
Nella sezione successiva vengono illustrate eccezioni come questa, con informazioni su come gestirle nel codice.
Rilevare gli errori
Per evitare l'arresto anomalo del programma, è possibile aggiungere il codice di eccezione intorno al codice di caricamento del modello. Eseguire il wrapping della chiamata client esistente await client.CreateModelsAsync(typeList)
in un gestore try/catch, come indicato di seguito:
try
{
await client.CreateModelsAsync(models);
Console.WriteLine("Models uploaded to the instance:");
}
catch (RequestFailedException e)
{
Console.WriteLine($"Upload model error: {e.Status}: {e.Message}");
}
Eseguire di nuovo il programma con dotnet run
nella finestra di comando. Si noterà che si ottengono altri dettagli sul problema di caricamento del modello, incluso un codice di errore che indica che ModelIdAlreadyExists
.
Da questo punto in poi, nell'esercitazione verrà eseguito il wrapping di tutte le chiamate ai metodi del servizio in gestori try/catch.
Creare i gemelli digitali
Dopo aver caricato un modello in Gemelli digitali di Azure, è possibile usare la relativa definizione per creare i gemelli digitali. I gemelli digitali sono istanze di un modello e rappresentano le entità all'interno dell'ambiente aziendale, ad esempio i sensori di un'azienda agricola, le stanze di un edificio o i fari di un'auto. Questa sezione crea alcuni gemelli digitali basati sul modello caricato in precedenza.
Aggiungere il codice seguente alla fine del metodo Main
per creare e inizializzare tre gemelli digitali basati su questo modello.
var twinData = new BasicDigitalTwin();
twinData.Metadata.ModelId = "dtmi:example:SampleModel;1";
twinData.Contents.Add("data", $"Hello World!");
string prefix = "sampleTwin-";
for (int i = 0; i < 3; i++)
{
try
{
twinData.Id = $"{prefix}{i}";
await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinData.Id, twinData);
Console.WriteLine($"Created twin: {twinData.Id}");
}
catch(RequestFailedException e)
{
Console.WriteLine($"Create twin error: {e.Status}: {e.Message}");
}
}
Nella finestra di comando eseguire il programma con dotnet run
. Nell'output cercare i messaggi che indicano che sampleTwin-0, sampleTwin-1 e sampleTwin-2 sono stati creati.
Quindi eseguire di nuovo il programma.
Si noti che non viene generato alcun errore quando i gemelli vengono creati per la seconda volta, anche se esistono già dopo la prima esecuzione. A differenza della creazione del modello, la creazione di un gemello è, a livello REST, una chiamata PUT con semantica upsert. Usando questo tipo di chiamata REST significa che se un gemello esiste già e si prova a creare di nuovo lo stesso gemello, verrà semplicemente sostituito quello originale. Non vengono generati errori.
Creare relazioni
Successivamente, è possibile creare relazioni tra i gemelli creati, per connetterli in un grafo dei gemelli. I grafi dei gemelli vengono usati per rappresentare l'intero ambiente.
Aggiungere un nuovo metodo statico alla classe Program
, sotto il metodo Main
(il codice include ora due metodi):
public async static Task CreateRelationshipAsync(DigitalTwinsClient client, string srcId, string targetId)
{
var relationship = new BasicRelationship
{
TargetId = targetId,
Name = "contains"
};
try
{
string relId = $"{srcId}-contains->{targetId}";
await client.CreateOrReplaceRelationshipAsync(srcId, relId, relationship);
Console.WriteLine("Created relationship successfully");
}
catch (RequestFailedException e)
{
Console.WriteLine($"Create relationship error: {e.Status}: {e.Message}");
}
}
Aggiungere quindi il codice seguente alla fine del metodo Main
per chiamare il metodo CreateRelationship
e usare il codice appena scritto:
// Connect the twins with relationships
await CreateRelationshipAsync(client, "sampleTwin-0", "sampleTwin-1");
await CreateRelationshipAsync(client, "sampleTwin-0", "sampleTwin-2");
Nella finestra di comando eseguire il programma con dotnet run
. Nell'output cercare le istruzioni di stampa che indicano che le due relazioni sono state create correttamente.
Gemelli digitali di Azure non consente di creare una relazione se ne esiste già una con lo stesso ID. Quindi, se si esegue il programma più volte, verranno visualizzate eccezioni alla creazione della relazione. Questo codice rileva le eccezioni e le ignora.
Elencare le relazioni
Il codice successivo che verrà aggiunto consente di visualizzare l'elenco di relazioni create.
Aggiungere il nuovo metodo seguente alla classe Program
:
public async static Task ListRelationshipsAsync(DigitalTwinsClient client, string srcId)
{
try
{
AsyncPageable<BasicRelationship> results = client.GetRelationshipsAsync<BasicRelationship>(srcId);
Console.WriteLine($"Twin {srcId} is connected to:");
await foreach (BasicRelationship rel in results)
{
Console.WriteLine($" -{rel.Name}->{rel.TargetId}");
}
}
catch (RequestFailedException e)
{
Console.WriteLine($"Relationship retrieval error: {e.Status}: {e.Message}");
}
}
Aggiungere quindi il codice seguente alla fine del metodo Main
per chiamare il codice ListRelationships
:
//List the relationships
await ListRelationshipsAsync(client, "sampleTwin-0");
Nella finestra di comando eseguire il programma con dotnet run
. Verrà visualizzato un elenco di tutte le relazioni create in un'istruzione di output simile alla seguente:
Eseguire query sui gemelli digitali
Una delle principali funzionalità di Gemelli digitali di Azure è la possibilità di eseguire query sul grafo dei gemelli in modo semplice ed efficiente per trovare le risposte alle domande sull'ambiente.
L'ultima sezione del codice da aggiungere in questa esercitazione esegue una query sull'istanza di Gemelli digitali di Azure. La query usata in questo esempio restituisce tutti i gemelli digitali dell'istanza.
Aggiungere questa istruzione using
per consentire l'uso della classe JsonSerializer
e presentare le informazioni del gemello digitale:
using System.Text.Json;
Aggiungere quindi il codice seguente alla fine del metodo Main
:
// Run a query for all twins
string query = "SELECT * FROM digitaltwins";
AsyncPageable<BasicDigitalTwin> queryResult = client.QueryAsync<BasicDigitalTwin>(query);
await foreach (BasicDigitalTwin twin in queryResult)
{
Console.WriteLine(JsonSerializer.Serialize(twin));
Console.WriteLine("---------------");
}
Nella finestra di comando eseguire il programma con dotnet run
. Nell'output verranno visualizzati tutti i dispositivi gemelli digitali di questa istanza.
Nota
Dopo aver apportato una modifica ai dati nel grafo, potrebbe verificarsi una latenza di fino a 10 secondi prima che le modifiche vengano riflesse nelle query.
L'API DigitalTwins riflette immediatamente le modifiche, quindi se è necessaria una risposta immediata, usare una richiesta API (DigitalTwins GetById) o una chiamata SDK (GetDigitalTwin) per ottenere dati gemelli anziché una query.
Esempio di codice completo
A questo punto dell'esercitazione si avrà un'app client completa, in grado di eseguire azioni di base con Gemelli digitali di Azure. Per riferimento, di seguito è riportato il codice completo del programma nel file Program.cs:
using System;
// <Azure_Digital_Twins_dependencies>
using Azure.DigitalTwins.Core;
using Azure.Identity;
// </Azure_Digital_Twins_dependencies>
// <Model_dependencies>
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
using Azure;
// </Model_dependencies>
// <Query_dependencies>
using System.Text.Json;
// </Query_dependencies>
namespace DigitalTwins_Samples
{
class DigitalTwinsClientAppSample
{
// <Async_signature>
static async Task Main(string[] args)
{
// </Async_signature>
Console.WriteLine("Hello World!");
// <Authentication_code>
string adtInstanceUrl = "https://<your-Azure-Digital-Twins-instance-hostName>";
var credential = new DefaultAzureCredential();
var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credential);
Console.WriteLine($"Service client created – ready to go");
// </Authentication_code>
// <Model_code>
Console.WriteLine();
Console.WriteLine("Upload a model");
string dtdl = File.ReadAllText("SampleModel.json");
var models = new List<string> { dtdl };
// Upload the model to the service
// <Model_try_catch>
try
{
await client.CreateModelsAsync(models);
Console.WriteLine("Models uploaded to the instance:");
}
catch (RequestFailedException e)
{
Console.WriteLine($"Upload model error: {e.Status}: {e.Message}");
}
// </Model_try_catch>
// <Print_model>
// Read a list of models back from the service
AsyncPageable<DigitalTwinsModelData> modelDataList = client.GetModelsAsync();
await foreach (DigitalTwinsModelData md in modelDataList)
{
Console.WriteLine($"Model: {md.Id}");
}
// </Print_model>
// </Model_code>
// <Initialize_twins>
var twinData = new BasicDigitalTwin();
twinData.Metadata.ModelId = "dtmi:example:SampleModel;1";
twinData.Contents.Add("data", $"Hello World!");
string prefix = "sampleTwin-";
for (int i = 0; i < 3; i++)
{
try
{
twinData.Id = $"{prefix}{i}";
await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinData.Id, twinData);
Console.WriteLine($"Created twin: {twinData.Id}");
}
catch(RequestFailedException e)
{
Console.WriteLine($"Create twin error: {e.Status}: {e.Message}");
}
}
// </Initialize_twins>
// <Use_create_relationship>
// Connect the twins with relationships
await CreateRelationshipAsync(client, "sampleTwin-0", "sampleTwin-1");
await CreateRelationshipAsync(client, "sampleTwin-0", "sampleTwin-2");
// </Use_create_relationship>
// <Use_list_relationships>
//List the relationships
await ListRelationshipsAsync(client, "sampleTwin-0");
// </Use_list_relationships>
// <Query_twins>
// Run a query for all twins
string query = "SELECT * FROM digitaltwins";
AsyncPageable<BasicDigitalTwin> queryResult = client.QueryAsync<BasicDigitalTwin>(query);
await foreach (BasicDigitalTwin twin in queryResult)
{
Console.WriteLine(JsonSerializer.Serialize(twin));
Console.WriteLine("---------------");
}
// </Query_twins>
}
// <Create_relationship>
public async static Task CreateRelationshipAsync(DigitalTwinsClient client, string srcId, string targetId)
{
var relationship = new BasicRelationship
{
TargetId = targetId,
Name = "contains"
};
try
{
string relId = $"{srcId}-contains->{targetId}";
await client.CreateOrReplaceRelationshipAsync(srcId, relId, relationship);
Console.WriteLine("Created relationship successfully");
}
catch (RequestFailedException e)
{
Console.WriteLine($"Create relationship error: {e.Status}: {e.Message}");
}
}
// </Create_relationship>
// <List_relationships>
public async static Task ListRelationshipsAsync(DigitalTwinsClient client, string srcId)
{
try
{
AsyncPageable<BasicRelationship> results = client.GetRelationshipsAsync<BasicRelationship>(srcId);
Console.WriteLine($"Twin {srcId} is connected to:");
await foreach (BasicRelationship rel in results)
{
Console.WriteLine($" -{rel.Name}->{rel.TargetId}");
}
}
catch (RequestFailedException e)
{
Console.WriteLine($"Relationship retrieval error: {e.Status}: {e.Message}");
}
}
// </List_relationships>
}
}
Pulire le risorse
Dopo aver completato questa esercitazione, è possibile scegliere le risorse da rimuovere, a seconda delle operazioni da eseguire successivamente.
- Se si prevede di continuare con l'esercitazione successiva, l'istanza usata in questa esercitazione può essere riutilizzata nella successiva. È possibile mantenere le risorse di Gemelli digitali di Azure configurate qui e ignorare il resto di questa sezione.
Se si desidera continuare a usare l'istanza di Gemelli digitali di Azure di questo articolo, ma cancellare tutti i modelli, i gemelli e le relazioni, eseguire il comando dell'interfaccia della riga di comandoaz dt job deletion seguente:
az dt job deletion create -n <name-of-Azure-Digital-Twins-instance> -y
Se si desidera eliminare solo alcuni di questi elementi, è possibile usare i comandi az dt twin relationship delete, az dt twin delete e az dt model delete per eliminare in modo selettivo solo gli elementi da rimuovere.
Se non sono necessarie risorse create in questa esercitazione, è possibile eliminare l'istanza di Gemelli digitali di Azure e tutte le altre risorse di questo articolo con il comando az group delete dell'interfaccia della riga di comando. In questo modo vengono eliminate tutte le risorse di Azure in un gruppo di risorse, nonché il gruppo di risorse stesso.
Importante
L'eliminazione di un gruppo di risorse è irreversibile. Il gruppo di risorse e tutte le risorse in esso contenute vengono eliminati in modo permanente. Assicurarsi di non eliminare accidentalmente il gruppo di risorse sbagliato o le risorse errate.
Aprire Azure Cloud Shell o una finestra dell’interfaccia della riga di comando locale ed eseguire il comando seguente per eliminare il gruppo di risorse e tutti gli elementi contenuti al suo interno.
az group delete --name <your-resource-group>
È anche possibile eliminare la cartella del progetto dal computer locale.
Passaggi successivi
In questa esercitazione è stata creata un'applicazione client console .NET da zero. È stato scritto il codice per l'app client per eseguire le azioni di base con un'istanza di Gemelli digitali di Azure.
Continuare con l'esercitazione successiva per esplorare le operazioni che è possibile eseguire con questa app client di esempio: