Share via


管理 Digital Twins

您環境中的實體會以數位對應項表示。 數位對應項的管理可能包括建立、修改和移除。

本文著重於數位對應項的管理;若要整體性地處理關聯性和對應項圖表,請參閱管理對應項圖表和關聯性

提示

所有 SDK 函式都有同步和非同步版本。

必要條件

若要使用本文中的 Azure Digital Twins,您必須要有 Azure Digital Twins 執行個體,以及必要的使用權限。 如果您已經設定好 Azure Digital Twins 執行個體,您可以直接使用該執行個體,並跳至下一節。 否則,請依照設定執行個體和驗證中的指示進行。 指示中包含的資訊可協助您確認已成功完成每個步驟。

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

開發人員介面

本文重點摘要如何使用 .NET (C#) SDK 來完成不同的管理作業。 您也可以使用 Azure Digital Twins API 和 SDK 中所述的其他語言 SDK 來製作這些相同的管理呼叫。

其他可用來完成這些作業的開發人員介面包括:

視覺效果

Azure Digital Twins Explorer 是一種視覺工具,可探索您 Azure Digital Twins 圖表中的資料。 您可以使用總管來檢視、查詢及編輯模型、對應項和關聯性。

如需閱讀 Azure Digital Twins Explorer 工具的相關資訊,請參閱 Azure Digital Twins Explorer。 如需如何使用其功能的詳細步驟,請參閱使用 Azure Digital Twins Explorer

以下是視覺效果的外觀:

Screenshot of Azure Digital Twins Explorer showing sample models and twins.

建立數位對應項

若要建立對應項,請在服務用戶端上使用 CreateOrReplaceDigitalTwinAsync() 方法,如下所示:

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

若要建立數位對應項,您必須提供:

  • 您要指派給數位對應項的識別碼值 (您會在對應項建立時定義該識別碼)
  • 您想要使用的模型
  • 任何所需的對應項資料初始化,包括...
    • 屬性 (可選擇初始化):如果您想要的話,可以設定數位對應項屬性的初始值。 屬性會被視為選擇性,且可於稍後設定,但請注意,屬性未經設定則不會顯示為對應項的一部分
    • 元件 (若存在於對應項上則必須初始化):如果您的對應項包含任何元件,則必須在建立對應項時初始化這些元件。 這可以是空物件,但是元件本身必須存在。

模型和任何初始屬性值都是透過 initData 參數提供的,這是包含相關資料的 JSON 字串。 如需關於建構此物件的詳細資訊,請繼續進行下一節。

提示

建立或更新對應項之後,最多可能會有 10 秒的延遲,變更才會反映在查詢中。 GetDigitalTwin API (本文後續將有說明) 不會遇到此延遲,因此如果您需要立即回應,請使用 API 呼叫來查看您新建立的對應項,而不是使用查詢。

初始化模型和屬性

您可以在建立對應項時初始化對應項的屬性。

對應項建立 API 接受序列化為對應項屬性的有效 JSON 描述的物件。 如需對應項的 JSON 格式描述,請參閱數位對應項和對應項圖表

首先,您可以建立資料物件來表示對應項及其屬性資料。 您可以手動建立參數物件,或使用提供的協助程式類別來建立。 以下是各項的範例。

使用手動建立的資料來建立對應項

若未使用任何自訂協助程式類別,您可以用 Dictionary<string, object> 來表示對應項的屬性,其中,string 是屬性的名稱,而 object 是代表屬性及其值的物件。

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

使用協助程式類別來建立對應項

BasicDigitalTwin 的協助程式類別可讓您直接將屬性欄位儲存在「對應項」物件中。 您仍可使用 Dictionary<string, object> 來建置屬性清單,然後可直接將其新增至對應項物件作為其 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);

注意

BasicDigitalTwin 物件隨附 Id 欄位。 您可以將此欄位保留為空白,但若您新增了識別碼值,該值必須符合傳至 CreateOrReplaceDigitalTwinAsync() 呼叫的識別碼參數。 例如:

twin.Id = "myRoomId";

使用匯入作業 API 大量建立對應項

您可以使用匯入作業 API,在單一 API 呼叫中一次建立許多對應項。 此方法需要使用 Azure Blob 儲存體,以及 Azure Digital Twins 執行個體中對應項和大量作業的寫入權限

提示

匯入作業 API 也允許在相同的呼叫中匯入模型和關聯性,以一次建立圖表的所有部分。 如需此程序的詳細資訊,請參閱使用匯入作業 API 大量上傳模型、對應項和關聯性

若要大量匯入對應項,您必須將對應項 (以及大量匯入作業中包含的任何其他資源) 建構為 NDJSON 檔案。 Twins 區段位於 Models 區段之後 (以及區 Relationships 段之前)。 檔案中定義的對應項可以參考此檔案中定義或已存在於執行個體中的模型,且其可以選擇性地包含對應項屬性的初始化。

您可以在匯入作業 API 簡介中檢視範例匯入檔案和範例專案,以建立這些檔案。

接下來,檔案必須上傳至 Azure Blob 儲存體中的附加 Blob。 如需如何建立 Azure 儲存體容器的指示,請參閱建立容器。 然後,使用您慣用的上傳方法來上傳檔案 (一些選項如 AzCopy 命令Azure CLIAzure 入口網站)。

將 NDJSON 文件案上傳至容器之後,請在 Blob 容器內取得其 URL。 您稍後會在大量匯入 API 呼叫的本文中使用此值。

以下螢幕擷取畫面顯示 Azure 入口網站中 Blob 檔案的 URL 值:

Screenshot of the Azure portal showing the URL of a file in a storage container.

然後,檔案可以在匯入作業 API 呼叫中使用。 您會提供輸入檔的 Blob 儲存體 URL,以及新的 Blob 儲存體 URL,以指出您想要在服務建立輸出記錄之後儲存的位置。

取得數位對應項的資料

您可以呼叫 GetDigitalTwin() 方法來存取任何數位對應項的詳細資料,如下所示:

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

此呼叫會將對應項資料傳回為強型別物件類型,例如 BasicDigitalTwinBasicDigitalTwin 是隨附於 SDK 的序列化協助程式類別,會以預先剖析的形式傳回核心對應項中繼資料和屬性。 將對應項資料還原序列化時,一律可以使用您選擇的 JSON 程式庫,例如 System.Text.JsonNewtonsoft.Json。 然而,協助程式類別可讓您更方便地進行對應項的基本存取。

注意

BasicDigitalTwin 使用 System.Text.Json 屬性。 若要將 BasicDigitalTwinDigitalTwinsClient 一起使用,您必須以預設建構函式初始化用戶端,或者,如果要自訂序列化程式選項,請使用 JsonObjectSerializer

BasicDigitalTwin 協助程式類別也可讓您透過 Dictionary<string, object> 存取對應項上定義的屬性。 若要列出對應項的屬性,您可以使用:

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

當您使用 GetDigitalTwin() 方法擷取對應項時,只會傳回至少設定過一次的屬性。

提示

對應項的 displayName 是其模型中繼資料的一部分,因此在取得對應項執行個體的資料時將不會顯示。 若要查看此值,您可以從模型加以擷取

若要使用單一 API 呼叫擷取多個對應項,請參閱查詢對應項圖表中的查詢 API 範例。

請考量下列定義 Moon 的模型 (以數位對應項定義語言 (DTDL) 撰寫):

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

對 Moon 類型對應項呼叫 object result = await client.GetDigitalTwinAsync("my-moon"); 的結果可能如下所示:

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

已定義的數位對應項屬性會傳回作為數位對應項的最上層屬性。 不屬於 DTDL 定義一部分的中繼資料或系統資訊,傳回時會加上 $ 前置詞。 中繼資料屬性包括下列值:

  • $dtId:此 Azure Digital Twins 執行個體中的數位對應項的識別碼
  • $etag:網頁伺服器所指派的標準 HTTP 欄位。 每次更新對應項時,此欄位都會更新為新的值,而可用來判斷對應項的資料在前次檢查之後是否已在伺服器上更新。 您可以使用 If-Match 來執行在實體的 etag 符合提供的 etag 時才會完成的更新和刪除。 如需這些作業的詳細資訊,請參閱 DigitalTwins 更新DigitalTwins 刪除的文件。
  • $metadata:一組中繼資料屬性,可能包含下列項目:
    • $model,數位對應項模型的 DTMI。
    • 數位對應項的 lastUpdateTime。 這是時間戳記,指出 Azure Digital Twins 處理屬性更新訊息的日期和時間
    • 數位對應項的 sourceTime。 這是選用的可寫入屬性,代表實際觀察到屬性更新時的時間戳記。

您可以進一步了解數位對應項中以數位對應項 JSON 格式所包含的欄位。 您可以在 Azure Digital Twins API 和 SDK 中深入了解 BasicDigitalTwin 之類的序列化協助程式類別。

檢視所有數位對應項

若要檢視執行個體中的所有數位對應項,請使用查詢。 您可以使用查詢 APICLI 命令來執行查詢。

以下是會傳回執行個體中所有數位對應項之清單的基本查詢本文:

SELECT * FROM DIGITALTWINS

更新數位對應項

若要更新數位對應項的屬性,請撰寫您想要以 JSON 修補檔格式取代的資訊。 如需可使用的 JSON 修補檔作業的完整清單 (包括 replaceaddremove),請參閱 JSON 修補檔的作業

在編寫包含更新資訊的 JSON 修補檔文件後,將文件傳入 UpdateDigitalTwin() 方法中:

await client.UpdateDigitalTwinAsync(twinId, updateTwinData);

一個修補檔呼叫可以隨您所需更新單一對應項上的多個屬性 (甚至所有屬性)。 如果您需要跨多個對應項更新屬性,每個對應項都需要個別的更新呼叫。

提示

建立或更新對應項之後,最多可能會有 10 秒的延遲,變更才會反映在查詢中。 GetDigitalTwin API (本文稍早所述) 不會遇到此延遲,因此如果您需要立即回應,請使用 API 呼叫來查看您剛更新的對應項,而不是使用查詢。

以下是 JSON 修補檔程式碼的範例。 本文件會取代其所套用之數位對應項的 massradius 屬性值。 此範例顯示 JSON 修補檔 replace 作業,這會取代現有屬性的值。

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

使用 .NET SDK 更新程式碼專案中的對應項時,您可以使用 Azure .NET SDK 的 JsonPatchDocument 來建立 JSON 修補檔。 以下是在專案程式碼中建立 JSON 修補檔文件和使用 UpdateDigitalTwin() 的範例。

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

提示

您可以使用本節所述的程序更新 $metadata.<property-name>.sourceTime 欄位,藉以維護數位對應項上的來源時間戳記。 若要進一步了解此欄位以及數位對應項上可寫入的其他欄位,請參閱數位對應項 JSON 格式

更新數位對應項元件中的子屬性

您應該記得,模型可能包含元件,因此可由其他模型組成。

若要修補數位對應項元件中的屬性,您可以在 JSON 修補檔中使用路徑語法:

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

更新物件類型屬性中的子屬性

模型可能包含屬於物件類型的屬性。 這些物件可以有其本身的屬性,且您可以更新其中一個屬於物件類型屬性的子屬性。 此程序類似於更新元件中的子屬性的程序,但可能需執行一些額外的步驟。

請考量具有物件類型屬性 ObjectProperty 的模型。 ObjectProperty 具有名為 StringSubProperty 的字串屬性。

使用此模型建立對應項時,不需要將 ObjectProperty 具現化。 如果在對應項建立期間未將物件屬性具現化,則不會為修補作業建立預設路徑來存取 ObjectProperty 及其 StringSubProperty。 您必須自行新增 ObjectProperty 的路徑,才能更新其屬性。

此作業可用 JSON 修補檔 add 作業來完成,如下所示:

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

注意

如果 ObjectProperty 有多個屬性,您應將所有屬性包含在此作業的 value 欄位中,即使您只要更新一個屬性亦然:

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

此動作完成一次之後,即有 StringSubProperty 的路徑存在,至此即可用一般 replace 作業直接加以更新:

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

雖然在對應項建立時具現化了 ObjectProperty 的情況下不需要第一個步驟,但建議您在每次首度更新子屬性時使用該步驟,因為您不一定能確知物件屬性最初是否已具現化。

更新數位對應項的模型

UpdateDigitalTwin() 函式也可以用來將數位對應項移轉至不同的模型。

例如,請考慮下列 JSON Patch 文件,取代數位對應項的中繼資料 $model 欄位:

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

只有在修補程式修改的數位對應項符合新模型時,此作業才會成功。

請考慮下列範例:

  1. 假設數位對應項具有 foo_old 的模型。 foo_old 會定義必要屬性 mass
  2. 新模型 foo_new 會定義屬性 mass,並新增必要屬性 temperature
  3. 修補之後,數位對應項必須同時具有質量與溫度屬性。

這種情況的修補程式需要更新模型和對應項的溫度屬性,如下所示:

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

更新屬性的 sourceTime

您可以選擇決定使用對應項屬性上的 sourceTime 欄位來記錄實際觀察到屬性更新時的時間戳記。 Azure Digital Twins 原生支援每個對應項屬性的中繼資料中的 sourceTimesourceTime 值必須符合 ISO 8601 日期和時間格式。 若要進一步了解此欄位以及數位對應項上的其他欄位,請參閱數位對應項 JSON 格式

支援此欄位的最低穩定 REST API 版本為 2022-05-31 版本。 若要使用 Azure Digital Twins SDK 來處理此欄位,建議使用最新版本的 SDK,以確定此欄位包含在內。

以下是 JSON 修補檔文件的範例,同時更新了 Temperature 屬性的值和 sourceTime 欄位:

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

若要更新屬於某元件之屬性上的 sourceTime 欄位,請在路徑的開頭處包含該元件。 在上述範例中,為此您應將路徑值從 /$metadata/Temperature/sourceTime 變更為 myComponent/$metadata/Temperature/sourceTime

注意

如果您先同時更新了屬性上的 sourceTime 和值,繼而僅更新了屬性的值,將會保留第一次更新的 sourceTime 時間戳記。

處理衝突的更新呼叫

Azure Digital Twins 可確保所有傳入的要求會逐一處理。 這表示,即使多個函式嘗試同時更新對應項上的相同屬性,您也不需要撰寫明確的鎖定程式碼來處理衝突。

此行為以個別對應項為基礎。

例如,假設以下三個呼叫同時抵達:

  • Twin1 上寫入屬性 A
  • Twin1 上寫入屬性 B
  • Twin2 上寫入屬性 A

修改 Twin1 的兩個呼叫會逐一執行,且每次變更都會產生變更訊息。 修改 Twin2 的呼叫可在抵達後隨即同時執行,而不會發生衝突。

刪除數位對應項

您可以使用 DeleteDigitalTwin() 方法來刪除對應項。 不過,您只能在對應項沒有其他關聯性時刪除對應項。 因此,請先刪除對應項的傳入和傳出關聯性。

以下是刪除對應項及其關聯性的程式碼範例。 DeleteDigitalTwin SDK 呼叫會醒目提示,以釐清其在更廣泛的範例內容中位於何處。

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

刪除所有數位對應項

如需如何同時刪除所有對應項的範例,請下載使用範例用戶端應用程式探索基本概念中使用的範例應用程式。 CommandLoop.cs 檔案會在 CommandDeleteAllTwins() 函式中執行此動作。

注意

如果您想要一次刪除執行個體中的所有模型、對應項和關聯性,請使用刪除作業 API

可執行的數位對應項程式碼範例

您可以使用下列可執行的程式碼範例來建立對應項、更新其詳細資料,以及刪除對應項。

設定範例專案檔

程式碼片段會使用範例模型定義 Room.json。 若要下載模型檔案以便在程式碼中使用,請使用此連結直接移至 GitHub 中的檔案。 然後,以滑鼠右鍵按一下畫面上的任何位置,在瀏覽器的右鍵功能表中選取 [另存新檔],然後使用 [另存新檔] 視窗,將檔案儲存為 Room.json

接下來,在 Visual Studio 或您選擇的編輯器中,建立新的主控台應用程式專案

然後,將可執行範例的下列程式碼複製到您的專案中:

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>

    }
}

注意

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

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

設定專案

接下來,完成下列步驟以設定您的專案程式碼:

  1. 將您稍早下載的 Room.json 檔案新增至專案,並取代程式碼中的 <path-to> 預留位置,以告知程式可在何處找到。

  2. 將預留位置 <your-instance-hostname> 取代為您 Azure Digital Twins 執行個體的主機名稱。

  3. 將使用 Azure Digital Twins 時所需的兩個相依性新增至您的專案。 第一個是適用於 .NET 的 Azure Digital Twins SDK 的套件,第二個則會提供協助驗證 Azure 的工具。

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

如果您想要直接執行範例,則也需要設定本機認證。 下一節將予以逐步解說。

設定本機 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 帳戶。 之後,當您執行程式碼範例時,應該會自動驗證。

執行範例

現在設定已完成,您可以執行範例程式碼專案。

以下是上述程式的主控台輸出:

Screenshot of the console output showing that the twin is created, updated, and deleted.

下一步

了解如何建立和管理數位對應項之間的關聯性: