Självstudie: Kodning med Azure Digital Twins SDK

Utvecklare som arbetar med Azure Digital Twins skriver ofta klientprogram för att interagera med sin instans av Azure Digital Twins-tjänsten. Den här utvecklarfokuserade självstudien ger en introduktion till programmering mot Azure Digital Twins-tjänsten med hjälp av Azure Digital Twins SDK för .NET (C#). Den vägleder dig genom att skriva en C#-konsolklientapp steg för steg, från början.

  • Konfigurera projekt
  • Kom igång med projektkod
  • Fullständigt kodexempel
  • Rensa resurser
  • Nästa steg

Förutsättningar

Den här Azure Digital Twins-självstudien använder kommandoraden för installation och projektarbete. Därför kan du använda valfri kodredigerare för att gå igenom övningarna.

Vad du behöver börja:

  • Valfri kodredigerare
  • .NET Core 3.1 på utvecklingsdatorn. Du kan ladda ned den här versionen av .NET Core SDK för flera plattformar från Ladda ned .NET Core 3.1.

Förbereda en Azure Digital Twins-instans

För att arbeta med Azure Digital Twins i den här artikeln behöver du en Azure Digital Twins-instans och de behörigheter som krävs för att använda den. Om du redan har konfigurerat en Azure Digital Twins-instans kan du använda den instansen och gå vidare till nästa avsnitt. Annars följer du anvisningarna i Konfigurera en instans och autentisering. Anvisningarna innehåller information som hjälper dig att kontrollera att du har slutfört varje steg.

När du har konfigurerat instansen antecknar du instansens värdnamn. Du hittar värdnamnet i Azure-portalen.

Konfigurera lokala Azure-autentiseringsuppgifter

Det här exemplet använder DefaultAzureCredential (en del av biblioteket) för att autentisera Azure.Identity användare med Azure Digital Twins-instansen när du kör den på den lokala datorn. Mer information om olika sätt som en klientapp kan autentisera med Azure Digital Twins finns i Skriva kod för appautentisering.

Med DefaultAzureCredentialsöker exemplet efter autentiseringsuppgifter i din lokala miljö, till exempel en Azure-inloggning i ett lokalt Azure CLI eller i Visual Studio eller Visual Studio Code. Därför bör du logga in på Azure lokalt via någon av dessa mekanismer för att konfigurera autentiseringsuppgifter för exemplet.

Om du använder Visual Studio eller Visual Studio Code för att köra kodexempel kontrollerar du att du är inloggad i redigeringsprogrammet med samma Azure-autentiseringsuppgifter som du vill använda för att komma åt din Azure Digital Twins-instans. Om du använder ett lokalt CLI-fönster kör az login du kommandot för att logga in på ditt Azure-konto. När du sedan kör kodexemplet bör du autentiseras automatiskt.

Konfigurera projekt

När du är redo att gå med din Azure Digital Twins-instans börjar du konfigurera klientappprojektet.

Öppna ett konsolfönster på datorn och skapa en tom projektkatalog där du vill lagra ditt arbete under den här självstudien. Ge katalogen namnet vad du vill (till exempel DigitalTwinsCodeTutorial).

Navigera till den nya katalogen.

När du är i projektkatalogen skapar du ett tomt .NET-konsolappprojekt. I kommandofönstret kan du köra följande kommando för att skapa ett minimalt C#-projekt för konsolen:

dotnet new console

Det här kommandot skapar flera filer i katalogen, inklusive en som heter Program.cs där du skriver det mesta av koden.

Håll kommandofönstret öppet eftersom du fortsätter att använda det i självstudien.

Lägg sedan till två beroenden i projektet som behövs för att arbeta med Azure Digital Twins. Den första är paketet för Azure Digital Twins SDK för .NET, det andra innehåller verktyg för att hjälpa till med autentisering mot Azure.

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

Kom igång med projektkod

I det här avsnittet börjar du skriva koden för ditt nya appprojekt för att arbeta med Azure Digital Twins. De åtgärder som omfattas är:

  • Autentisera mot tjänsten
  • Ladda upp en modell
  • Fånga upp fel
  • Skapa digitala tvillingar
  • Skapa relationer
  • Köra frågor mot digitala tvillingar

Det finns också ett avsnitt som visar den fullständiga koden i slutet av självstudien. Du kan använda det här avsnittet som referens för att kontrollera programmet när du går.

Börja genom att öppna filen Program.cs i valfri kodredigerare. Du ser en minimal kodmall som ser ut ungefär så här:

Screenshot of a snippet of sample code in a code editor.

Lägg först till några using rader överst i koden för att hämta nödvändiga beroenden.

using Azure.DigitalTwins.Core;
using Azure.Identity;

Sedan lägger du till kod i den här filen för att fylla i vissa funktioner.

Autentisera mot tjänsten

Det första din app behöver göra är att autentisera mot Azure Digital Twins-tjänsten. Sedan kan du skapa en tjänstklientklass för att få åtkomst till SDK-funktionerna.

För att autentisera behöver du värdnamnet för din Azure Digital Twins-instans.

I Program.cs klistrar du in följande kod under utskriftsraden "Hello, World!" i Main -metoden. Ange värdet adtInstanceUrl för till azure Digital Twins-instansens värdnamn.

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");

Spara filen.

Kör koden med det här kommandot i kommandofönstret:

dotnet run

Det här kommandot återställer beroendena vid första körningen och kör sedan programmet.

  • Om inget fel inträffar skrivs programmet ut: "Tjänstklienten har skapats – klar att gå".
  • Eftersom det ännu inte finns någon felhantering i det här projektet visas ett undantag som genereras av koden om det finns några problem.

Kommentar

Det finns för närvarande ett känt problem som påverkar omslutningsklassen DefaultAzureCredential som kan leda till ett fel vid autentisering. Om du stöter på det här problemet kan du prova att instansiera DefaultAzureCredential med följande valfria parameter för att lösa det: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });

Mer information om det här problemet finns i Kända problem med Azure Digital Twins.

Ladda upp en modell

Azure Digital Twins har inget inbyggt domänförråd. De typer av element i din miljö som du kan representera i Azure Digital Twins definieras av dig med hjälp av modeller. Modeller liknar klasser i objektorienterade programmeringsspråk. De tillhandahåller användardefinierade mallar som digitala tvillingar kan följa och instansiera senare. De är skrivna på ett JSON-liknande språk som heter Digital Twins Definition Language (DTDL).

Det första steget i att skapa en Azure Digital Twins-lösning är att definiera minst en modell i en DTDL-fil.

I katalogen där du skapade projektet skapar du en ny .json-fil med namnet SampleModel.json. Klistra in följande filtext:

{
  "@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"
}

Dricks

Om du använder Visual Studio för den här självstudien kanske du vill välja den nyskapade JSON-filen och ange egenskapen Kopiera till utdatakatalog i egenskapskontrollen till Kopiera om det är nyare eller Kopiera alltid. Detta gör att Visual Studio kan hitta JSON-filen med standardsökvägen när du kör programmet med F5 under resten av självstudien.

Dricks

Du kan kontrollera modelldokumenten för att kontrollera att DTDL är giltigt med hjälp av DTDLParser-biblioteket. Mer information om hur du använder det här biblioteket finns i Parsa och verifiera modeller.

Lägg sedan till lite mer kod i Program.cs för att ladda upp den modell som du har skapat till din Azure Digital Twins-instans.

Lägg först till några using instruktioner överst i filen:

using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
using Azure;

Förbered sedan att använda asynkrona metoder i C#-tjänstens SDK genom att ändra metodsignaturen Main så att den tillåter asynkron körning.

static async Task Main(string[] args)
{

Kommentar

Användning async är inte strikt obligatoriskt eftersom SDK:t även tillhandahåller synkrona versioner av alla anrop. Den här självstudien använder async.

Därefter kommer den första kodbiten som interagerar med Azure Digital Twins-tjänsten. Den här koden läser in DTDL-filen som du skapade från disken och laddar sedan upp den till din Azure Digital Twins-tjänstinstans.

Klistra in följande kod under auktoriseringskoden som du lade till tidigare.

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);

Kör programmet med det här kommandot i kommandofönstret:

dotnet run

"Ladda upp en modell" skrivs ut i utdata, vilket indikerar att den här koden har nåtts, men det finns inga utdata ännu för att ange om uppladdningen lyckades.

Om du vill lägga till en utskriftssats som visar alla modeller som har laddats upp till instansen lägger du till följande kod direkt efter föregående avsnitt:

// 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}");
}

Innan du kör programmet igen för att testa den här nya koden, kom ihåg att den senaste gången du körde programmet laddade du upp din modell redan. Azure Digital Twins låter dig inte ladda upp samma modell två gånger, så om du försöker ladda upp samma modell igen bör programmet utlösa ett undantag.

Med den här informationen i åtanke kör du programmet igen med det här kommandot i kommandofönstret:

dotnet run

Programmet bör utlösa ett undantag. När du försöker ladda upp en modell som redan har laddats upp returnerar tjänsten ett fel med "felaktig begäran" via REST-API:et. Därför utlöser Azure Digital Twins-klient-SDK i sin tur ett undantag för varje annan tjänstreturkod än lyckad.

I nästa avsnitt beskrivs undantag som detta och hur du hanterar dem i koden.

Fånga fel

Om du vill förhindra att programmet kraschar kan du lägga till undantagskod runt modellens uppladdningskod. Omslut det befintliga klientanropet await client.CreateModelsAsync(typeList) i en try/catch-hanterare, så här:

try
{
    await client.CreateModelsAsync(models);
    Console.WriteLine("Models uploaded to the instance:");
}
catch (RequestFailedException e)
{
    Console.WriteLine($"Upload model error: {e.Status}: {e.Message}");
}

Kör programmet igen med dotnet run i kommandofönstret. Du ser att du får tillbaka mer information om modelluppladdningsproblemet, inklusive en felkod som anger att ModelIdAlreadyExists.

Från och med nu omsluter självstudien alla anrop till tjänstmetoder i try/catch-hanterare.

Skapa digitala tvillingar

Nu när du har laddat upp en modell till Azure Digital Twins kan du använda den här modelldefinitionen för att skapa digitala tvillingar. Digitala tvillingar är instanser av en modell och representerar entiteterna i din företagsmiljö – till exempel sensorer på en servergrupp, rum i en byggnad eller lampor i en bil. Det här avsnittet skapar några digitala tvillingar baserat på den modell som du laddade upp tidigare.

Lägg till följande kod i slutet av Main metoden för att skapa och initiera tre digitala tvillingar baserat på den här modellen.

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}");
    }
}

Kör programmet med dotnet runi kommandofönstret. I utdata letar du efter de utskriftsmeddelanden som sampleTwin-0, sampleTwin-1 och sampleTwin-2 skapades.

Kör sedan programmet igen.

Observera att inget fel utlöses när tvillingarna skapas andra gången, även om tvillingarna redan finns efter den första körningen. Till skillnad från modellskapande är tvillingskapande på REST-nivå ett PUT-anrop med upsert-semantik . Med den här typen av REST-anrop innebär det att om det redan finns en tvilling ersätter ett försök att skapa samma tvilling igen bara den ursprungliga tvillingen. Inget fel utlöses.

Skapa relationer

Sedan kan du skapa relationer mellan tvillingarna som du har skapat för att ansluta dem till en tvillinggraf. Tvillingdiagram används för att representera hela din miljö.

Lägg till en ny statisk metod i Program klassen under Main metoden (koden har nu två metoder):

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}");
    }
}

Lägg sedan till följande kod i slutet av Main metoden för att anropa CreateRelationship metoden och använda koden som du just skrev:

// Connect the twins with relationships
await CreateRelationshipAsync(client, "sampleTwin-0", "sampleTwin-1");
await CreateRelationshipAsync(client, "sampleTwin-0", "sampleTwin-2");

Kör programmet med dotnet runi kommandofönstret. I utdata letar du efter utskriftsuttryck som säger att de två relationerna har skapats.

Med Azure Digital Twins kan du inte skapa en relation om det redan finns en annan relation med samma ID. Om du kör programmet flera gånger visas undantag vid skapandet av relationer. Den här koden fångar undantagen och ignorerar dem.

Lista relationer

Med nästa kod som du lägger till kan du se listan över relationer som du har skapat.

Lägg till följande nya metod till Program-klassen:

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}");
    }
}

Lägg sedan till följande kod i slutet av Main metoden för att anropa ListRelationships koden:

//List the relationships
await ListRelationshipsAsync(client, "sampleTwin-0");

Kör programmet med dotnet runi kommandofönstret. Du bör se en lista över alla relationer som du har skapat i en utdatasats som ser ut så här:

Screenshot of a console showing the program output, which results in a message that lists the twin relationships.

Fråga digitala tvillingar

En viktig funktion i Azure Digital Twins är möjligheten att enkelt och effektivt köra frågor mot tvillingdiagrammet för att besvara frågor om din miljö.

Det sista kodavsnittet som ska läggas till i den här självstudien kör en fråga mot Azure Digital Twins-instansen. Frågan som används i det här exemplet returnerar alla digitala tvillingar i instansen.

Lägg till den här using instruktionen JsonSerializer för att aktivera användning av klassen för att presentera information om digitala tvillingar:

using System.Text.Json;

Lägg sedan till följande kod i slutet av Main metoden:

// 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("---------------");
}

Kör programmet med dotnet runi kommandofönstret. Du bör se alla digitala tvillingar i den här instansen i utdata.

Kommentar

När du har gjort en ändring av data i diagrammet kan det finnas en svarstid på upp till 10 sekunder innan ändringarna återspeglas i frågor.

DigitalTwins-API:et återspeglar ändringar omedelbart, så om du behöver ett omedelbart svar använder du en API-begäran (DigitalTwins GetById) eller ett SDK-anrop (GetDigitalTwin) för att hämta tvillingdata i stället för en fråga.

Exempel på fullständig kod

Nu i självstudien har du en komplett klientapp som kan utföra grundläggande åtgärder mot Azure Digital Twins. Som referens visas den fullständiga koden för programmet i Program.cs nedan:

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>
    }
}

Rensa resurser

När du har slutfört den här självstudien kan du välja vilka resurser du vill ta bort, beroende på vad du vill göra härnäst.

  • Om du planerar att fortsätta till nästa självstudie kan den instans som används i den här självstudien återanvändas i nästa. Du kan behålla de Azure Digital Twins-resurser som du har konfigurerat här och hoppa över resten av det här avsnittet.
  • Om du vill fortsätta använda Azure Digital Twins-instansen från den här artikeln, men rensa alla dess modeller, tvillingar och relationer, kör du följande az dt job deletion CLI-kommando:

    az dt job deletion create -n <name-of-Azure-Digital-Twins-instance> -y
    

    Om du bara vill ta bort vissa av dessa element kan du använda kommandot az dt twin relationship delete, az dt twin delete och az dt model delete för att selektivt ta bort de element som du vill ta bort.

  • Om du inte behöver någon av de resurser som du skapade i den här självstudien kan du ta bort Azure Digital Twins-instansen och alla andra resurser från den här artikeln med kommandot az group delete CLI. Detta tar bort alla Azure-resurser i en resursgrupp samt själva resursgruppen.

    Viktigt!

    Att ta bort en resursgrupp kan inte ångras. Resursgruppen och alla resurser som ingår i den tas bort permanent. Var noga så att du inte tar bort fel resursgrupp eller resurser av misstag.

    Öppna Azure Cloud Shell eller ett lokalt CLI-fönster och kör följande kommando för att ta bort resursgruppen och allt den innehåller.

    az group delete --name <your-resource-group>
    

Du kanske också vill ta bort projektmappen från den lokala datorn.

Nästa steg

I den här självstudien skapade du ett .NET-konsolklientprogram från grunden. Du skrev kod för den här klientappen för att utföra de grundläggande åtgärderna på en Azure Digital Twins-instans.

Fortsätt till nästa självstudie för att utforska vad du kan göra med en sådan exempelklientapp: