Digital Twins 관리

사용자 환경의 엔터티는 디지털 트윈으로 표현됩니다. 디지털 트윈 관리에는 만들기, 수정 및 제거가 포함될 수 있습니다.

이 문서에서는 디지털 트윈을 관리하는 방법을 중점적으로 설명합니다. 관계 및 트윈 그래프 전체를 사용하려면 트윈 그래프 및 관계 관리를 참조하세요.

모든 SDK 함수는 동기 및 비동기 버전으로 제공됩니다.

필수 조건

이 문서에서 Azure Digital Twins로 작업하려면 Azure Digital Twins 인스턴스와 이를 사용하는 데 필요한 권한이 필요합니다. 이미 Azure Digital Twins 인스턴스를 설정한 경우 해당 인스턴스를 사용하고 다음 섹션으로 건너뛸 수 있습니다. 그렇지 않으면 인스턴스 및 인증 설정의 지침을 따릅니다. 지침에는 각 단계를 성공적으로 완료했는지 확인하는 데 도움이 되는 정보가 포함되어 있습니다.

인스턴스가 설정되면 인스턴스의 호스트 이름을 적어 둡니다. Azure Portal에서 호스트 이름을 찾을 수 있습니다.

개발자 인터페이스

이 문서에서는 .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);

디지털 트윈을 만들려면 다음을 제공해야 합니다.

  • 디지털 트윈에 할당하려는 ID(트윈을 만들 때 해당 ID를 정의하고 있음).
  • 사용하려는 모델
  • 다음을 포함한 트윈 데이터의 desired 초기화...
    • 속성(초기화 선택 사항): 원하는 경우 디지털 트윈의 속성에 대한 초기 값을 설정할 수 있습니다. 속성은 선택 사항으로 처리되고 나중에 설정할 수 있지만 설정될 때까지 트윈의 일부로 표시되지 않습니다.
    • 구성 요소(트윈에 있는 경우 초기화 필요): 트윈에 구성 요소가 포함된 경우 트윈을 만들 때 초기화해야 합니다. 비어 있는 개체일 수 있지만 구성 요소 자체는 존재해야 합니다.

모델과 모든 초기 속성 값은 관련 데이터를 포함하는 JSON 문자열인 initData 매개 변수를 통해 제공됩니다. 이 개체를 구조화하는 방법에 대한 자세한 내용을 보려면 다음 섹션을 계속 진행하세요.

트윈을 만들거나 업데이트한 후에는 변경 내용이 쿼리에 반영될 때까지 최대 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 필드와 함께 제공됩니다. 이 필드는 비워 둘 수 있지만 ID 값을 추가하는 경우 CreateOrReplaceDigitalTwinAsync() 호출에 전달된 ID 매개 변수와 일치해야 합니다. 예시:

twin.Id = "myRoomId";

작업 가져오기 API를 사용하여 대량으로 트윈 만들기

작업 가져오기 API를 사용하면 단일 API 호출로 한 번에 여러 트윈을 만들 수 있습니다. 이 방법을 사용하려면 트윈 및 대량 작업을 위해 Azure Digital Twins 인스턴스에서 Azure Blob Storage쓰기 권한을 사용해야 합니다.

작업 가져오기 API를 사용하면 모델과 트윈을 동일한 호출로 가져와 한 번에 그래프의 모든 파트를 만들 수 있습니다. 이 프로세스에 대한 자세한 내용은 작업 가져오기 API를 사용하여 모델, 트윈 및 관계 대량 업로드를 참조하세요.

트윈을 대량으로 가져오려면 트윈(및 대량 가져오기 작업에 포함된 기타 리소스)을 NDJSON 파일로 구성해야 합니다. Twins 섹션은 Models 섹션 뒤와 Relationships 섹션 앞에 제공됩니다. 파일에 정의된 트윈은 이 파일에 정의되었거나 인스턴스에 이미 있는 모델을 참조할 수 있으며 선택적으로 트윈 속성의 초기화를 포함할 수 있습니다.

작업 가져오기 API 소개에서 가져오기 파일 예와 이러한 파일을 만들기 위한 프로젝트 샘플을 볼 수 있습니다.

다음으로 파일을 Azure Blob Storage의 추가 Blob에 업로드해야 합니다. Azure Storage 컨테이너를 만드는 방법에 대한 지침은 컨테이너 만들기를 참조하세요. 그런 다음 기본 설정하는 업로드 방법(일부 옵션은 AzCopy 명령, Azure CLI 또는 Azure Portal)을 사용하여 파일을 업로드합니다.

NDJSON 파일이 컨테이너에 업로드되면 Blob 컨테이너 내에서 URL을 가져옵니다. 대량 가져오기 API 호출의 본문에서 나중에 이 값을 사용합니다.

다음은 Azure Portal에 있는 Blob 파일의 URL 값을 보여 주는 스크린샷입니다.

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

그런 다음 해당 파일을 Import Jobs API 호출에 사용할 수 있습니다. 입력 파일의 Blob Storage URL과 새 Blob Storage URL을 제공하여 서비스가 만들어진 후 출력 로그를 저장할 위치를 나타냅니다.

디지털 트윈에 대한 데이터 가져오기

다음과 같이 GetDigitalTwin() 메서드를 호출하여 디지털 트윈의 세부 정보에 액세스할 수 있습니다.

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

이 호출은 BasicDigitalTwin과 같은 강력한 형식의 개체 형식으로 트윈 데이터를 반환합니다. BasicDigitalTwin은 SDK에 포함된 직렬화 도우미 클래스로, 핵심 트윈 메타데이터와 속성을 준비된 형식으로 반환합니다. System.Text.Json 또는 Newtonsoft.Json과 같이 선택한 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
        }
    ]
}

문식 선문자 형식 트윈에 대한 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 인스턴스의 디지털 트윈 ID입니다.
  • $etag: 웹 서버에서 할당한 표준 HTTP 필드입니다. 이 값은 트윈이 업데이트될 때마다 새 값으로 업데이트되므로 이전 검사 이후 서버에서 트윈의 데이터가 업데이트되었는지 여부를 확인하는 데 유용할 수 있습니다. If-Match를 사용하여 엔터티의 etag가 제공된 etag와 일치하는 경우에만 완료되는 업데이트 및 삭제를 수행할 수 있습니다. 이러한 작업에 대한 자세한 내용은 DigitalTwins 업데이트DigitalTwins 삭제 설명서를 참조하세요.
  • $metadata: 다음을 포함할 수 있는 메타데이터 속성 집합입니다.
    • $model: 디지털 트윈 모델의 DTMI입니다.
    • lastUpdateTime: 트윈 속성용입니다. Azure Digital Twins가 속성 업데이트 메시지를 처리한 날짜와 시간을 나타내는 타임스탬프입니다.
    • sourceTime: 트윈 속성용입니다. 이는 현실 세계에서 속성 업데이트가 관찰되었을 때 타임스탬프를 나타내는 선택적인 쓰기 가능한 속성입니다.

디지털 트윈 JSON 형식의 디지털 트윈에 포함된 필드에 대해 자세히 확인할 수 있습니다. Azure Digital Twins API 및 SDK에서 BasicDigitalTwin과 같은 serialization 도우미 클래스에 대해 자세히 알아볼 수 있습니다.

모든 디지털 트윈 보기

인스턴스의 모든 디지털 트윈을 보려면 쿼리를 사용합니다. 쿼리 API 또는 CLI 명령을 사용하여 쿼리를 실행할 수 있습니다.

인스턴스의 모든 디지털 트윈 목록을 반환하는 기본 쿼리의 본문은 다음과 같습니다.

SELECT * FROM DIGITALTWINS

디지털 쌍 업데이트

디지털 트윈의 속성을 업데이트하려면 JSON 패치 형식으로 바꿀 정보를 작성합니다. replace, addremove를 비롯하여 사용할 수 있는 JSON 패치 작업의 전체 목록은 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를 인스턴스화할 필요가 없습니다. 트윈을 만드는 동안 개체 속성이 인스턴스화되지 않은 경우에는 패치 작업을 위해 ObjectPropertyStringSubProperty에 액세스할 수 있는 기본 경로가 생성되지 않습니다. 해당 속성을 업데이트하기 전에 직접 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() 함수를 사용하여 디지털 트윈을 다른 모델로 마이그레이션할 수도 있습니다.

예를 들어 디지털 트윈의 메타데이터 $model 필드를 대체하는 다음과 같은 JSON 패치 문서를 고려합니다.

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

이 작업은 패치로 수정되는 디지털 트윈이 새 모델을 준수하는 경우에만 성공합니다.

다음 예제를 참조하세요.

  1. foo_old 모델을 사용하는 디지털 트윈을 생각해 보세요. foo_old는 필요한 속성 mass를 정의합니다.
  2. 새 모델 foo_new는 속성 mass를 정의하고 새 필수 속성 temperature를 추가합니다.
  3. 패치 후에 디지털 트윈에는 mass 속성과 temperature 속성이 모두 있어야 합니다.

이 상황에 대한 패치는 모델과 트윈의 temperature 속성을 모두 업데이트해야 합니다. 예를 들면 다음과 같습니다.

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

속성의 sourceTime 업데이트

필요에 따라 트윈 속성의 sourceTime 필드를 사용하여 실제로 속성 업데이트가 관찰되는 시기에 대한 타임스탬프를 기록하도록 결정할 수 있습니다. Azure Digital Twins는 기본적으로 각 트윈 속성에 대한 메타데이터의 sourceTime을 지원합니다. sourceTime 값은 ISO 8601 날짜 및 시간 형식을 준수해야 합니다. 이 필드 및 디지털 트윈의 다른 필드에 대한 자세한 내용은 디지털 트윈 JSON 형식을 참조하세요.

이 필드를 지원하는 안정적인 최소 REST API 버전은 2022-05-31 버전입니다. Azure Digital Twins SDK를 사용하여 이 필드를 작업하려면 최신 버전의 SDK를 사용하여 이 필드가 포함되어 있는지 확인하는 것이 좋습니다.

다음은 Temperature 속성의 값과 sourceTime 필드를 모두 업데이트하는 JSON 패치 문서의 예제입니다.

[
  {
    "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.

다음 단계

디지털 트윈 간의 관계를 만들고 관리하는 방법을 참조하세요.