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ê precisa 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, esses componentes deverão ser inicializados 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 sofre 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 numa descrição JSON válida das propriedades do gémeo. 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 BasicDigitalTwin permite armazenar campos de propriedade diretamente num objeto "gémeo". 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 Importação de Trabalhos

Você pode usar a API de Importação de Trabalhos para criar muitos gémeos de uma só vez em uma única chamada de API. Esse método requer o uso de Armazenamento de Blobs do Azure e permissões de gravação na 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 este 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. Os gêmeos definidos no arquivo podem, opcionalmente, incluir a inicialização de propriedades gêmeas.

Você pode visualizar um ficheiro de importação de exemplo e um projeto exemplo para criar estes ficheiros 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 ficheiro NDJSON for carregado para o contentor, obtenha o seu URL dentro do contentor de blobs. Você usa 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 aceder aos detalhes de qualquer gémeo digital chamando o método GetDigitalTwin() desta forma:

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

Esta 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 principais dos gêmeos digitais em formato pré-processado. Você sempre pode desserializar dados gêmeos usando a biblioteca JSON de sua escolha, como System.Text.Json ou Newtonsoft.Json. Para acesso básico a um gêmeo, no entanto, as classes auxiliares podem tornar a desserialização de dados gêmeos 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>. 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 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 aparece 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 executar object result = await client.GetDigitalTwinAsync("my-moon"); num 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. Essa propriedade é atualizada 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 as seguintes propriedades:
    • $model, o DTMI do modelo do gémeo digital.
    • lastUpdateTime para propriedades gêmeas. Esta propriedade é um carimbo temporal que indica a data e a hora em que o Azure Digital Twins processou a mensagem de atualização de propriedade.
    • sourceTime para propriedades gêmeas. Esta propriedade é uma propriedade opcional e gravável que representa o timestamp em que 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 do 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 visualizar todos os gémeos digitais na sua instância, utilize uma consulta. Você pode executar uma consulta com as APIs de Queryou os comandosCLI.

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 pretende substituir no formato JSON Patch. Para obter uma lista completa das operações do Patch JSON que podem ser usadas, incluindo replace, adde 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). Caso precise de 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 sofre 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 de um gêmeo digital. 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 os carimbos de data/hora de origem nos seus gémeos digitais atualizando o campo $metadata.<property-name>.sourceTime com o processo descrito nesta secçã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 do objeto não for instanciada durante a criação do gémeo, 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 você mesmo antes de atualizar suas propriedades.

Esta adição pode ser feita com uma operação JSON Patch add, 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 de esta adição ser feita uma vez, um caminho para StringSubProperty já existe, podendo 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 instanciado quando o gémeo foi criado, recomendamos que utilize essa opção sempre que atualizar uma subpropriedade pela primeira vez, porque pode não saber 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 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 a propriedade obrigatória massa.
  2. O novo modelo foo_new define uma propriedade massa e adiciona uma nova propriedade obrigatória temperatura.
  3. Após o patch, o gémeo digital deve ter propriedades 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 a hora de origem 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 nativo a sourceTime nos metadados de cada propriedade twin. 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 tanto o sourceTime campo quanto o valor 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 anterior, você incluiria o componente alterando o valor do caminho de /$metadata/Temperature/sourceTime para myComponent/$metadata/Temperature/sourceTime.

Nota

Se atualizar tanto o sourceTime quanto o valor de uma propriedade e, posteriormente, atualizar apenas o valor da propriedade, o carimbo de data/hora sourceTime 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 sequencialmente, uma após a outra. Esse processamento sequencial 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.

Este comportamento aplica-se a cada par de 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, ao ser recebida.

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 chamada do DeleteDigitalTwin SDK é destacada para esclarecer onde se enquadra no contexto mais amplo do exemplo.

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 ficheiro CommandLoop.cs elimina todos os gêmeos digitais numa CommandDeleteAllTwins() função.

Nota

Se pretender eliminar todos os modelos, gémeos e relacionamentos de uma instância de uma só vez, utilize a API Delete Jobs.

Exemplo de código executável de Digital Twin

Você pode usar o seguinte exemplo de código executável 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 DefaultAzureCredential que pode resultar em um erro durante a 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 marcador de posição <your-instance-hostname> pelo nome de host da sua 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 Azure Digital Twins para .NET, e o segundo fornece ferramentas para ajudar na autenticação contra o 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 percorre esse pré-requisito.

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 DefaultAzureCredential, o exemplo procura credenciais no seu ambiente local, como um início de sessão no Azure numa 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 de entrar, quando você executar 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 anterior:

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: