共用方式為


教學課程:使用 Azure Digital Twins SDK 撰寫程式碼

使用 Azure Digital Twins 的開發人員通常會撰寫用戶端應用程式,與其 Azure Digital Twins 服務執行個體互動。 這項以開發人員為主的教學課程,會介紹使用適用於 .NET 的 Azure Digital Twins SDK (C#) (英文) 設計 Azure Digital Twins 服務的程式。 逐步引導您從頭開始撰寫 C# 主控台用戶端應用程式。

  • 設定專案
  • 開始使用專案程式碼
  • 完整的程式碼範例
  • 清除資源
  • 下一步

必要條件

本 Azure Digital Twins 教學課程使用命令列進行設定及專案工作。 因此,您可以使用任何程式碼編輯器來逐步完成練習。

開始前的準備:

  • 任何程式碼編輯器
  • 開發電腦上的 .NET Core 3.1。 您可以從下載 .NET Core 3.1 (英文) 下載此適用於多個平台的 .NET Core SDK 版本。

準備 Azure Digital Twins 執行個體

若要使用本文中的 Azure Digital Twins,您需要 Azure Digital Twins 實例和使用它所需的許可權。 如果您已經設定好 Azure Digital Twins 執行個體,您可以直接使用該執行個體,並跳至下一節。 否則,請依照設定執行個體和驗證中的指示進行。 這些指示包含的信息可協助您確認您已成功完成每個步驟。

設定執行個體之後,請記下執行個體的主機名稱。 您可以在 Azure 入口網站中找到主機名稱

設定本機 Azure 認證

這個範例會使用 DefaultAzureCredential (屬於 Azure.Identity 程式庫),在本機電腦上執行時,使用 Azure Digital Twins 執行個體來驗證使用者。 如需深入了解用戶端應用程式向 Azure Digital Twins 進行驗證的不同方式,請參閱撰寫應用程式驗證碼

使用 DefaultAzureCredential,該範例會搜尋本機環境中的認證,例如在本機 Azure CLI 中或在 Visual Studio 或 Visual Studio Code 中的 Azure 登入。 因此,您應該透過下列其中一種機制本機登入 Azure,以設定該範例的認證。

如果您使用 Visual Studio 或 Visual Studio Code 來執行程式碼範例,請確定使用要用來存取 Azure Digital Twins 執行個體的相同 Azure 認證來登入該編輯器。 如果您使用本機 CLI 視窗,請執行 az login 命令來登入您的 Azure 帳戶。 之後,當您執行程式碼範例時,應該會自動驗證。

設定專案

準備好使用您的 Azure Digital Twins 執行個體之後,請開始設定用戶端應用程式專案。

在您的電腦上開啟主控台視窗,建立儲存本教學課程工作的空白專案目錄。 將目錄命名為任何您想要的名稱 (例如 DigitalTwinsCodeTutorial)。

導覽到新目錄。

進入專案目錄後,建立空白的 .NET 主控台應用程式專案。 在命令視窗中執行下列命令,以建立主控台的基礎 C# 專案:

dotnet new console

此命令會在您的目錄中建立數個檔案,包括一個稱為 Program.cs ,您可以在其中撰寫大部分的程序代碼。

讓命令視窗保持開啟,因為您在整個教學課程中繼續使用。

接下來,將兩個相依性新增至您的專案,以搭配 Azure Digital Twins 使用。 第一個相依性是適用於 .NETAzure Digital Twins SDK 套件。 第二個相依性提供工具來協助對 Azure 進行驗證。

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

開始使用專案程式碼

在本節中,您會開始撰寫新應用程式項目的程序代碼,以使用 Azure Digital Twins。 涵蓋的動作包括:

  • 驗證服務
  • 上傳模型
  • 攔截錯誤
  • 建立數位分身
  • 建立關聯性
  • 查詢數位分身

本教學課程結束時,會另有一節顯示完整的程式碼。 您可以此區段作為參考,隨時檢查您的程式。

開始前,請使用任何程式碼編輯器開啟 Program.cs 檔案。 您會看到如下所示的最小程式代碼樣本:

程式碼編輯器中範例程式碼片段的螢幕擷取畫面。

首先,在程式碼頂端新增一些 using 行,以提取必要的相依性。

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

接下來,您會將程式代碼新增至此檔案,以填寫一些功能。

驗證服務

您的應用程式需要做的第一件事是針對 Azure Digital Twins 服務進行驗證。 接著,您就可以建立服務用戶端類別以存取 SDK 函式。

為了進行驗證,您需要 Azure Digital Twins 執行個體的主機名稱。

Program.cs 中,將 "Hello, World!" 列印行下方的下列程式碼貼在 Main 方法中。 將 adtInstanceUrl 的值設定為您的 Azure Digital Twins 執行個體主機名稱。

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

儲存檔案。

在命令視窗中,使用此命令執行程式碼:

dotnet run

此命令會在第一次執行時還原相依性,然後執行程式。

  • 如果沒有發生錯誤,程式會列印:「服務用戶端已建立 - 已準備就緒」。
  • 由於此專案中還沒有任何錯誤處理,如果發生任何問題,您會看到程式代碼擲回的例外狀況。

注意

目前有已知問題會影響 DefaultAzureCredential 包裝函式類別,這可能會導致在驗證時發生錯誤。 如果遇到此問題,您可以嘗試使用下列選擇性參數將 DefaultAzureCredential 具現化,以解決此問題:new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });

如需關於此問題的詳細資訊,請參閱 Azure Digital Twins 已知問題

上傳模型

Azure Digital Twins 沒有內建的網域詞彙。 您可以使用 模型 來定義環境中可在 Azure Digital Twins 中代表的項目類型。 模型類似物件導向程式設計語言中的類別,為數位分身提供日後可遵循並具現化的使用者定義範本。 以類似 JSON,稱為數位分身定義語言 (DTDL) 的語言所撰寫。

建立 Azure Digital Twins 解決方案的第一個步驟,是在 DTDL 檔案中至少定義一個模型。

在您建立專案的目錄中,建立新的 .json 檔案,名為 SampleModel.json。 貼入下列檔案主體:

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

提示

如果您使用 Visual Studio 進行本教學課程,您可能會想要選取新建立的 JSON 檔案,並將屬性偵測器中的 [複製到輸出目錄] 屬性設定[新增][複製永遠複製]。 當您在教學課程的其餘部分使用 F5 執行程式時,這個屬性值可讓 Visual Studio 尋找具有預設路徑的 JSON 檔案。

提示

您可以使用 DTDLParser 程式庫來檢查模型文件,以確定 DTDL 有效。 如需使用此程式庫的詳細資訊,請參閱剖析和驗證模型

接下來,將更多程式代碼新增至 Program.cs ,以將您建立的模型上傳至 Azure Digital Twins 實例。

首先,在檔案頂端新增一些 using 陳述式:

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

接下來,將 Main 方法簽章變更為允許非同步執行,準備使用 C# 服務 SDK 中的非同步方法。

static async Task Main(string[] args)
{

注意

不需要使用 async ,因為 SDK 也會提供所有呼叫的同步版本。 本教學課程的練習使用 async

接下來是與 Azure Digital Twins 服務互動的第一段程式碼。 此程式碼會載入您從磁碟建立的 DTDL 檔案,然後上傳至您的 Azure Digital Twins 服務執行個體。

在您稍早新增的授權碼底下貼上下列程式碼。

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

在命令視窗中,使用下列命令執行程式:

dotnet run

輸出中會列印「上傳模型」,以指出已達到此程序代碼。 不過,尚未輸出指出上傳是否成功。

若要新增列印語句,其中顯示成功上傳至 實例的所有模型,請在上一節之後新增下列程序代碼:

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

再次執行程式之前,請先測試這段新的程式碼,請記得上次執行程式後,已上傳了您的模型。 Azure Digital Twins 不會讓您上傳相同的模型兩次,因此,如果您再次嘗試上傳相同的模型,程式應該會擲回例外狀況。

請記住此資訊,在您的命令視窗中,再次使用此命令執行程式:

dotnet run

程式應該會擲回例外狀況。 當您嘗試上傳已上傳的模型時,服務會透過 REST API 傳回「不正確的要求」錯誤。 因此,Azure Digital Twins 用戶端 SDK 會針對成功以外的每個服務傳回碼擲回例外狀況。

下一節將討論類似這樣的例外狀況,以及該如何在您的程式碼中處理。

攔截錯誤

為使程式不損毀,您可以在模型上傳程式碼的周圍新增例外狀況程式碼。 在 try/catch 處理常式中包裝現有的用戶端呼叫 await client.CreateModelsAsync(typeList),如下所示:

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

在您的命令視窗中,再次使用 dotnet run 執行程式。 您會看到您取得模型上傳問題的詳細數據,包括指出的錯誤 ModelIdAlreadyExists碼。

從這一點開始,本教學課程會在 try/catch 處理程式中包裝對服務方法的所有呼叫。

建立數位分身

現在您已將模型上傳至 Azure Digital Twins,您可以使用此模型定義來建立 數位對應項數位分身是模型的執行個體,代表商務環境中的實體,例如伺服陣列上的感應器、建築物中的房間,或汽車的燈。 本節會根據您之前上傳的模型,建立一些數位分身。

若要根據此模型建立和初始化三個數字對應項,請將下列程式代碼新增至 方法的 Main 結尾。

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

在命令視窗中,使用 dotnet run 執行程式。 在輸出中,尋找指出 sampleTwin-0、sampleTwin-1 和 sampleTwin-2 已建立的列印訊息。

然後,再次執行程式。

請注意,第二次建立對應項時,即使對應項在第一次執行後已經存在,也不會擲回任何錯誤。 不同於模型建立,對應項建立是 REST 層級具有 upsert 語意的 PUT 呼叫。 使用這種 REST 呼叫表示如果對應項已經存在,嘗試再次建立相同的對應項只會取代原始對應項。 不會擲回錯誤。

建立關聯

接下來,您可以在您所建立 的對應項之間建立關聯 性,將它們連線到對應項 圖形對應項圖形用來表示整個環境。

Main 方法底下,將新的靜態方法新增至 Program 類別 (程式碼現在有兩個方法):

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

接下來,將下列程式碼新增至 Main 方法的結尾處,以呼叫 CreateRelationship 方法及使用您剛才撰寫的程式碼:

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

在命令視窗中,使用 dotnet run 執行程式。 在輸出中,尋找指出已成功建立兩個關聯性的列印陳述式。

如果已有相同標識碼的另一個關聯性,Azure Digital Twins 不會讓您建立關聯性。 因此,如果您多次執行程式,就會在關聯性建立時看到例外狀況。 此程式碼會攔截例外狀況並加以忽略。

列出關聯性

您將新增的下一個程式代碼可讓您查看您所建立的關聯性清單。

將下列新方法新增至 Program 類別:

public async static Task ListRelationshipsAsync(DigitalTwinsClient client, string srcId)
{
    try
    {
        AsyncPageable<BasicRelationship> results = client.GetRelationshipsAsync<BasicRelationship>(srcId);
        Console.WriteLine($"Twin {srcId} is connected to:");
        await foreach (BasicRelationship rel in results)
        {
            Console.WriteLine($" -{rel.Name}->{rel.TargetId}");
        }
    }
    catch (RequestFailedException e)
    {
        Console.WriteLine($"Relationship retrieval error: {e.Status}: {e.Message}");
    }
}

然後,將下列程式碼新增至 Main 方法的結尾處,以呼叫 ListRelationships 程式碼:

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

在命令視窗中,使用 dotnet run 執行程式。 您應該會看到您在輸出語句中建立的所有關聯性清單,如下所示:

主控台的螢幕擷取畫面,其中顯示程序輸出,這會產生列出對應項關聯性的訊息。

查詢數位分身

Azure Digital Twins 的主要功能是能夠輕鬆且有效率地查詢對應項圖形,以回答有關環境的問題。

本教學課程要新增的最後一段程式碼,會針對 Azure Digital Twins 執行個體執行查詢。 此範例中使用的查詢會傳回此執行個體中的所有數位分身。

新增此 using 陳述式,以利用 JsonSerializer 類別呈現數位對應項資訊:

using System.Text.Json;

然後,將下列程式碼新增至 Main 方法的結尾:

// Run a query for all twins
string query = "SELECT * FROM digitaltwins";
AsyncPageable<BasicDigitalTwin> queryResult = client.QueryAsync<BasicDigitalTwin>(query);

await foreach (BasicDigitalTwin twin in queryResult)
{
    Console.WriteLine(JsonSerializer.Serialize(twin));
    Console.WriteLine("---------------");
}

在命令視窗中,使用 dotnet run 執行程式。 您應該會在輸出中看到此執行個體中的所有數位分身。

注意

變更圖表中的資料之後,最多可能會有 10 秒的延遲,變更才會反映在查詢中。

DigitalTwins API 會立即反映變更,所以如果您需要立即回應,請使用 API 要求 (DigitalTwins GetById) 或 SDK 呼叫 (GetDigitalTwin) 來取得對應項資料,而不是使用查詢。

完整的程式碼範例

現在在本教學課程中,您有一個完整的用戶端應用程式,能夠針對 Azure Digital Twins 執行基本動作。 如需參考,下列範例會列出程式的完整程式代碼,Program.cs

using System;
// <Azure_Digital_Twins_dependencies>
using Azure.DigitalTwins.Core;
using Azure.Identity;
// </Azure_Digital_Twins_dependencies>
// <Model_dependencies>
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
using Azure;
// </Model_dependencies>
// <Query_dependencies>
using System.Text.Json;
// </Query_dependencies>

namespace DigitalTwins_Samples
{
    class DigitalTwinsClientAppSample
    {
        // <Async_signature>
        static async Task Main(string[] args)
        {
        // </Async_signature>
            Console.WriteLine("Hello World!");
            // <Authentication_code>
            string adtInstanceUrl = "https://<your-Azure-Digital-Twins-instance-hostName>"; 
            
            var credential = new DefaultAzureCredential();
            var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credential);
            Console.WriteLine($"Service client created – ready to go");
            // </Authentication_code>

            // <Model_code>
            Console.WriteLine();
            Console.WriteLine("Upload a model");
            string dtdl = File.ReadAllText("SampleModel.json");
            var models = new List<string> { dtdl };

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

            // <Print_model>
            // Read a list of models back from the service
            AsyncPageable<DigitalTwinsModelData> modelDataList = client.GetModelsAsync();
            await foreach (DigitalTwinsModelData md in modelDataList)
            {
                Console.WriteLine($"Model: {md.Id}");
            }
            // </Print_model>
            // </Model_code>

            // <Initialize_twins>
            var twinData = new BasicDigitalTwin();
            twinData.Metadata.ModelId = "dtmi:example:SampleModel;1";
            twinData.Contents.Add("data", $"Hello World!");
            
            string prefix = "sampleTwin-";
            for (int i = 0; i < 3; i++)
            {
                try
                {
                    twinData.Id = $"{prefix}{i}";
                    await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinData.Id, twinData);
                    Console.WriteLine($"Created twin: {twinData.Id}");
                }
                catch(RequestFailedException e)
                {
                    Console.WriteLine($"Create twin error: {e.Status}: {e.Message}");
                }
            }
            // </Initialize_twins>

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

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

            // <Query_twins>
            // Run a query for all twins
            string query = "SELECT * FROM digitaltwins";
            AsyncPageable<BasicDigitalTwin> queryResult = client.QueryAsync<BasicDigitalTwin>(query);
            
            await foreach (BasicDigitalTwin twin in queryResult)
            {
                Console.WriteLine(JsonSerializer.Serialize(twin));
                Console.WriteLine("---------------");
            }
            // </Query_twins>
        }

        // <Create_relationship>
        public async static Task CreateRelationshipAsync(DigitalTwinsClient client, string srcId, string targetId)
        {
            var relationship = new BasicRelationship
            {
                TargetId = targetId,
                Name = "contains"
            };
        
            try
            {
                string relId = $"{srcId}-contains->{targetId}";
                await client.CreateOrReplaceRelationshipAsync(srcId, relId, relationship);
                Console.WriteLine("Created relationship successfully");
            }
            catch (RequestFailedException e)
            {
                Console.WriteLine($"Create relationship error: {e.Status}: {e.Message}");
            }
        }
        // </Create_relationship>
        
        // <List_relationships>
        public async static Task ListRelationshipsAsync(DigitalTwinsClient client, string srcId)
        {
            try
            {
                AsyncPageable<BasicRelationship> results = client.GetRelationshipsAsync<BasicRelationship>(srcId);
                Console.WriteLine($"Twin {srcId} is connected to:");
                await foreach (BasicRelationship rel in results)
                {
                    Console.WriteLine($" -{rel.Name}->{rel.TargetId}");
                }
            }
            catch (RequestFailedException e)
            {
                Console.WriteLine($"Relationship retrieval error: {e.Status}: {e.Message}");
            }
        }
        // </List_relationships>
    }
}

清除資源

完成本教學課程之後,您可以根據接下來要執行的動作,選擇要移除的資源。

  • 如果您計劃繼續下一個教學課程,在本教學課程中使用的執行個體可在下一個教學課程中重複使用。 您可以保留在這裡設定的 Azure Digital Twins 資源,並略過本節的其餘部分。
  • 如果您想要繼續使用本文中的 Azure Digital Twins 執行個體,但清除其所有模型、對應項和關聯性,請執行下列 az dt job deletion CLI 命令:

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

    如果您只想要刪除部分元素,可以使用 az dt twin relationship deleteaz dt twin deleteaz dt model delete 命令,選擇性地只刪除您想要移除的元素。

  • 如果您不需要在本教學課程中建立的任何資源,可以使用 az group delete CLI 命令刪除本文的 Azure Digital Twins 執行個體和其他所有資源。 這會刪除資源群組中的所有 Azure 資源,以及資源群組本身。

    重要

    刪除資源群組是無法回復的動作。 資源群組和其中包含的所有資源都將永久刪除。 請確定您不會誤刪錯誤的資源群組或資源。

    開啟 Azure Cloud Shell 或本機 CLI 視窗,並執行以下命令,以刪除資源群組及其包含的所有內容。

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

您也可以從本機電腦刪除項目資料夾。

下一步

在本教學課程中,您建立了全新的 .NET 主控台用戶端應用程式。 您為此用戶端應用程式撰寫了程式碼,在 Azure Digital Twins 執行個體上執行基本動作。

請繼續前往下一個教學課程,探索您可以使用這類範例用戶端應用程式執行的工作: