Partilhar via


Gerir duplos digitais

As entidades em seu ambiente são representadas por gêmeos digitais. Gerenciar seus gêmeos digitais pode incluir criação, modificação e remoção.

Este artigo se concentra no gerenciamento de gêmeos digitais; para trabalhar com relacionamentos e o gráfico gêmeo como um todo, consulte Gerenciar o gráfico gêmeo e relacionamentos.

Gorjeta

Todas as funções do SDK vêm em versões síncronas e assíncronas.

Pré-requisitos

Para trabalhar com Gêmeos Digitais do Azure neste artigo, você precisará de uma instância de Gêmeos Digitais do Azure e as permissões necessárias para usá-la. Se você já tiver uma instância do Azure Digital Twins configurada, poderá usar essa instância e pular para a próxima seção. Caso contrário, siga as instruções em Configurar uma instância e autenticação. As instruções contêm informações para ajudá-lo a verificar se você concluiu cada etapa com êxito.

Depois de configurar sua instância, anote o nome do host da instância. Você pode encontrar o nome do host no portal do Azure.

Interfaces de desenvolvimento

Este artigo destaca como concluir diferentes operações de gerenciamento usando o SDK do .NET (C#). Você também pode criar essas mesmas chamadas de gerenciamento usando os outros SDKs de linguagem descritos em APIs e SDKs do Azure Digital Twins.

Outras interfaces de desenvolvedor que podem ser usadas para concluir essas operações incluem:

Visualização

O Azure Digital Twins Explorer é uma ferramenta visual para explorar os dados no seu gráfico de Gêmeos Digitais do Azure. Você pode usar o explorador para visualizar, consultar e editar seus modelos, gêmeos e relacionamentos.

Para ler sobre a ferramenta Azure Digital Twins Explorer, consulte Azure Digital Twins Explorer. Para obter etapas detalhadas sobre como usar seus recursos, consulte Usar o Azure Digital Twins Explorer.

Veja como é a visualização:

Captura de ecrã do Azure Digital Twins Explorer a mostrar modelos de exemplo e gémeos.

Criar um gêmeo digital

Para criar um gêmeo, use o CreateOrReplaceDigitalTwinAsync() método no cliente de serviço da seguinte forma:

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

Para criar um gêmeo digital, você precisa fornecer:

  • Um valor de ID que você deseja atribuir ao gêmeo digital (você está definindo esse ID quando o gêmeo é criado)
  • O modelo que pretende utilizar
  • Qualquer inicialização desejada de dados gêmeos, incluindo...
    • Propriedades (inicialização opcional): Você pode definir valores iniciais para propriedades do gêmeo digital, se desejar. As propriedades são tratadas como opcionais e podem ser definidas posteriormente, mas observe que elas não aparecerão como parte de um gêmeo até que tenham sido definidas.
    • Componentes (inicialização necessária se estiverem presentes em um gêmeo): Se o gêmeo contiver algum componente, ele deverá ser inicializado quando o gêmeo for criado. Podem ser objetos vazios, mas os próprios componentes têm de existir.

O modelo e quaisquer valores de propriedade inicial são fornecidos através do initData parâmetro, que é uma cadeia de caracteres JSON contendo os dados relevantes. Para obter mais informações sobre a estruturação deste objeto, continue para a próxima seção.

Gorjeta

Depois de criar ou atualizar um gêmeo, pode haver uma latência de até 10 segundos antes que as alterações sejam refletidas nas consultas. A GetDigitalTwin API (descrita mais adiante neste artigo) não enfrenta esse atraso, portanto, se você precisar de uma resposta instantânea, use a chamada de API em vez de consultar para ver seus gêmeos recém-criados.

Inicializar modelo e propriedades

Você pode inicializar as propriedades de um gêmeo no momento em que o gêmeo é criado.

A API de criação de gêmeos aceita um objeto que é serializado em uma descrição JSON válida das propriedades de gêmeos. Consulte Gêmeos digitais e o gráfico de gêmeos para obter uma descrição do formato JSON para um gêmeo.

Primeiro, você pode criar um objeto de dados para representar o gêmeo e seus dados de propriedade. Você pode criar um objeto de parâmetro manualmente ou usando uma classe auxiliar fornecida. Aqui está um exemplo de cada um.

Criar gêmeos usando dados criados manualmente

Sem o uso de classes auxiliares personalizadas, você pode representar as propriedades de um gêmeo em um Dictionary<string, object>, onde o string é o nome da propriedade e o é um objeto que object representa a propriedade e seu valor.

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

Crie gêmeos com a classe auxiliar

A classe auxiliar de permite armazenar campos de BasicDigitalTwin propriedade em um objeto "gêmeo" diretamente. Talvez você ainda queira criar a lista de propriedades usando um Dictionary<string, object>, que pode ser adicionado ao objeto gêmeo como seu CustomProperties diretamente.

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

Nota

BasicDigitalTwin Os objetos vêm com um Id campo. Você pode deixar esse campo vazio, mas se você adicionar um valor de ID, ele precisará corresponder ao parâmetro ID passado para a CreateOrReplaceDigitalTwinAsync() chamada. Por exemplo:

twin.Id = "myRoomId";

Crie gêmeos em massa com a API de Trabalhos de Importação

Você pode usar a API de Trabalhos de Importação para criar muitos gêmeos de uma só vez em uma única chamada de API. Esse método requer o uso do Armazenamento de Blobs do Azure e permissões de gravação em sua instância do Azure Digital Twins para gêmeos e trabalhos em massa.

Gorjeta

A API de Trabalhos de Importação também permite que modelos e relacionamentos sejam importados na mesma chamada, para criar todas as partes de um gráfico de uma só vez. Para obter mais informações sobre esse processo, consulte Carregar modelos, gêmeos e relacionamentos em massa com a API de Trabalhos de Importação.

Para importar gêmeos em massa, você precisa estruturar seus gêmeos (e quaisquer outros recursos incluídos no trabalho de importação em massa) como um arquivo NDJSON . A Twins seção vem depois da Models seção (e antes da Relationships seção). Os gêmeos definidos no arquivo podem fazer referência a modelos definidos neste arquivo ou já presentes na instância e, opcionalmente, podem incluir a inicialização das propriedades do gêmeo.

Você pode exibir um arquivo de importação de exemplo e um projeto de exemplo para criar esses arquivos na introdução da API de Trabalhos de Importação.

Em seguida, o arquivo precisa ser carregado em um blob de acréscimo no Armazenamento de Blobs do Azure. Para obter instruções sobre como criar um contêiner de armazenamento do Azure, consulte Criar um contêiner. Em seguida, carregue o arquivo usando seu método de carregamento preferido (algumas opções são o comando AzCopy, a CLI do Azure ou o portal do Azure).

Depois que o arquivo NDJSON tiver sido carregado para o contêiner, obtenha sua URL dentro do contêiner de blob. Você usará esse valor posteriormente no corpo da chamada de API de importação em massa.

Aqui está uma captura de tela mostrando o valor da URL de um arquivo de blob no portal do Azure:

Captura de ecrã do portal do Azure a mostrar o URL de um ficheiro num contentor de armazenamento.

Em seguida, o arquivo pode ser usado em uma chamada da API Import Jobs. Você fornece a URL de armazenamento de blob do arquivo de entrada e uma nova URL de armazenamento de blob para indicar onde você gostaria que o log de saída fosse armazenado depois que o serviço o criasse.

Obter dados para um gêmeo digital

Você pode acessar os detalhes de qualquer gêmeo digital chamando o GetDigitalTwin() método assim:

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

Essa chamada retorna dados gêmeos como um tipo de objeto fortemente tipado, como BasicDigitalTwin. BasicDigitalTwin é uma classe auxiliar de serialização incluída com o SDK, que retorna os metadados e propriedades gêmeos principais no formato pré-analisado. Você sempre pode desserializar dados gêmeos usando a biblioteca JSON de sua escolha, como System.Text.Json ou Newtonsoft.Json. Para o acesso básico a um gêmeo, no entanto, as classes auxiliares podem tornar isso mais conveniente.

Nota

BasicDigitalTwin usa System.Text.Json atributos. Para usar BasicDigitalTwin com seu DigitalTwinsClient, você deve inicializar o cliente com o construtor padrão ou, se quiser personalizar a opção serializador, use o JsonObjectSerializer.

A BasicDigitalTwin classe auxiliar também lhe dá acesso às propriedades definidas no gêmeo, por meio de um Dictionary<string, object>arquivo . Para listar as propriedades do gêmeo, você pode usar:

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

Somente as propriedades que foram definidas pelo menos uma vez são retornadas quando você recupera um gêmeo com o GetDigitalTwin() método.

Gorjeta

O displayName para um gêmeo faz parte de seus metadados de modelo, portanto, ele não será exibido ao obter dados para a instância gêmea. Para ver esse valor, você pode recuperá-lo do modelo.

Para recuperar vários gêmeos usando uma única chamada de API, consulte os exemplos de API de consulta em Consultar o gráfico de gêmeos.

Considere o seguinte modelo (escrito em Digital Twins Definition Language (DTDL)) que define uma Lua:

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

O resultado de chamar object result = await client.GetDigitalTwinAsync("my-moon"); um gêmeo do tipo Lua pode ser assim:

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

As propriedades definidas do gêmeo digital são retornadas como propriedades de nível superior no gêmeo digital. Metadados ou informações do sistema que não fazem parte da definição DTDL são retornados com um $ prefixo. As propriedades de metadados incluem os seguintes valores:

  • $dtId: A ID do gêmeo digital nesta instância do Azure Digital Twins
  • $etag: Um campo HTTP padrão atribuído pelo servidor web. Isso é atualizado para um novo valor toda vez que o gêmeo é atualizado, o que pode ser útil para determinar se os dados do gêmeo foram atualizados no servidor desde uma verificação anterior. Você pode usar If-Match para executar atualizações e exclusões que só são concluídas se o etag da entidade corresponder ao etag fornecido. Para obter mais informações sobre essas operações, consulte a documentação para DigitalTwins Update e DigitalTwins Delete.
  • $metadata: Um conjunto de propriedades de metadados, que pode incluir o seguinte:
    • $model, o DTMI do modelo do gêmeo digital.
    • lastUpdateTime para propriedades gêmeas. Este é um carimbo de data/hora que indica a data e a hora em que os Gêmeos Digitais do Azure processaram a mensagem de atualização de propriedade
    • sourceTime para propriedades gêmeas. Esta é uma propriedade opcional gravável que representa o carimbo de data/hora quando a atualização da propriedade foi observada no mundo real.

Você pode ler mais sobre os campos contidos em um gêmeo digital no formato JSON de gêmeo digital. Você pode ler mais sobre as classes auxiliares de serialização, como BasicDigitalTwin em APIs e SDKs do Azure Digital Twins.

Ver todos os gémeos digitais

Para exibir todos os gêmeos digitais em sua instância, use uma consulta. Você pode executar uma consulta com as APIs de consulta ou os comandos da CLI.

Aqui está o corpo da consulta básica que retorna uma lista de todos os gêmeos digitais na instância:

SELECT * FROM DIGITALTWINS

Atualizar um gêmeo digital

Para atualizar as propriedades de um gêmeo digital, escreva as informações que você deseja substituir no formato de patch JSON. Para obter uma lista completa das operações do Patch JSON que podem ser usadas, incluindo replace, add e remove, consulte as Operações para Patch JSON.

Depois de criar o documento JSON Patch contendo informações de atualização, passe o documento para o UpdateDigitalTwin() método:

await client.UpdateDigitalTwinAsync(twinId, updateTwinData);

Uma única chamada de patch pode atualizar quantas propriedades quiser em um único gêmeo (até mesmo todas). Se você precisar atualizar propriedades em vários gêmeos, precisará de uma chamada de atualização separada para cada gêmeo.

Gorjeta

Depois de criar ou atualizar um gêmeo, pode haver uma latência de até 10 segundos antes que as alterações sejam refletidas nas consultas. A GetDigitalTwin API (descrita anteriormente neste artigo) não enfrenta esse atraso, portanto, use a chamada de API em vez de consultar para ver seus gêmeos recém-atualizados se precisar de uma resposta instantânea.

Aqui está um exemplo de código de patch JSON. Este documento substitui os valores das propriedades de massa e raio do gêmeo digital ao qual ele é aplicado. Este exemplo mostra a operação JSON Patch replace , que substitui o valor de uma propriedade existente.

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

Ao atualizar um gêmeo de um projeto de código usando o SDK do .NET, você pode criar patches JSON usando o JsonPatchDocument do SDK do Azure .NET. Aqui está um exemplo de criação de um documento de patch JSON e uso UpdateDigitalTwin() no código do projeto.

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

Gorjeta

Você pode manter carimbos de data/hora de origem em seus gêmeos digitais atualizando o $metadata.<property-name>.sourceTime campo com o processo descrito nesta seção. Para obter mais informações sobre este campo e outros campos graváveis em gêmeos digitais, consulte Formato JSON de gêmeos digitais.

Atualizar subpropriedades em componentes de gêmeos digitais

Lembre-se de que um modelo pode conter componentes, permitindo que seja composto por outros modelos.

Para corrigir propriedades nos componentes de um gêmeo digital, você pode usar a sintaxe de caminho no Patch JSON:

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

Atualizar subpropriedades em propriedades de tipo de objeto

Os modelos podem conter propriedades que são de um tipo de objeto. Esses objetos podem ter suas próprias propriedades, e talvez você queira atualizar uma dessas subpropriedades pertencentes à propriedade de tipo de objeto. Esse processo é semelhante ao processo de atualização de subpropriedades em componentes, mas pode exigir algumas etapas extras.

Considere um modelo com uma propriedade de tipo de objeto, ObjectProperty. ObjectProperty tem uma propriedade string chamada StringSubProperty.

Quando um gêmeo é criado usando esse modelo, não é necessário instanciar o ObjectProperty naquele momento. Se a propriedade object não for instanciada durante a criação de gêmeos, não haverá nenhum caminho padrão criado para acessar ObjectProperty e seu StringSubProperty para uma operação de patch. Você precisa adicionar o caminho a ObjectProperty si mesmo antes de atualizar suas propriedades.

Isso pode ser feito com uma operação de patch add JSON, como esta:

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

Nota

Se ObjectProperty tiver mais de um imóvel, você deve incluir todos eles no value campo desta operação, mesmo que esteja atualizando apenas um:

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

Depois que isso tiver sido feito uma vez, um caminho para StringSubProperty existir, e ele pode ser atualizado diretamente a partir de agora com uma operação típica replace :

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

Embora a primeira etapa não seja necessária nos casos em que ObjectProperty foi instanciada quando o gêmeo foi criado, é recomendável usá-la toda vez que você atualizar uma subpropriedade pela primeira vez, pois nem sempre você sabe com certeza se a propriedade do objeto foi inicialmente instanciada ou não.

Atualizar o modelo de um gêmeo digital

A UpdateDigitalTwin() função também pode ser usada para migrar um gêmeo digital para um modelo diferente.

Por exemplo, considere o seguinte documento JSON Patch que substitui o campo de metadados $model do gêmeo digital:

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

Esta operação só é bem-sucedida se o gêmeo digital que está sendo modificado pelo patch estiver em conformidade com o novo modelo.

Considere o seguinte exemplo:

  1. Imagine um gêmeo digital com um modelo de foo_old. foo_old define uma massa de propriedade necessária.
  2. O novo modelo foo_new define uma massa de propriedade e adiciona uma nova temperatura de propriedade necessária.
  3. Após o patch, o gêmeo digital deve ter uma propriedade de massa e temperatura.

O patch para essa situação precisa atualizar o modelo e a propriedade de temperatura do gêmeo, da seguinte forma:

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

Atualizar sourceTime de uma propriedade

Opcionalmente, você pode decidir usar o sourceTime campo em propriedades gêmeas para registrar carimbos de data/hora para quando as atualizações de propriedade são observadas no mundo real. O Azure Digital Twins dá suporte sourceTime nativo nos metadados de cada propriedade gêmea. O sourceTime valor deve estar em conformidade com o formato de data e hora ISO 8601. Para obter mais informações sobre este campo e outros campos em gêmeos digitais, consulte Formato JSON de gêmeos digitais.

A versão mínima estável da API REST para suportar este campo é a versão 2022-05-31 . Para trabalhar com esse campo usando os SDKs do Azure Digital Twins, recomendamos usar a versão mais recente do SDK para garantir que esse campo esteja incluído.

Aqui está um exemplo de um documento de patch JSON que atualiza o valor e o sourceTime campo de uma Temperature propriedade:

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

Para atualizar o sourceTime campo em uma propriedade que faz parte de um componente, inclua o componente no início do caminho. No exemplo acima, você faria isso alterando o valor do caminho de /$metadata/Temperature/sourceTime para myComponent/$metadata/Temperature/sourceTime.

Nota

Se você atualizar o valor e em sourceTime uma propriedade e, posteriormente, atualizar apenas o valor da propriedade, o carimbo sourceTime de data/hora da primeira atualização permanecerá.

Lidar com chamadas de atualização conflitantes

Os Gêmeos Digitais do Azure garantem que todas as solicitações de entrada sejam processadas uma após a outra. Isso significa que, mesmo que várias funções tentem atualizar a mesma propriedade em um gêmeo ao mesmo tempo, não há necessidade de escrever código de bloqueio explícito para lidar com o conflito.

Esse comportamento é por gêmeos.

Como exemplo, imagine um cenário em que essas três chamadas cheguem ao mesmo tempo:

  • Escreva a propriedade A em Twin1
  • Escreva a propriedade B em Twin1
  • Escreva a propriedade A no Twin2

As duas chamadas que modificam o Twin1 são executadas uma após a outra, e mensagens de alteração são geradas para cada alteração. A chamada para modificar o Twin2 pode ser executada simultaneamente sem conflito, assim que chegar.

Excluir um gêmeo digital

Você pode excluir gêmeos usando o DeleteDigitalTwin() método. No entanto, você só pode excluir um gêmeo quando ele não tiver mais relacionamentos. Então, exclua primeiro os relacionamentos de entrada e saída do gêmeo.

Aqui está um exemplo do código para excluir gêmeos e seus relacionamentos. A DeleteDigitalTwin chamada SDK é realçada para esclarecer onde ela se enquadra no contexto de exemplo mais amplo.

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

Excluir todos os gêmeos digitais

Para obter um exemplo de como excluir todos os gêmeos de uma só vez, baixe o aplicativo de exemplo usado no Explore the basics with a sample client app. O arquivo CommandLoop.cs faz isso em uma CommandDeleteAllTwins() função.

Nota

Se você quiser excluir todos os modelos, gêmeos e relacionamentos em uma instância de uma só vez, use a API Excluir trabalhos.

Exemplo de código de gêmeo digital executável

Você pode usar o exemplo de código executável abaixo para criar um gêmeo, atualizar seus detalhes e excluir o gêmeo.

Configurar arquivos de projeto de exemplo

O trecho usa uma definição de modelo de exemplo, Room.json. Para baixar o arquivo de modelo para que você possa usá-lo em seu código, use este link para ir diretamente para o arquivo no GitHub. Em seguida, clique com o botão direito do mouse em qualquer lugar na tela, selecione Salvar como no menu do botão direito do mouse do navegador e use a janela Salvar como para salvar o arquivo como Room.json.

Em seguida, crie um novo projeto de aplicativo de console no Visual Studio ou no editor de sua escolha.

Em seguida, copie o seguinte código do exemplo executável em seu projeto:

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>

    }
}

Nota

Atualmente, há um problema conhecido que afeta a classe wrapper que pode resultar em um erro durante a DefaultAzureCredential autenticação. Se você encontrar esse problema, você pode tentar instanciar DefaultAzureCredential com o seguinte parâmetro opcional para resolvê-lo: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });

Para obter mais informações sobre esse problema, consulte Problemas conhecidos dos Gêmeos Digitais do Azure.

Configurar projeto

Em seguida, conclua as seguintes etapas para configurar o código do projeto:

  1. Adicione o arquivo Room.json que você baixou anteriormente ao seu projeto e substitua o espaço reservado <path-to> no código para informar ao seu programa onde encontrá-lo.

  2. Substitua o espaço reservado <your-instance-hostname> pelo nome de host da instância do Azure Digital Twins.

  3. Adicione duas dependências ao seu projeto que são necessárias para trabalhar com os Gêmeos Digitais do Azure. O primeiro é o pacote para o SDK de Gêmeos Digitais do Azure para .NET, e o segundo fornece ferramentas para ajudar com a autenticação no Azure.

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

Você também precisa configurar credenciais locais se quiser executar o exemplo diretamente. A próxima seção passa por isso.

Configurar credenciais locais do Azure

Este exemplo usa DefaultAzureCredential (parte da Azure.Identity biblioteca) para autenticar usuários com a instância do Azure Digital Twins quando você a executa em sua máquina local. Para obter mais informações sobre diferentes maneiras pelas quais um aplicativo cliente pode se autenticar com Gêmeos Digitais do Azure, consulte Escrever código de autenticação de aplicativo.

Com DefaultAzureCredentialo , o exemplo procurará credenciais em seu ambiente local, como uma entrada do Azure em uma CLI do Azure local ou no Visual Studio ou Visual Studio Code. Por esse motivo, você deve entrar no Azure localmente por meio de um desses mecanismos para configurar credenciais para o exemplo.

Se estiver a utilizar o Visual Studio ou o Visual Studio Code para executar exemplos de código, certifique-se de que tem sessão iniciada nesse editor com as mesmas credenciais do Azure que pretende utilizar para aceder à sua instância do Azure Digital Twins. Se você estiver usando uma janela de CLI local, execute o az login comando para entrar em sua conta do Azure. Depois disso, quando você executa seu exemplo de código, você deve ser autenticado automaticamente.

Executar o exemplo

Agora que a instalação está concluída, você pode executar o projeto de código de exemplo.

Aqui está a saída do console do programa acima:

Captura de tela da saída do console mostrando que o gêmeo foi criado, atualizado e excluído.

Próximos passos

Veja como criar e gerir relações entre os seus gémeos digitais: