Hantera ett diagram över digitala tvillingar med hjälp av relationer
Kärnan i Azure Digital Twins är tvillingdiagrammet som representerar hela din miljö. Tvillingdiagrammet består av enskilda digitala tvillingar som är anslutna via relationer. Den här artikeln fokuserar på att hantera relationer och grafen som helhet. information om hur du arbetar med enskilda digitala tvillingar finns i Hantera digitala tvillingar.
När du har en fungerande Azure Digital Twins-instans och har konfigurerat autentiseringskod i klientappen kan du skapa, ändra och ta bort digitala tvillingar och deras relationer i en Azure Digital Twins-instans.
Förutsättningar
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.
Utvecklargränssnitt
Den här artikeln beskriver hur du slutför olika hanteringsåtgärder med hjälp av .NET (C#) SDK. Du kan också skapa samma hanteringsanrop med de andra språk-SDK:erna som beskrivs i Azure Digital Twins-API:er och SDK:er.
Andra utvecklargränssnitt som kan användas för att slutföra dessa åtgärder är:
Visualisering
Azure Digital Twins Explorer är ett visuellt verktyg för att utforska data i ditt Azure Digital Twins-diagram. Du kan använda utforskaren för att visa, fråga och redigera dina modeller, tvillingar och relationer.
Mer information om Azure Digital Twins Explorer-verktyget finns i Azure Digital Twins Explorer. Detaljerade anvisningar om hur du använder dess funktioner finns i Använda Azure Digital Twins Explorer.
Så här ser visualiseringen ut:
Skapa relationer
Relationer beskriver hur olika digitala tvillingar är anslutna till varandra, vilket utgör grunden för tvillingdiagrammet.
De typer av relationer som kan skapas från en (käll)tvilling till en annan (mål)-tvilling definieras som en del av källtvillingens DTDL-modell. Du kan skapa en instans av en relation med hjälp av SDK-anropet CreateOrReplaceRelationshipAsync()
med tvillingar och relationsinformation som följer DTDL-definitionen.
Om du vill skapa en relation måste du ange:
- Källtvillingens ID (
srcId
i kodexemplet nedan): ID:t för tvillingen där relationen kommer. - Måltvillingens ID (
targetId
i kodexemplet nedan): ID:t för tvillingen där relationen kommer. - Ett relationsnamn (
relName
i kodexemplet nedan): Den allmänna typen av relation, ungefär som innehåller. - Ett relations-ID (
relId
i kodexemplet nedan): Det specifika namnet på den här relationen, ungefär som Relation1.
Relations-ID:t måste vara unikt inom den angivna källtvillingen. Den behöver inte vara globalt unik. För tvillingen Foo måste till exempel varje specifikt relations-ID vara unikt. En annan tvillingstapel kan dock ha en utgående relation som matchar samma ID för en Foo-relation.
Följande kodexempel visar hur du skapar en relation i din Azure Digital Twins-instans. Den använder SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.
private async static Task CustomMethod_CreateRelationshipAsync(DigitalTwinsClient client, string srcId, string targetId, string relName, IDictionary<string,object> inputProperties)
{
var relationship = new BasicRelationship
{
TargetId = targetId,
Name = relName,
Properties = inputProperties
};
try
{
string relId = $"{srcId}-{relName}->{targetId}";
await client.CreateOrReplaceRelationshipAsync<BasicRelationship>(srcId, relId, relationship);
Console.WriteLine($"Created {relName} relationship successfully. Relationship ID is {relId}.");
}
catch (RequestFailedException rex)
{
Console.WriteLine($"Create relationship error: {rex.Status}:{rex.Message}");
}
}
Den här anpassade funktionen kan nu anropas för att skapa en contains-relation på följande sätt:
await CustomMethod_CreateRelationshipAsync(client, srcId, targetId, "contains", properties);
Om du vill skapa flera relationer kan du upprepa anrop till samma metod och skicka olika relationstyper till argumentet.
Mer information om hjälpklassen BasicRelationship
finns i Azure Digital Twins API:er och SDK:er.
Skapa flera relationer mellan tvillingar
Relationer kan klassificeras som antingen:
- Utgående relationer: Relationer som tillhör den här tvillingen som pekar utåt för att ansluta den till andra tvillingar. Metoden
GetRelationshipsAsync()
används för att hämta utgående relationer för en tvilling. - Inkommande relationer: Relationer som tillhör andra tvillingar som pekar mot den här tvillingen för att skapa en "inkommande" länk. Metoden
GetIncomingRelationshipsAsync()
används för att hämta inkommande relationer för en tvilling.
Det finns ingen begränsning för antalet relationer som du kan ha mellan två tvillingar – du kan ha så många relationer mellan tvillingar som du vill.
Det innebär att du kan uttrycka flera olika typer av relationer mellan två tvillingar samtidigt. Tvilling A kan till exempel ha både en lagrad relation och en tillverkad relation med Tvilling B.
Du kan till och med skapa flera instanser av samma typ av relation mellan samma två tvillingar, om du vill. I det här exemplet kan Tvilling A ha två olika lagrade relationer med Tvilling B, så länge relationerna har olika relations-ID:n.
Kommentar
DTDL-attributen minMultiplicity
för och maxMultiplicity
för relationer stöds för närvarande inte i Azure Digital Twins – även om de definieras som en del av en modell tillämpas de inte av tjänsten. Mer information finns i Tjänstspecifika DTDL-anteckningar.
Skapa relationer i grupp med API:et Importera jobb
Du kan använda API:et Importera jobb för att skapa många relationer samtidigt i ett enda API-anrop. Den här metoden kräver användning av Azure Blob Storage, samt skrivbehörigheter i din Azure Digital Twins-instans för relationer och massjobb.
Dricks
MED API:et Importera jobb kan även modeller och tvillingar importeras i samma anrop för att skapa alla delar av ett diagram samtidigt. Mer information om den här processen finns i Ladda upp modeller, tvillingar och relationer i bulk med API:et Importera jobb.
Om du vill importera relationer i grupp måste du strukturera dina relationer (och andra resurser som ingår i massimportjobbet) som en NDJSON-fil . Avsnittet Relationships
kommer efter avsnittet Twins
, vilket gör det till det sista grafdataavsnittet i filen. Relationer som definierats i filen kan referera till tvillingar som antingen definieras i den här filen eller som redan finns i instansen, och de kan också inkludera initiering av alla egenskaper som relationerna har.
Du kan visa en exempelimportfil och ett exempelprojekt för att skapa dessa filer i introduktionen för API:et Importera jobb.
Därefter måste filen laddas upp till en tilläggsblob i Azure Blob Storage. Anvisningar om hur du skapar en Azure Storage-container finns i Skapa en container. Ladda sedan upp filen med den uppladdningsmetod du föredrar (vissa alternativ är Kommandot AzCopy, Azure CLI eller Azure-portalen).
När NDJSON-filen har laddats upp till containern hämtar du dess URL i blobcontainern. Du använder det här värdet senare i brödtexten i API-anropet för massimport.
Här är en skärmbild som visar URL-värdet för en blobfil i Azure-portalen:
Sedan kan filen användas i ett API-anrop för importjobb. Du anger bloblagrings-URL:en för indatafilen samt en ny bloblagrings-URL för att ange var du vill att utdataloggen ska lagras när den skapas av tjänsten.
Lista relationer
Lista egenskaper för en enskild relation
Du kan alltid deserialisera relationsdata till valfri typ. För grundläggande åtkomst till en relation använder du typen BasicRelationship
. Hjälpklassen BasicRelationship
ger dig också åtkomst till egenskaper som definierats för relationen via en IDictionary<string, object>
. Om du vill visa en lista över egenskaper kan du använda:
public async Task ListRelationshipProperties(DigitalTwinsClient client, string twinId, string relId, BasicDigitalTwin twin)
{
var res = await client.GetRelationshipAsync<BasicRelationship>(twinId, relId);
BasicRelationship rel = res.Value;
Console.WriteLine($"Relationship Name: {rel.Name}");
foreach (string prop in rel.Properties.Keys)
{
if (twin.Contents.TryGetValue(prop, out object value))
{
Console.WriteLine($"Property '{prop}': {value}");
}
}
}
Lista utgående relationer från en digital tvilling
Om du vill komma åt listan över utgående relationer för en viss tvilling i diagrammet kan du använda metoden GetRelationships()
så här:
AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);
Den här metoden returnerar en Azure.Pageable<T>
eller Azure.AsyncPageable<T>
, beroende på om du använder den synkrona eller asynkrona versionen av anropet.
Här är ett exempel som hämtar en lista över relationer. Den använder SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.
private static async Task<List<BasicRelationship>> CustomMethod_FindOutgoingRelationshipsAsync(DigitalTwinsClient client, string dtId)
{
// Find the relationships for the twin
try
{
// GetRelationshipsAsync will throw if an error occurs
AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);
var results = new List<BasicRelationship>();
await foreach (BasicRelationship rel in rels)
{
results.Add(rel);
Console.WriteLine($"Found relationship: {rel.Id}");
//Print its properties
Console.WriteLine($"Relationship properties:");
foreach(KeyValuePair<string, object> property in rel.Properties)
{
Console.WriteLine("{0} = {1}", property.Key, property.Value);
}
}
return results;
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving relationships for {dtId} due to {ex.Message}");
return null;
}
}
Du kan nu anropa den här anpassade metoden för att se tvillingarnas utgående relationer så här:
await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);
Du kan använda de hämtade relationerna för att navigera till andra tvillingar i diagrammet genom att läsa target
fältet från relationen som returneras och använda det som ID för nästa anrop till GetDigitalTwin()
.
Lista inkommande relationer till en digital tvilling
Azure Digital Twins har också ett SDK-anrop för att hitta alla inkommande relationer till en viss tvilling. Denna SDK är ofta användbar för omvänd navigering eller när du tar bort en tvilling.
Kommentar
IncomingRelationship
anrop returnerar inte hela brödtexten i relationen. Mer information om klassen finns i referensdokumentationen IncomingRelationship
.
Kodexemplet i föregående avsnitt fokuserade på att hitta utgående relationer från en tvilling. Följande exempel är strukturerat på liknande sätt, men hittar inkommande relationer till tvillingen i stället. I det här exemplet används även SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.
private static async Task<List<IncomingRelationship>> CustomMethod_FindIncomingRelationshipsAsync(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);
var results = new List<IncomingRelationship>();
await foreach (IncomingRelationship incomingRel in incomingRels)
{
results.Add(incomingRel);
Console.WriteLine($"Found incoming relationship: {incomingRel.RelationshipId}");
//Print its properties
Response<BasicRelationship> relResponse = await client.GetRelationshipAsync<BasicRelationship>(incomingRel.SourceId, incomingRel.RelationshipId);
BasicRelationship rel = relResponse.Value;
Console.WriteLine($"Relationship properties:");
foreach(KeyValuePair<string, object> property in rel.Properties)
{
Console.WriteLine("{0} = {1}", property.Key, property.Value);
}
}
return results;
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving incoming relationships for {dtId} due to {ex.Message}");
return null;
}
}
Du kan nu anropa den här anpassade metoden för att se tvillingarnas inkommande relationer så här:
await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);
Visa en lista över alla tvillingegenskaper och relationer
Med hjälp av ovanstående metoder för att lista utgående och inkommande relationer till en tvilling kan du skapa en metod som skriver ut fullständig tvillinginformation, inklusive tvillingens egenskaper och båda typerna av relationer. Här är ett exempel på en anpassad metod som visar hur du kombinerar ovanstående anpassade metoder för detta ändamål.
private static async Task CustomMethod_FetchAndPrintTwinAsync(string twin_Id, DigitalTwinsClient client)
{
Response<BasicDigitalTwin> res = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twin_Id);
await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);
await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);
return;
}
Du kan nu anropa den här anpassade funktionen så här:
await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
Uppdatera relationer
Relationer uppdateras med hjälp av UpdateRelationship
metoden .
Kommentar
Den här metoden är till för att uppdatera egenskaperna för en relation. Om du behöver ändra källtvillingen eller måltvillingen för relationen måste du ta bort relationen och återskapa en med hjälp av de nya tvillingarna.
De obligatoriska parametrarna för klientanropet är:
- ID för källtvillingen (tvillingen där relationen kommer).
- ID för relationen som ska uppdateras.
- Ett JSON Patch-dokument som innehåller de egenskaper och nya värden som du vill uppdatera.
Här är ett exempelkodfragment som visar hur du använder den här metoden. I det här exemplet används SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.
private async static Task CustomMethod_UpdateRelationshipAsync(DigitalTwinsClient client, string srcId, string relId, Azure.JsonPatchDocument updateDocument)
{
try
{
await client.UpdateRelationshipAsync(srcId, relId, updateDocument);
Console.WriteLine($"Successfully updated {relId}");
}
catch (RequestFailedException rex)
{
Console.WriteLine($"Update relationship error: {rex.Status}:{rex.Message}");
}
}
Här är ett exempel på ett anrop till den här anpassade metoden som skickar in ett JSON Patch-dokument med information om att uppdatera en egenskap.
var updatePropertyPatch = new JsonPatchDocument();
updatePropertyPatch.AppendAdd("/ownershipUser", "ownershipUser NEW value");
await CustomMethod_UpdateRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}", updatePropertyPatch);
Ta bort relationer
Den första parametern anger källtvillingen (tvillingen där relationen kommer). Den andra parametern är relations-ID:t. Du behöver både tvilling-ID:t och relations-ID:t eftersom relations-ID:t bara är unika inom omfånget för en tvilling.
Här är exempelkoden som visar hur du använder den här metoden. I det här exemplet används SDK-anropet (markerat) i en anpassad metod som kan visas i kontexten för ett större program.
private static async Task CustomMethod_DeleteRelationshipAsync(DigitalTwinsClient client, string srcId, string relId)
{
try
{
Response response = await client.DeleteRelationshipAsync(srcId, relId);
await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
Console.WriteLine("Deleted relationship successfully");
}
catch (RequestFailedException e)
{
Console.WriteLine($"Error {e.ErrorCode}");
}
}
Du kan nu anropa den här anpassade metoden för att ta bort en relation som den här:
await CustomMethod_DeleteRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}");
Kommentar
Om du vill ta bort alla modeller, tvillingar och relationer i en instans samtidigt använder du API:et Ta bort jobb.
Skapa flera grafelement samtidigt
I det här avsnittet beskrivs strategier för att skapa ett diagram med flera element samtidigt, i stället för att använda enskilda API-anrop för att ladda upp modeller, tvillingar och relationer för att ladda upp dem en i taget.
Ladda upp modeller, tvillingar och relationer i grupp med API:et Importera jobb
Du kan använda API:et Importera jobb för att ladda upp flera modeller, tvillingar och relationer till din instans i ett enda API-anrop, vilket effektivt skapar grafen samtidigt. Den här metoden kräver användning av Azure Blob Storage, samt skrivbehörigheter i din Azure Digital Twins-instans för grafelement (modeller, tvillingar och relationer) och massjobb.
Om du vill importera resurser i grupp börjar du med att skapa en NDJSON-fil som innehåller information om dina resurser. Filen börjar med ett Header
avsnitt följt av de valfria avsnitten Models
, Twins
och Relationships
. Du behöver inte inkludera alla tre typerna av grafdata i filen, men alla avsnitt som finns måste följa den ordningen. Tvillingar som definierats i filen kan referera till modeller som antingen definieras i den här filen eller som redan finns i instansen, och de kan också inkludera initiering av tvillingens egenskaper. Relationer som definierats i filen kan referera till tvillingar som antingen definieras i den här filen eller som redan finns i instansen, och de kan också inkludera initiering av relationsegenskaper.
Du kan visa en exempelimportfil och ett exempelprojekt för att skapa dessa filer i introduktionen för API:et Importera jobb.
Därefter måste filen laddas upp till en tilläggsblob i Azure Blob Storage. Anvisningar om hur du skapar en Azure Storage-container finns i Skapa en container. Ladda sedan upp filen med den uppladdningsmetod du föredrar (vissa alternativ är Kommandot AzCopy, Azure CLI eller Azure-portalen).
När NDJSON-filen har laddats upp till containern hämtar du dess URL i blobcontainern. Du använder det här värdet senare i brödtexten i API-anropet för massimport.
Här är en skärmbild som visar URL-värdet för en blobfil i Azure-portalen:
Sedan kan filen användas i ett API-anrop för importjobb. Du anger bloblagrings-URL:en för indatafilen samt en ny bloblagrings-URL för att ange var du vill att utdataloggen ska lagras när den skapas av tjänsten.
Importera graf med Azure Digital Twins Explorer
Azure Digital Twins Explorer är ett visuellt verktyg för att visa och interagera med tvillingdiagrammet. Den innehåller en funktion för att importera en graffil i JSON- eller Excel-format som kan innehålla flera modeller, tvillingar och relationer.
Detaljerad information om hur du använder den här funktionen finns i Import graph i dokumentationen för Azure Digital Twins Explorer.
Skapa tvillingar och relationer från en CSV-fil
Ibland kan du behöva skapa tvillinghierarkier av data som lagras i en annan databas, eller i ett kalkylblad eller en CSV-fil. Det här avsnittet visar hur du läser data från en CSV-fil och skapar ett tvillingdiagram av den.
Tänk på följande datatabell som beskriver en uppsättning digitala tvillingar och relationer. Modellerna som refereras i den här filen måste redan finnas i Azure Digital Twins-instansen.
Model ID | Tvilling-ID (måste vara unikt) | Relationsnamn | Måltvilling-ID | Dubbla init-data |
---|---|---|---|---|
dtmi:example:Floor; 1 | Våning 1 | innehåller | Rum 1 | |
dtmi:example:Floor; 1 | Golv 0 | innehåller | Rum0 | |
dtmi:example:Room; 1 | Rum 1 | {"Temperatur": 80} | ||
dtmi:example:Room; 1 | Rum0 | {"Temperatur": 70} |
Ett sätt att hämta dessa data till Azure Digital Twins är att konvertera tabellen till en CSV-fil. När tabellen har konverterats kan kod skrivas för att tolka filen till kommandon för att skapa tvillingar och relationer. Följande kodexempel visar hur du läser data från CSV-filen och skapar ett tvillingdiagram i Azure Digital Twins.
I koden nedan kallas CSV-filen data.csv och det finns en platshållare som representerar värdnamnet för din Azure Digital Twins-instans. Exemplet använder också flera paket som du kan lägga till i projektet för att hjälpa till med den här processen.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Azure;
using Azure.DigitalTwins.Core;
using Azure.Identity;
namespace creating_twin_graph_from_csv
{
class Program
{
static async Task Main(string[] args)
{
var relationshipRecordList = new List<BasicRelationship>();
var twinList = new List<BasicDigitalTwin>();
List<List<string>> data = ReadData();
DigitalTwinsClient client = CreateDtClient();
// Interpret the CSV file data, by each row
foreach (List<string> row in data)
{
string modelID = row.Count > 0 ? row[0].Trim() : null;
string srcID = row.Count > 1 ? row[1].Trim() : null;
string relName = row.Count > 2 ? row[2].Trim() : null;
string targetID = row.Count > 3 ? row[3].Trim() : null;
string initProperties = row.Count > 4 ? row[4].Trim() : null;
Console.WriteLine($"ModelID: {modelID}, TwinID: {srcID}, RelName: {relName}, TargetID: {targetID}, InitData: {initProperties}");
var props = new Dictionary<string, object>();
// Parse properties into dictionary (left out for compactness)
// ...
// Null check for source and target IDs
if (!string.IsNullOrWhiteSpace(srcID) && !string.IsNullOrWhiteSpace(targetID) && !string.IsNullOrWhiteSpace(relName))
{
relationshipRecordList.Add(
new BasicRelationship
{
SourceId = srcID,
TargetId = targetID,
Name = relName,
});
}
if (!string.IsNullOrWhiteSpace(srcID) && !string.IsNullOrWhiteSpace(modelID))
twinList.Add(
new BasicDigitalTwin
{
Id = srcID,
Metadata = { ModelId = modelID },
Contents = props,
});
}
// Create digital twins
foreach (BasicDigitalTwin twin in twinList)
{
try
{
await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twin.Id, twin);
Console.WriteLine("Twin is created");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Error {ex.Status}: {ex.Message}");
}
}
// Create relationships between the twins
foreach (BasicRelationship rec in relationshipRecordList)
{
string relId = $"{rec.SourceId}-{rec.Name}->{rec.TargetId}";
try
{
await client.CreateOrReplaceRelationshipAsync<BasicRelationship>(rec.SourceId, relId, rec);
Console.WriteLine($"Relationship {relId} is created");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Error creating relationship {relId}. {ex.Status}: {ex.Message}");
}
}
}
// Method to ingest data from the CSV file
public static List<List<string>> ReadData()
{
string path = "<path-to>/data.csv";
string[] lines = System.IO.File.ReadAllLines(path);
var data = new List<List<string>>();
int count = 0;
foreach (string line in lines)
{
if (count++ == 0)
continue;
var cols = new List<string>();
string[] columns = line.Split(',');
foreach (string column in columns)
{
cols.Add(column);
}
data.Add(cols);
}
return data;
}
// Method to create the digital twins client
private static DigitalTwinsClient CreateDtClient()
{
string adtInstanceUrl = "https://<your-instance-hostname>";
var credentials = new DefaultAzureCredential();
return new DigitalTwinsClient(new Uri(adtInstanceUrl), credentials);
}
}
}
Exempel på runnable twin graph
Följande runnable-kodfragment använder relationsåtgärderna från den här artikeln för att skapa ett tvillingdiagram av digitala tvillingar och relationer.
Konfigurera exempelprojektfiler
Kodfragmentet använder två exempelmodelldefinitioner, Room.json och Floor.json. Om du vill ladda ned modellfilerna så att du kan använda dem i koden använder du dessa länkar för att gå direkt till filerna i GitHub. Högerklicka sedan var som helst på skärmen, välj Spara som i webbläsarens högerklicka-meny och använd fönstret Spara som för att spara filerna som Room.json och Floor.json.
Skapa sedan ett nytt konsolappprojekt i Visual Studio eller valfri redigerare.
Kopiera sedan följande kod för det körbara exemplet till projektet:
using System;
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
using Azure;
using Azure.DigitalTwins.Core;
using Azure.Identity;
namespace DigitalTwins_Samples
{
public class GraphOperationsSample
{
public static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
// Create the Azure Digital Twins client for API calls
DigitalTwinsClient client = createDtClient();
Console.WriteLine($"Service client created – ready to go");
Console.WriteLine();
// Upload models
Console.WriteLine($"Upload models");
Console.WriteLine();
string dtdl = File.ReadAllText("<path-to>/Room.json");
string dtdl1 = File.ReadAllText("<path-to>/Floor.json");
var models = new List<string>
{
dtdl,
dtdl1,
};
// Upload the models to the service
await client.CreateModelsAsync(models);
// Create new (Floor) digital twin
var floorTwin = new BasicDigitalTwin();
string srcId = "myFloorID";
floorTwin.Metadata.ModelId = "dtmi:example:Floor;1";
// Floor twins have no properties, so nothing to initialize
// Create the twin
await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(srcId, floorTwin);
Console.WriteLine("Twin created successfully");
// Create second (Room) digital twin
var roomTwin = new BasicDigitalTwin();
string targetId = "myRoomID";
roomTwin.Metadata.ModelId = "dtmi:example:Room;1";
// Initialize properties
roomTwin.Contents.Add("Temperature", 35.0);
roomTwin.Contents.Add("Humidity", 55.0);
// Create the twin
await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(targetId, roomTwin);
// Create relationship between them
var properties = new Dictionary<string, object>
{
{ "ownershipUser", "ownershipUser original value" },
};
// <UseCreateRelationship>
await CustomMethod_CreateRelationshipAsync(client, srcId, targetId, "contains", properties);
// </UseCreateRelationship>
Console.WriteLine();
// Update relationship's Name property
// <UseUpdateRelationship>
var updatePropertyPatch = new JsonPatchDocument();
updatePropertyPatch.AppendAdd("/ownershipUser", "ownershipUser NEW value");
await CustomMethod_UpdateRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}", updatePropertyPatch);
// </UseUpdateRelationship>
Console.WriteLine();
//Print twins and their relationships
Console.WriteLine("--- Printing details:");
Console.WriteLine($"Outgoing relationships from source twin, {srcId}:");
// <UseFetchAndPrint>
await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
// </UseFetchAndPrint>
Console.WriteLine();
Console.WriteLine($"Incoming relationships to target twin, {targetId}:");
await CustomMethod_FetchAndPrintTwinAsync(targetId, client);
Console.WriteLine("--------");
Console.WriteLine();
// Delete the relationship
// <UseDeleteRelationship>
await CustomMethod_DeleteRelationshipAsync(client, srcId, $"{srcId}-contains->{targetId}");
// </UseDeleteRelationship>
Console.WriteLine();
// Print twins and their relationships again
Console.WriteLine("--- Printing details (after relationship deletion):");
Console.WriteLine("Outgoing relationships from source twin:");
await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
Console.WriteLine();
Console.WriteLine("Incoming relationships to target twin:");
await CustomMethod_FetchAndPrintTwinAsync(targetId, client);
Console.WriteLine("--------");
Console.WriteLine();
}
private static DigitalTwinsClient createDtClient()
{
string adtInstanceUrl = "https://<your-instance-hostname>";
var credentials = new DefaultAzureCredential();
var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credentials);
return client;
}
// <CreateRelationshipMethod>
private async static Task CustomMethod_CreateRelationshipAsync(DigitalTwinsClient client, string srcId, string targetId, string relName, IDictionary<string,object> inputProperties)
{
var relationship = new BasicRelationship
{
TargetId = targetId,
Name = relName,
Properties = inputProperties
};
try
{
string relId = $"{srcId}-{relName}->{targetId}";
await client.CreateOrReplaceRelationshipAsync<BasicRelationship>(srcId, relId, relationship);
Console.WriteLine($"Created {relName} relationship successfully. Relationship ID is {relId}.");
}
catch (RequestFailedException rex)
{
Console.WriteLine($"Create relationship error: {rex.Status}:{rex.Message}");
}
}
// </CreateRelationshipMethod>
// <UpdateRelationshipMethod>
private async static Task CustomMethod_UpdateRelationshipAsync(DigitalTwinsClient client, string srcId, string relId, Azure.JsonPatchDocument updateDocument)
{
try
{
await client.UpdateRelationshipAsync(srcId, relId, updateDocument);
Console.WriteLine($"Successfully updated {relId}");
}
catch (RequestFailedException rex)
{
Console.WriteLine($"Update relationship error: {rex.Status}:{rex.Message}");
}
}
// </UpdateRelationshipMethod>
// <FetchAndPrintMethod>
private static async Task CustomMethod_FetchAndPrintTwinAsync(string twin_Id, DigitalTwinsClient client)
{
Response<BasicDigitalTwin> res = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twin_Id);
// <UseFindOutgoingRelationships>
await CustomMethod_FindOutgoingRelationshipsAsync(client, twin_Id);
// </UseFindOutgoingRelationships>
// <UseFindIncomingRelationships>
await CustomMethod_FindIncomingRelationshipsAsync(client, twin_Id);
// </UseFindIncomingRelationships>
return;
}
// </FetchAndPrintMethod>
// <FindOutgoingRelationshipsMethod>
private static async Task<List<BasicRelationship>> CustomMethod_FindOutgoingRelationshipsAsync(DigitalTwinsClient client, string dtId)
{
// Find the relationships for the twin
try
{
// GetRelationshipsAsync will throw if an error occurs
// <GetRelationshipsCall>
AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);
// </GetRelationshipsCall>
var results = new List<BasicRelationship>();
await foreach (BasicRelationship rel in rels)
{
results.Add(rel);
Console.WriteLine($"Found relationship: {rel.Id}");
//Print its properties
Console.WriteLine($"Relationship properties:");
foreach(KeyValuePair<string, object> property in rel.Properties)
{
Console.WriteLine("{0} = {1}", property.Key, property.Value);
}
}
return results;
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving relationships for {dtId} due to {ex.Message}");
return null;
}
}
// </FindOutgoingRelationshipsMethod>
// <FindIncomingRelationshipsMethod>
private static async Task<List<IncomingRelationship>> CustomMethod_FindIncomingRelationshipsAsync(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);
var results = new List<IncomingRelationship>();
await foreach (IncomingRelationship incomingRel in incomingRels)
{
results.Add(incomingRel);
Console.WriteLine($"Found incoming relationship: {incomingRel.RelationshipId}");
//Print its properties
Response<BasicRelationship> relResponse = await client.GetRelationshipAsync<BasicRelationship>(incomingRel.SourceId, incomingRel.RelationshipId);
BasicRelationship rel = relResponse.Value;
Console.WriteLine($"Relationship properties:");
foreach(KeyValuePair<string, object> property in rel.Properties)
{
Console.WriteLine("{0} = {1}", property.Key, property.Value);
}
}
return results;
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving incoming relationships for {dtId} due to {ex.Message}");
return null;
}
}
// </FindIncomingRelationshipsMethod>
// <DeleteRelationshipMethod>
private static async Task CustomMethod_DeleteRelationshipAsync(DigitalTwinsClient client, string srcId, string relId)
{
try
{
Response response = await client.DeleteRelationshipAsync(srcId, relId);
await CustomMethod_FetchAndPrintTwinAsync(srcId, client);
Console.WriteLine("Deleted relationship successfully");
}
catch (RequestFailedException e)
{
Console.WriteLine($"Error {e.ErrorCode}");
}
}
// </DeleteRelationshipMethod>
}
}
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.
Konfigurera projekt
Slutför sedan följande steg för att konfigurera projektkoden:
Lägg till filerna Room.json och Floor.json som du laddade ned tidigare i projektet och ersätt
<path-to>
platshållarna i koden för att berätta för programmet var de finns.Ersätt platshållaren
<your-instance-hostname>
med azure Digital Twins-instansens värdnamn.Lägg 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 och 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
Du måste också konfigurera lokala autentiseringsuppgifter om du vill köra exemplet direkt. Nästa avsnitt går igenom den här processen.
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 DefaultAzureCredential
sö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.
Kör exemplet
Nu när du har slutfört installationen kan du köra exempelkodprojektet.
Här är programmets konsolutdata:
Dricks
Tvillingdiagrammet är ett begrepp för att skapa relationer mellan tvillingar. Om du vill visa den visuella representationen av tvillingdiagrammet kan du läsa avsnittet Visualisering i den här artikeln.
Nästa steg
Lär dig mer om att köra frågor mot ett Azure Digital Twins-tvillingdiagram: