Gestire i gemelli digitali

Le entità nell'ambiente sono rappresentate da gemelli digitali. La gestione dei gemelli digitali può includere la creazione, la modifica e la rimozione.

Questo articolo è incentrato sulla gestione dei gemelli digitali; per lavorare con le relazioni e il grafo dei gemelli nel suo complesso, vedere Gestire il grafo e le relazioni dei gemelli.

Suggerimento

Tutte le funzioni SDK sono disponibili in versioni sincrone e asincrone.

Prerequisiti

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.

Interfacce per sviluppatori

Questo articolo illustra come completare diverse operazioni di gestione usando .NET (C#) SDK. È anche possibile creare queste stesse chiamate di gestione usando gli altri SDK del linguaggio descritti in API e SDK di Gemelli digitali di Azure.

Altre interfacce di sviluppo che è possibile usare per completare queste operazioni includono:

Visualizzazione

Azure Digital Twins Explorer è uno strumento visivo per esplorare i dati nel grafo di Gemelli digitali di Azure. È possibile usare Esplora risorse per visualizzare, eseguire query e modificare modelli, gemelli e relazioni.

Per informazioni sullo strumento Azure Digital Twins Explorer, vedere Azure Digital Twins Explorer. Per informazioni dettagliate su come usare le funzionalità, vedere Usare Azure Digital Twins Explorer.

La visualizzazione deve avere il seguente aspetto:

Screenshot di Azure Digital Twins Explorer che mostra modelli e gemelli di esempio.

Creare un gemello digitale

Per creare un gemello, usare il metodo CreateOrReplaceDigitalTwinAsync() nel client del servizio, come illustrato di seguito:

await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinId, initData);

Per creare un gemello digitale è necessario fornire:

  • Valore ID da assegnare al gemello digitale (si sta definendo tale ID al momento della creazione del gemello)
  • Il modello da usare
  • Qualsiasi inizializzazione desiderata dei dati gemelli, tra cui...
    • Proprietà (inizializzazione facoltativa): è possibile impostare i valori iniziali per le proprietà del gemello digitale, se necessario. Le proprietà vengono considerate facoltative e possono essere impostate in un secondo momento, ma si noti che non verranno visualizzate come parte di un gemello fino a quando non sono state impostate.
    • Componenti (inizializzazione necessaria se presenti in un gemello): se il gemello contiene componenti, questi devono essere inizializzati quando viene creato il gemello. Possono essere oggetti vuoti, ma i componenti stessi devono esistere.

Il modello e i valori iniziali delle proprietà vengono forniti tramite il parametro initData, ovvero una stringa JSON contenente i dati pertinenti. Per altre informazioni sulla strutturazione di questo oggetto, continuare con la sezione successiva.

Suggerimento

Dopo aver creato o aggiornato un gemello, potrebbe verificarsi una latenza di fino a 10 secondi prima che le modifiche vengano riflesse nelle query. L'API GetDigitalTwin (descritta più avanti in questo articolo) non riscontra questo ritardo, quindi se è necessaria una risposta immediata, usare la chiamata API anziché eseguire query per visualizzare i gemelli appena creati.

Inizializzare il modello e le proprietà

È possibile inizializzare le proprietà di un gemello al momento della sua creazione.

L'API di creazione del gemello accetta un oggetto serializzato in una descrizione JSON valida delle proprietà del gemello. Per una descrizione del formato JSON per un gemello, vedere Gemelli digitali e il grafo dei gemelli.

In primo luogo, è possibile creare un oggetto dati per rappresentare il gemello e i relativi dati delle proprietà. È possibile creare un oggetto parametro manualmente o usando una classe helper fornita. Ecco un esempio di ognuno di essi.

Creare gemelli usando dati creati manualmente

Senza l'uso di classi helper personalizzate, è possibile rappresentare le proprietà di un gemello in un Dictionary<string, object>, dove string è il nome della proprietà e object è un oggetto che rappresenta la proprietà e il relativo valore.

// Define a custom model type for the twin to be created

internal class CustomDigitalTwin
{
    [JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinId)]
    public string Id { get; set; }

    [JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinETag)]
    public string ETag { get; set; }

    [JsonPropertyName("temperature")]
    public double Temperature { get; set; }

    [JsonPropertyName("humidity")]
    public double Humidity{ get; set; }
}

// Initialize properties and create the twin
public class TwinOperationsCreateTwin
{
    public async Task CreateTwinAsync(DigitalTwinsClient client)
    {
        // Initialize the twin properties
        var myTwin = new CustomDigitalTwin
        {
            Temperature = 25.0,
            Humidity = 50.0,
        };

        // Create the twin
        const string twinId = "<twin-ID>";
        Response<CustomDigitalTwin> response = await client.CreateOrReplaceDigitalTwinAsync(twinId, myTwin);
        Console.WriteLine($"Temperature value: {response.Value.Temperature}");
    }
}

Creare gemelli con la classe helper

La classe helper di BasicDigitalTwin consente di archiviare direttamente i campi delle proprietà in un oggetto "gemello". È comunque possibile compilare l'elenco di proprietà usando un Dictionary<string, object>, che può quindi essere aggiunto all'oggetto gemello direttamente come suo CustomProperties.

string twinId = "myTwinID";
var initData = new BasicDigitalTwin
{
    Id = twinId,
    Metadata = { ModelId = "dtmi:example:Room;1" },
    // Initialize properties
    Contents =
    {
        { "Temperature", 25.0 },
        { "Humidity", 50.0 },
    },
};

await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinId, initData);

Nota

Gli oggetti BasicDigitalTwin sono dotati di un campo Id. È possibile lasciare vuoto questo campo, ma se si aggiunge un valore ID, deve corrispondere al parametro ID passato alla chiamata CreateOrReplaceDigitalTwinAsync(). Ad esempio:

twin.Id = "myRoomId";

Creare gemelli in blocco con l'API Importa processi

È possibile usare l'API Importa processi per creare più gemelli contemporaneamente in una singola chiamata API. Questo metodo richiede l'uso di Archiviazione BLOB di Azure e delle autorizzazioni di scrittura nell'istanza di Gemelli digitali di Azure per i gemelli e i processi in blocco.

Suggerimento

L'API Processi di importazione consente anche l'importazione di modelli e relazioni nella stessa chiamata, per creare tutte le parti di un grafo contemporaneamente. Per altre informazioni su questo processo, vedere Caricare modelli, gemelli e relazioni in blocco con l'API Importa processi.

Per importare gemelli in blocco, è necessario strutturare i gemelli (e tutte le altre risorse incluse nel processo di importazione bulk) come file NDJSON. La sezione Twins viene dopo quella Models (e prima della sezione Relationships ). I gemelli definiti nel file possono fare riferimento a modelli definiti in questo file o già presenti nell'istanza e possono includere facoltativamente l'inizializzazione delle proprietà del gemello.

È possibile visualizzare un file di importazione di esempio e un progetto di esempio per la creazione di questi file nell’introduzione all'API Importa processi.

Successivamente, il file deve essere caricato in un BLOB di accodamento in Archiviazione BLOB di Azure. Per istruzioni su come creare un contenitore di Archiviazione di Azure, vedere Creare un contenitore. Caricare quindi il file usando il metodo di caricamento preferito (alcune opzioni sono il comando AzCopy, l'interfaccia della riga di comando di Azure o il portale di Azure).

Dopo aver caricato il file NDJSON nel contenitore, ottenere l'URL all'interno del contenitore BLOB. Questo valore verrà usato più avanti nel corpo della chiamata API di importazione in blocco.

Ecco uno screenshot che mostra il valore URL di un file BLOB nel portale di Azure:

Screenshot del portale di Azure che mostra l'URL di un file in un contenitore di archiviazione.

Il file può quindi essere usato in una chiamata API Importa lavori. Specificare l'URL di archiviazione BLOB del file di input e un nuovo URL di archiviazione BLOB per indicare dove archiviare il log di output dopo la creazione del servizio.

Ottenere dati per un gemello digitale

È possibile accedere ai dettagli di qualsiasi gemello digitale chiamando il metodo GetDigitalTwin() nel modo seguente:

Response<BasicDigitalTwin> twinResponse = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twinId);
twin = twinResponse.Value;

Questa chiamata restituisce dati gemelli come tipo di oggetto fortemente tipizzato, ad esempio BasicDigitalTwin. BasicDigitalTwin è una classe helper di serializzazione inclusa nell'SDK, che restituisce i metadati e le proprietà del gemello di base nel modulo preparato. È sempre possibile deserializzare i dati gemelli usando la libreria JSON di propria scelta, ad esempio System.Text.Json o Newtonsoft.Json. Per l'accesso di base a un gemello, tuttavia, le classi helper possono rendere più conveniente questa operazione.

Nota

BasicDigitalTwin usa gli attributi System.Text.Json. Per usare BasicDigitalTwin con DigitalTwinsClient, è necessario inizializzare il client con il costruttore predefinito oppure, se si desidera personalizzare l'opzione serializzatore, usare JsonObjectSerializer.

La classe helper BasicDigitalTwin consente anche di accedere alle proprietà definite nel gemello tramite un Dictionary<string, object>. Per elencare le proprietà del gemello digitale, è possibile usare:

BasicDigitalTwin twin;
Response<BasicDigitalTwin> twinResponse = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twinId);
twin = twinResponse.Value;
Console.WriteLine($"Model id: {twin.Metadata.ModelId}");
foreach (string prop in twin.Contents.Keys)
{
    if (twin.Contents.TryGetValue(prop, out object value))
        Console.WriteLine($"Property '{prop}': {value}");
}

Quando si recupera un gemello con il metodo GetDigitalTwin(), vengono restituite solo le proprietà impostate almeno una volta.

Suggerimento

Il displayName per un gemello fa parte dei metadati del modello, quindi non verrà visualizzato quando si recuperano dati per l'istanza del gemello. Per visualizzare questo valore, è possibile recuperarlo dal modello.

Per recuperare più gemelli usando una singola chiamata API, vedere esempi di API di query in Eseguire query sul grafo dei gemelli.

Si consideri il modello seguente (scritto in Digital Twins Definition Language (DTDL)) che definisce un Moon:

{
    "@id": "dtmi:example:Moon;1",
    "@type": "Interface",
    "@context": "dtmi:dtdl:context;3",
    "contents": [
        {
            "@type": "Property",
            "name": "radius",
            "schema": "double",
            "writable": true
        },
        {
            "@type": "Property",
            "name": "mass",
            "schema": "double",
            "writable": true
        }
    ]
}

Il risultato della chiamata object result = await client.GetDigitalTwinAsync("my-moon"); a un gemello di tipo Moon potrebbe essere simile al seguente:

{
  "$dtId": "myMoon-001",
  "$etag": "W/\"e59ce8f5-03c0-4356-aea9-249ecbdc07f9\"",
  "radius": 1737.1,
  "mass": 0.0734,
  "$metadata": {
    "$model": "dtmi:example:Moon;1",
    "radius": {
      "lastUpdateTime": "2022-12-06T20:00:32.8209188Z"
    },
    "mass": {
      "lastUpdateTime": "2022-12-04T12:04:43.3859361Z"
    }
  }
}

Le proprietà definite del gemello digitale vengono restituite come proprietà di primo livello nel gemello digitale. I metadati o le informazioni di sistema che non fanno parte della definizione DTDL vengono restituiti con un prefisso $. Le proprietà dei metadati sono inclusi i valori seguenti:

  • $dtId: ID del gemello digitale in questa istanza di Gemelli digitali di Azure
  • $etag: campo HTTP standard assegnato dal server Web. Questo valore viene aggiornato a un nuovo valore ogni volta che il gemello viene aggiornato, che può essere utile per determinare se i dati del gemello sono stati aggiornati nel server dopo un controllo precedente. È possibile usare If-Match per eseguire aggiornamenti ed eliminazioni che vengono completate solo se l'etag dell'entità corrisponde all'etag specificato. Per altre informazioni su queste operazioni, vedere la documentazione relativa all'Aggiornamento di DigitalTwins ed Eliminazione di DigitalTwins.
  • $metadata: set di proprietà dei metadati, che possono includere quanto segue:
    • $model, il DTMI del modello del gemello digitale.
    • lastUpdateTime per le proprietà del gemello. Timestamp che indica la data e l'ora in cui Gemelli digitali di Azure ha elaborato il messaggio di aggiornamento della proprietà
    • sourceTime per le proprietà del gemello. Si tratta di una proprietà facoltativa scrivibile che rappresenta il timestamp quando l'aggiornamento della proprietà è stato osservato nel mondo reale.

Per altre informazioni sui campi contenuti in un gemello digitale, vedere Formato JSON di Gemelli digitali. Per altre informazioni sulle classi helper di serializzazione, ad esempio BasicDigitalTwin in API e SDK di Gemelli digitali di Azure.

Visualizzare tutti i gemelli digitali

Per visualizzare tutti i gemelli digitali nell'istanza, usare una query. È possibile eseguire una query con le API Query o i comandi dell'interfaccia della riga di comando.

Ecco il corpo della query di base che restituisce un elenco di tutti i gemelli digitali nell'istanza:

SELECT * FROM DIGITALTWINS

Aggiornare un gemello digitale

Per aggiornare le proprietà di un gemello digitale, scrivere le informazioni da sostituire nel formato JSON Patch. Per un elenco completo delle operazioni JSON Patch che possono essere usate, tra cui replace, add e remove, vedere Operazioni per JSON Patch.

Dopo aver creato il documento JSON Patch contenente informazioni sull'aggiornamento, passare il documento al metodo UpdateDigitalTwin():

await client.UpdateDigitalTwinAsync(twinId, updateTwinData);

Una singola chiamata patch può aggiornare tutte le proprietà in un singolo gemello desiderato (anche tutte). Se è necessario aggiornare le proprietà tra più gemelli, è necessaria una chiamata di aggiornamento separata per ogni gemello.

Suggerimento

Dopo aver creato o aggiornato un gemello, potrebbe verificarsi una latenza di fino a 10 secondi prima che le modifiche vengano riflesse nelle query. L'API GetDigitalTwin (descritta in precedenza in questo articolo) non riscontra questo ritardo, per cui usare la chiamata API anziché eseguire query per visualizzare i gemelli appena creati, laddove sia necessaria una risposta immediata.

Di seguito è riportato un esempio di codice JSON Patch. Questo documento sostituisce i valori delle proprietà massa e raggio del gemello digitale a cui viene applicato. Questo esempio mostra l'operazione JSON Patch replace, che sostituisce il valore di una proprietà esistente.

[
    {
      "op": "replace",
      "path": "/mass",
      "value": 0.0799
    },
    {
      "op": "replace",
      "path": "/radius",
      "value": 0.800
    }
  ]

Quando si aggiorna un gemello da un progetto di codice usando .NET SDK, è possibile creare JSON Patch usando JsonPatchDocument di SDK Azure .NET. Ecco un esempio di creazione di un documento JSON Patch e dell'uso di UpdateDigitalTwin() nel codice del progetto.

var updateTwinData = new JsonPatchDocument();
updateTwinData.AppendAdd("/Temperature", 25.0);
updateTwinData.AppendAdd("/myComponent/Property", "Hello");
// Un-set a property
updateTwinData.AppendRemove("/Humidity");

await client.UpdateDigitalTwinAsync("myTwin", updateTwinData).ConfigureAwait(false);

Suggerimento

È possibile mantenere i timestamp di origine nei gemelli digitali aggiornando il campo $metadata.<property-name>.sourceTime con il processo descritto in questa sezione. Per altre informazioni su questo campo e altri campi scrivibili nei gemelli digitali, vedere Formato JSON di Gemelli digitali.

Aggiornare le sottoproprietà nei componenti di Gemelli digitali

Tenere presente che un modello può contenere componenti, consentendogli di essere costituito da altri modelli.

Per applicare patch alle proprietà nei componenti di un gemello digitale, è possibile usare la sintassi del percorso in JSON Patch:

[
  {
    "op": "replace",
    "path": "/mycomponentname/mass",
    "value": 0.0799
  }
]

Aggiornare le sottoproprietà nelle proprietà di tipo oggetto

I modelli possono contenere proprietà di un tipo di oggetto. Tali oggetti potrebbero avere proprietà specifiche e potrebbe essere necessario aggiornare una di queste sottoproprietà appartenenti alla proprietà di tipo oggetto. Questo processo è simile al processo per l'aggiornamento delle sottoproprietà nei componenti, ma potrebbe richiedere alcuni passaggi aggiuntivi.

Si consideri un modello con una proprietà di tipo oggetto, ObjectProperty. ObjectProperty ha una proprietà stringa denominata StringSubProperty.

Quando un gemello viene creato usando questo modello, non è necessario creare un'istanza di ObjectProperty in quel momento. Se la proprietà dell'oggetto non viene creata un'istanza durante la creazione del gemello, non esiste alcun percorso predefinito creato per l'accesso ObjectProperty e per StringSubProperty un'operazione di patch. È necessario aggiungere il percorso a ObjectProperty sé stessi prima di poter aggiornarne le proprietà.

Questa operazione può essere eseguita con un'operazione add JSON Patch, come illustrato di seguito:

[
  {
    "op": "add", 
    "path": "/ObjectProperty", 
    "value": {"StringSubProperty":"<string-value>"}
  }
]

Nota

Se ObjectProperty ha più di una proprietà, è necessario includerne tutte nel campo value di questa operazione, anche se ne sta aggiornando una sola:

... "value": {"StringSubProperty":"<string-value>", "Property2":"<property2-value>", ...}

Una volta completata questa operazione, è presente un percorso a StringSubProperty che è possibile aggiornare direttamente da ora in poi con un'operazione replace tipica:

[
  {
    "op": "replace",
    "path": "/ObjectProperty/StringSubProperty",
    "value": "<string-value>"
  }
]

Anche se il primo passaggio non è necessario nei casi in cui è stata creata un'istanza ObjectProperty al momento della creazione del gemello, è consigliabile usarla ogni volta che si aggiorna una sottoproprietà per la prima volta, poiché non è sempre possibile sapere con certezza se la proprietà dell'oggetto è stata inizialmente creata o meno.

Aggiornare il modello di un gemello digitale

La funzione UpdateDigitalTwin() può essere usata anche per eseguire la migrazione di un gemello digitale a un modello diverso.

Si consideri ad esempio il documento JSON Patch seguente che sostituisce il campo $model dei metadati del gemello digitale:

[
  {
    "op": "replace",
    "path": "/$metadata/$model",
    "value": "dtmi:example:foo;1"
  }
]

Questa operazione ha esito positivo solo se il gemello digitale modificato dalla patch è conforme al nuovo modello.

Si consideri l'esempio seguente:

  1. Immaginare un gemello digitale con un modello di foo_old. foo_old definisce una massa di proprietà obbligatoria.
  2. Il nuovo modello foo_new definisce una massa di proprietà e aggiunge una nuova temperatura della proprietà richiesta.
  3. Dopo la patch, il gemello digitale deve avere come proprietà sia la massa che la temperatura.

La patch per questa situazione deve aggiornare la proprietà temperatura sia del modello che del gemello, come indicato di seguito:

[
  {
    "op": "replace",
    "path": "/$metadata/$model",
    "value": "dtmi:example:foo_new;1"
  },
  {
    "op": "add",
    "path": "/temperature",
    "value": 60
  }
]

Aggiornare sourceTime di una proprietà

Facoltativamente, è possibile decidere di usare il campo sourceTime sulle proprietà dei dispositivi gemelli per registrare i timestamp per quando gli aggiornamenti delle proprietà vengono osservati nel mondo reale. Gemelli digitali di Azure supporta sourceTime in modo nativo nei metadati per ogni proprietà del gemello. Il valore sourceTime deve essere conforme al formato di data e ora ISO 8601. Per altre informazioni su questo campo e altri campi nei gemelli digitali, vedere Formato JSON di Gemelli digitali.

La versione minima dell'API REST stabile per supportare questo campo è la versione 2022-05-31. Per usare questo campo usando gli SDK di Gemelli digitali di Azure, è consigliabile usare la versione più recente dell'SDK per assicurarsi che questo campo sia incluso.

Di seguito è riportato un esempio di documento JSON Patch che aggiorna sia il valore che il campo sourceTime di una proprietà Temperature :

[
  {
    "op": "replace",
    "path": "/Temperature",
    "value": "22.3"
  },
  {
    "op": "replace",
    "path": "/$metadata/Temperature/sourceTime",
    "value": "2021-11-30T18:47:53.7648958Z"
  }
]

Per aggiornare il campo sourceTime su una proprietà che fa parte di un componente, includere il componente all'inizio del percorso. Nell'esempio precedente è possibile eseguire questa operazione modificando il valore del percorso da /$metadata/Temperature/sourceTime a myComponent/$metadata/Temperature/sourceTime.

Nota

Se si aggiorna sia sourceTime che il valore in una proprietà e successivamente si aggiorna solo il valore della proprietà, il timestamp sourceTime del primo aggiornamento rimarrà.

Gestire chiamate di aggiornamento in conflitto

Gemelli digitali di Azure garantisce che tutte le richieste in ingresso vengano elaborate una dopo l'altra. Ciò significa, che anche se più funzioni tentano di aggiornare la stessa proprietà in un gemello contemporaneamente, non è necessario scrivere codice di blocco esplicito per gestire il conflitto.

Questo comportamento è per singolo dispositivo gemello.

Si supponga, ad esempio, uno scenario in cui queste tre chiamate arrivano contemporaneamente:

  • Scrivere la proprietà A in Twin1
  • Scrivere la proprietà B in Twin1
  • Scrivere la proprietà A in Twin2

Le due chiamate che modificano Twin1 vengono eseguite una dopo l'altra e i messaggi di modifica vengono generati per ogni modifica. La chiamata alla modifica di Twin2 può essere eseguita simultaneamente senza conflitti, non appena arriva.

Eliminare un gemello digitale

È possibile eliminare i gemelli mediante il metodo DeleteDigitalTwin(). Tuttavia, è possibile eliminare un gemello solo quando non ha più relazioni. Pertanto, eliminare prima le relazioni in ingresso e in uscita del gemello.

Ecco un esempio del codice per eliminare i gemelli e le relative relazioni. La chiamata SDK DeleteDigitalTwin è evidenziata per chiarire dove rientra nel contesto di esempio più ampio.

private static async Task CustomMethod_DeleteTwinAsync(DigitalTwinsClient client, string twinId)
{
    await CustomMethod_FindAndDeleteOutgoingRelationshipsAsync(client, twinId);
    await CustomMethod_FindAndDeleteIncomingRelationshipsAsync(client, twinId);
    try
    {
        await client.DeleteDigitalTwinAsync(twinId);
        Console.WriteLine("Twin deleted successfully");
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine($"*** Error:{ex.Message}");
    }
}

private static async Task CustomMethod_FindAndDeleteOutgoingRelationshipsAsync(DigitalTwinsClient client, string dtId)
{
    // Find the relationships for the twin

    try
    {
        // GetRelationshipsAsync will throw an error if a problem occurs
        AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);

        await foreach (BasicRelationship rel in rels)
        {
            await client.DeleteRelationshipAsync(dtId, rel.Id).ConfigureAwait(false);
            Console.WriteLine($"Deleted relationship {rel.Id} from {dtId}");
        }
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving or deleting relationships for {dtId} due to {ex.Message}");
    }
}

private static async Task CustomMethod_FindAndDeleteIncomingRelationshipsAsync(DigitalTwinsClient client, string dtId)
{
    // Find the relationships for the twin

    try
    {
        // GetRelationshipsAsync will throw an error if a problem occurs
        AsyncPageable<IncomingRelationship> incomingRels = client.GetIncomingRelationshipsAsync(dtId);

        await foreach (IncomingRelationship incomingRel in incomingRels)
        {
            await client.DeleteRelationshipAsync(incomingRel.SourceId, incomingRel.RelationshipId).ConfigureAwait(false);
            Console.WriteLine($"Deleted incoming relationship {incomingRel.RelationshipId} from {dtId}");
        }
    }
    catch (RequestFailedException ex)
    {
        Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving or deleting incoming relationships for {dtId} due to {ex.Message}");
    }
}

Eliminare tutti i gemelli digitali

Per un esempio di come eliminare tutti i gemelli contemporaneamente, scaricare l'app di esempio usata in Esplora le nozioni di base con un'app client di esempio. Il file CommandLoop.cs esegue questa operazione in una funzione CommandDeleteAllTwins().

Nota

Se si desidera eliminare tutti i modelli, i gemelli e le relazioni in un'istanza contemporaneamente, usare l'API Elimina processi.

Esempio di codice di gemelli digitali eseguibili

È possibile usare l'esempio di codice eseguibile seguente per creare un gemello, aggiornarne i dettagli ed eliminare il gemello.

Configurare i file di progetto di esempio

Il frammento di codice usa una definizione di modello di esempio, Room.json. Per scaricare il file del modello in modo da poterlo usare nel codice, usare questo link per passare direttamente al file in GitHub. Fare quindi clic con il pulsante destro del mouse in un punto qualsiasi della schermata, scegliere Salva con nome nel menu di scelta rapida del browser e usare la finestra Salva con nome per salvare il file come Room.json.

Creare quindi un nuovo progetto di app console in Visual Studio o nell'editor preferito.

Successivamente, copiare il codice seguente dell'esempio eseguibile nel progetto:

using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Azure;
using Azure.DigitalTwins.Core;
using Azure.Identity;
using System.IO;

namespace DigitalTwins_Samples
{
    class TwinOperationsSample
    {
        public static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            // Create the Azure Digital Twins client for API calls
            string adtInstanceUrl = "https://<your-instance-hostname>";
            var credentials = new DefaultAzureCredential();
            var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credentials);
            Console.WriteLine($"Service client created – ready to go");

            // Upload models
            Console.WriteLine($"Upload a model");
            string dtdl = File.ReadAllText("<path-to>/Room.json");
            var models = new List<string> { dtdl };
            // Upload the model to the service
            await client.CreateModelsAsync(models);

            // Create new digital twin
            // <CreateTwin_withHelper>
            string twinId = "myTwinID";
            var initData = new BasicDigitalTwin
            {
                Id = twinId,
                Metadata = { ModelId = "dtmi:example:Room;1" },
                // Initialize properties
                Contents =
                {
                    { "Temperature", 25.0 },
                    { "Humidity", 50.0 },
                },
            };

            // <CreateTwinCall>
            await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinId, initData);
            // </CreateTwinCall>
            // </CreateTwin_withHelper>
            Console.WriteLine("Twin created successfully");

            //Print twin
            Console.WriteLine("--- Printing twin details:");
            await CustomMethod_FetchAndPrintTwinAsync(twinId, client);
            Console.WriteLine("--------");

            //Update twin data
            var updateTwinData = new JsonPatchDocument();
            updateTwinData.AppendAdd("/Temperature", 30.0);
            // <UpdateTwinCall>
            await client.UpdateDigitalTwinAsync(twinId, updateTwinData);
            // </UpdateTwinCall>
            Console.WriteLine("Twin properties updated");
            Console.WriteLine();

            //Print twin again
            Console.WriteLine("--- Printing twin details (after update):");
            await CustomMethod_FetchAndPrintTwinAsync(twinId, client);
            Console.WriteLine("--------");
            Console.WriteLine();

            //Delete twin
            await CustomMethod_DeleteTwinAsync(client, twinId);
        }

        private static async Task<BasicDigitalTwin> CustomMethod_FetchAndPrintTwinAsync(string twinId, DigitalTwinsClient client)
        {
            // <GetTwin>
            BasicDigitalTwin twin;
            // <GetTwinCall>
            Response<BasicDigitalTwin> twinResponse = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twinId);
            twin = twinResponse.Value;
            // </GetTwinCall>
            Console.WriteLine($"Model id: {twin.Metadata.ModelId}");
            foreach (string prop in twin.Contents.Keys)
            {
                if (twin.Contents.TryGetValue(prop, out object value))
                    Console.WriteLine($"Property '{prop}': {value}");
            }
            // </GetTwin>

            return twin;
        }

        // <DeleteTwin>
        private static async Task CustomMethod_DeleteTwinAsync(DigitalTwinsClient client, string twinId)
        {
            await CustomMethod_FindAndDeleteOutgoingRelationshipsAsync(client, twinId);
            await CustomMethod_FindAndDeleteIncomingRelationshipsAsync(client, twinId);
            try
            {
                await client.DeleteDigitalTwinAsync(twinId);
                Console.WriteLine("Twin deleted successfully");
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"*** Error:{ex.Message}");
            }
        }

        private static async Task CustomMethod_FindAndDeleteOutgoingRelationshipsAsync(DigitalTwinsClient client, string dtId)
        {
            // Find the relationships for the twin

            try
            {
                // GetRelationshipsAsync will throw an error if a problem occurs
                AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);

                await foreach (BasicRelationship rel in rels)
                {
                    await client.DeleteRelationshipAsync(dtId, rel.Id).ConfigureAwait(false);
                    Console.WriteLine($"Deleted relationship {rel.Id} from {dtId}");
                }
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving or deleting relationships for {dtId} due to {ex.Message}");
            }
        }

        private static async Task CustomMethod_FindAndDeleteIncomingRelationshipsAsync(DigitalTwinsClient client, string dtId)
        {
            // Find the relationships for the twin

            try
            {
                // GetRelationshipsAsync will throw an error if a problem occurs
                AsyncPageable<IncomingRelationship> incomingRels = client.GetIncomingRelationshipsAsync(dtId);

                await foreach (IncomingRelationship incomingRel in incomingRels)
                {
                    await client.DeleteRelationshipAsync(incomingRel.SourceId, incomingRel.RelationshipId).ConfigureAwait(false);
                    Console.WriteLine($"Deleted incoming relationship {incomingRel.RelationshipId} from {dtId}");
                }
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving or deleting incoming relationships for {dtId} due to {ex.Message}");
            }
        }
        // </DeleteTwin>

    }
}

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.

Configurare il progetto

Completare quindi i passaggi seguenti per configurare il codice del progetto:

  1. Aggiungere il file Room.json scaricato in precedenza al progetto e sostituire il segnaposto <path-to> nel codice per indicare al programma dove trovarlo.

  2. Sostituire il segnaposto <your-instance-hostname> con il nome host dell'istanza di Gemelli digitali di Azure.

  3. Aggiungere due dipendenze al progetto che sono necessarie per l'uso con Gemelli digitali di Azure. La prima è il pacchetto per Azure Digital Twins SDK per .NET mentre la seconda fornisce gli strumenti che consentono di eseguire l'autenticazione in Azure.

    dotnet add package Azure.DigitalTwins.Core
    dotnet add package Azure.Identity
    

È anche necessario configurare le credenziali locali se si desidera eseguire direttamente l'esempio. La sezione successiva illustra questa procedura.

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.

Eseguire l'esempio

Dopo aver completato l'installazione, è possibile eseguire il progetto di codice di esempio.

Ecco l'output della console del programma precedente:

Screenshot dell'output della console che mostra che il gemello viene creato, aggiornato ed eliminato.

Passaggi successivi

Informazioni su come creare e gestire relazioni tra gemelli digitali: