Tutorial: Codificando com o SDK do Azure Digital Twins

Os desenvolvedores que trabalham com Gêmeos Digitais do Azure geralmente escrevem aplicativos cliente para interagir com suas instâncias do serviço Gêmeos Digitais do Azure. Este tutorial focado no desenvolvedor fornece uma introdução à programação no serviço Gêmeos Digitais do Azure, usando o SDK dos Gêmeos Digitais do Azure para .NET (C#). Ele orienta você ao escrever um aplicativo cliente de console C# passo a passo, começando do zero.

  • Configurar projeto
  • Introdução ao código do projeto
  • Exemplo de código completo
  • Clean up resources (Limpar recursos)
  • Próximos passos

Pré-requisitos

Este tutorial do Azure Digital Twins usa a linha de comando para instalação e trabalho de projeto. Como tal, você pode usar qualquer editor de código para percorrer os exercícios.

O que você precisa para começar:

  • Qualquer editor de código
  • .NET Core 3.1 em sua máquina de desenvolvimento. Você pode baixar esta versão do SDK do .NET Core para várias plataformas em Baixar o .NET Core 3.1.

Preparar uma instância do Azure Digital Twins

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.

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 como 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.

Configurar projeto

Quando estiver pronto para usar sua instância do Azure Digital Twins, comece a configurar o projeto de aplicativo cliente.

Abra uma janela de console em sua máquina e crie um diretório de projeto vazio onde você deseja armazenar seu trabalho durante este tutorial. Nomeie o diretório como quiser (por exemplo, DigitalTwinsCodeTutorial).

Navegue até o novo diretório.

Uma vez no diretório do projeto, crie um projeto de aplicativo de console .NET vazio. Na janela de comando, você pode executar o seguinte comando para criar um projeto C# mínimo para o console:

dotnet new console

Este comando criará vários arquivos dentro do seu diretório, incluindo um chamado Programa.cs onde você escreverá a maior parte do seu código.

Mantenha a janela de comando aberta, pois você continuará a usá-la durante todo o tutorial.

Em seguida, adicione duas dependências ao seu projeto que serão necessárias para trabalhar com os Gêmeos Digitais do Azure. O primeiro é o pacote para o SDK do Azure Digital Twins para .NET, o segundo fornece ferramentas para ajudar com a autenticação no Azure.

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

Introdução ao código do projeto

Nesta seção, você começará a escrever o código para seu novo projeto de aplicativo para trabalhar com os Gêmeos Digitais do Azure. As ações abrangidas incluem:

  • Autenticação no serviço
  • Carregar um modelo
  • Erros de captura
  • Criação de gêmeos digitais
  • Criação de relações
  • Consultando gêmeos digitais

Há também uma seção mostrando o código completo no final do tutorial. Você pode usar esta seção como uma referência para verificar seu programa à medida que avança.

Para começar, abra o arquivo Program.cs em qualquer editor de código. Você verá um modelo de código mínimo que se parece com isto:

Screenshot of a snippet of sample code in a code editor.

Primeiro, adicione algumas using linhas na parte superior do código para extrair as dependências necessárias.

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

Em seguida, você adicionará código a este arquivo para preencher algumas funcionalidades.

Autenticar no serviço

A primeira coisa que seu aplicativo precisará fazer é autenticar no serviço Gêmeos Digitais do Azure. Em seguida, você pode criar uma classe de cliente de serviço para acessar as funções do SDK.

Para autenticar, você precisa do nome do host da sua instância do Azure Digital Twins.

Em Program.cs, cole o seguinte código abaixo da linha de impressão "Hello, World!" no Main método. Defina o valor de para o nome do host da instância do adtInstanceUrl Azure Digital Twins.

string adtInstanceUrl = "https://<your-Azure-Digital-Twins-instance-hostName>"; 

var credential = new DefaultAzureCredential();
var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credential);
Console.WriteLine($"Service client created – ready to go");

Guarde o ficheiro.

Na janela de comando, execute o código com este comando:

dotnet run

Este comando irá restaurar as dependências na primeira execução e, em seguida, executar o programa.

  • Se nenhum erro ocorrer, o programa imprimirá: "Cliente de serviço criado - pronto para ir".
  • Como ainda não há tratamento de erros neste projeto, se houver algum problema, você verá uma exceção lançada pelo código.

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.

Carregar um modelo

Os Gêmeos Digitais do Azure não têm vocabulário de domínio intrínseco. Os tipos de elementos em seu ambiente que você pode representar nos Gêmeos Digitais do Azure são definidos por você, usando modelos. Os modelos são semelhantes às classes em linguagens de programação orientadas a objetos, eles fornecem modelos definidos pelo usuário para gêmeos digitais seguirem e instanciarem mais tarde. Eles são escritos em uma linguagem semelhante a JSON chamada Digital Twins Definition Language (DTDL).

A primeira etapa na criação de uma solução de Gêmeos Digitais do Azure é definir pelo menos um modelo em um arquivo DTDL.

No diretório onde você criou seu projeto, crie um novo arquivo .json chamado SampleModel.json. Cole no seguinte corpo de arquivo:

{
  "@id": "dtmi:example:SampleModel;1",
  "@type": "Interface",
  "displayName": "SampleModel",
  "contents": [
    {
      "@type": "Relationship",
      "name": "contains"
    },
    {
      "@type": "Property",
      "name": "data",
      "schema": "string"
    }
  ],
  "@context": "dtmi:dtdl:context;3"
}

Gorjeta

Se você estiver usando o Visual Studio para este tutorial, convém selecionar o arquivo JSON recém-criado e definir a propriedade Copiar para diretório de saída no Inspetor de propriedades como Copiar se for mais recente ou Copiar sempre. Isso permitirá que o Visual Studio localize o arquivo JSON com o caminho padrão quando você executar o programa com F5 durante o restante do tutorial.

Gorjeta

Você pode verificar documentos de modelo para certificar-se de que a DTDL é válida usando a biblioteca DTDLParser. Para obter mais informações sobre como usar essa biblioteca, consulte Analisar e validar modelos.

Em seguida, adicione mais algum código ao Program.cs para carregar o modelo que você criou em sua instância do Azure Digital Twins.

Primeiro, adicione algumas using instruções à parte superior do arquivo:

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

Em seguida, prepare-se para usar os métodos assíncronos no SDK do serviço C#, alterando a assinatura do método para permitir a execução assíncrona Main .

static async Task Main(string[] args)
{

Nota

O uso async não é estritamente necessário, pois o SDK também fornece versões síncronas de todas as chamadas. Este tutorial pratica o uso do async.

Em seguida, vem o primeiro bit de código que interage com o serviço Azure Digital Twins. Este código carrega o ficheiro DTDL que criou a partir do disco e, em seguida, carrega-o para a instância de serviço do Azure Digital Twins.

Cole o código a seguir sob o código de autorização que você adicionou anteriormente.

Console.WriteLine();
Console.WriteLine($"Upload a model");
string dtdl = File.ReadAllText("SampleModel.json");
var models = new List<string> { dtdl };
// Upload the model to the service
await client.CreateModelsAsync(models);

Na janela de comando, execute o programa com este comando:

dotnet run

"Carregar um modelo" será impresso na saída, indicando que esse código foi alcançado, mas ainda não há saída para indicar se o upload foi bem-sucedido.

Para adicionar uma instrução print mostrando todos os modelos que foram carregados com êxito na instância, adicione o seguinte código logo após a seção anterior:

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

Antes de executar o programa novamente para testar esse novo código, lembre-se de que a última vez que você executou o programa, você já carregou seu modelo. Os Gêmeos Digitais do Azure não permitem que você carregue o mesmo modelo duas vezes, portanto, se você tentar carregar o mesmo modelo novamente, o programa deverá lançar uma exceção.

Com essas informações em mente, execute o programa novamente com este comando na janela de comando:

dotnet run

O programa deve lançar uma exceção. Quando você tenta carregar um modelo que já foi carregado, o serviço retorna um erro de "solicitação incorreta" por meio da API REST. Como resultado, o SDK do cliente do Azure Digital Twins, por sua vez, lançará uma exceção, para cada código de retorno de serviço diferente do sucesso.

A próxima seção fala sobre exceções como esta e como lidar com elas em seu código.

Erros de captura

Para evitar que o programa falhe, você pode adicionar código de exceção ao redor do código de carregamento do modelo. Envolva a chamada await client.CreateModelsAsync(typeList) de cliente existente em um manipulador try/catch, da seguinte forma:

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

Execute o programa novamente com dotnet run na janela de comando. Você verá que recebe mais detalhes sobre o problema de carregamento do modelo, incluindo um código de erro informando que ModelIdAlreadyExists.

A partir deste ponto, o tutorial encapsulará todas as chamadas para métodos de serviço em manipuladores try/catch.

Criar duplos digitais

Agora que carregou um modelo para os Gêmeos Digitais do Azure, você pode usar essa definição de modelo para criar gêmeos digitais. Os gêmeos digitais são instâncias de um modelo e representam as entidades dentro do seu ambiente de negócios — coisas como sensores em uma fazenda, quartos em um prédio ou luzes em um carro. Esta seção cria alguns gêmeos digitais com base no modelo que você carregou anteriormente.

Adicione o seguinte código ao final do Main método para criar e inicializar três gêmeos digitais com base nesse modelo.

var twinData = new BasicDigitalTwin();
twinData.Metadata.ModelId = "dtmi:example:SampleModel;1";
twinData.Contents.Add("data", $"Hello World!");

string prefix = "sampleTwin-";
for (int i = 0; i < 3; i++)
{
    try
    {
        twinData.Id = $"{prefix}{i}";
        await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinData.Id, twinData);
        Console.WriteLine($"Created twin: {twinData.Id}");
    }
    catch(RequestFailedException e)
    {
        Console.WriteLine($"Create twin error: {e.Status}: {e.Message}");
    }
}

Na janela de comando, execute o programa com dotnet run. Na saída, procure as mensagens de impressão que sampleTwin-0, sampleTwin-1 e sampleTwin-2 foram criadas.

Em seguida, execute o programa novamente.

Observe que nenhum erro é lançado quando os gêmeos são criados pela segunda vez, mesmo que os gêmeos já existam após a primeira corrida. Ao contrário da criação de modelos, a criação de gêmeos é, no nível REST, uma chamada PUT com semântica upsert . Usar esse tipo de chamada REST significa que, se um gêmeo já existir, uma tentativa de criar o mesmo gêmeo novamente apenas substituirá o gêmeo original. Nenhum erro é lançado.

Criar relações

Em seguida, você pode criar relações entre os gêmeos que você criou, para conectá-los em um gráfico de gêmeos. Os gráficos gêmeos são usados para representar todo o seu ambiente.

Adicione um novo método estático à Program classe, abaixo do Main método (o código agora tem dois métodos):

public async static Task CreateRelationshipAsync(DigitalTwinsClient client, string srcId, string targetId)
{
    var relationship = new BasicRelationship
    {
        TargetId = targetId,
        Name = "contains"
    };

    try
    {
        string relId = $"{srcId}-contains->{targetId}";
        await client.CreateOrReplaceRelationshipAsync(srcId, relId, relationship);
        Console.WriteLine("Created relationship successfully");
    }
    catch (RequestFailedException e)
    {
        Console.WriteLine($"Create relationship error: {e.Status}: {e.Message}");
    }
}

Em seguida, adicione o seguinte código ao final do Main método, para chamar o método e usar o CreateRelationship código que você acabou de escrever:

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

Na janela de comando, execute o programa com dotnet run. Na saída, procure instruções impressas dizendo que as duas relações foram criadas com êxito.

Os Gêmeos Digitais do Azure não permitirão que você crie um relacionamento se outro relacionamento com a mesma ID já existir, portanto, se você executar o programa várias vezes, verá exceções na criação de relacionamentos. Esse código captura as exceções e as ignora.

Listar relações

O próximo código que você adicionará permitirá que você veja a lista de relacionamentos que você criou.

Adicione o novo método seguinte à classe Program:

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

Em seguida, adicione o seguinte código ao final do Main método para chamar o ListRelationships código:

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

Na janela de comando, execute o programa com dotnet run. Você verá uma lista de todos os relacionamentos criados em uma instrução de saída com esta aparência:

Screenshot of a console showing the program output, which results in a message that lists the twin relationships.

Consultar gêmeos digitais

Uma característica principal dos Gêmeos Digitais do Azure é a capacidade de consultar seu gráfico gêmeo de forma fácil e eficiente para responder a perguntas sobre seu ambiente.

A última seção de código a ser adicionada neste tutorial executa uma consulta na instância do Azure Digital Twins. A consulta usada neste exemplo retorna todos os gêmeos digitais na instância.

Adicione esta using instrução para habilitar o JsonSerializer uso da classe para ajudar a apresentar as informações do gêmeo digital:

using System.Text.Json;

Em seguida, adicione o seguinte código ao final do Main método:

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

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

Na janela de comando, execute o programa com dotnet run. Você deve ver todos os gêmeos digitais neste caso na saída.

Nota

Depois de fazer uma alteração nos dados do gráfico, pode haver uma latência de até 10 segundos antes que as alterações sejam refletidas nas consultas.

A API do DigitalTwins reflete as alterações imediatamente, portanto, se você precisar de uma resposta instantânea, use uma solicitação de API (DigitalTwins GetById) ou uma chamada SDK (GetDigitalTwin) para obter dados gêmeos em vez de uma consulta.

Exemplo de código completo

Neste ponto do tutorial, você tem um aplicativo cliente completo que pode executar ações básicas nos Gêmeos Digitais do Azure. Para referência, o código completo do programa em Program.cs está listado abaixo:

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

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

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

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

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

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

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

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

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

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

Clean up resources (Limpar recursos)

Depois de concluir este tutorial, você pode escolher quais recursos deseja remover, dependendo do que deseja fazer em seguida.

  • Se você planeja continuar para o próximo tutorial, a instância usada neste tutorial pode ser reutilizada no próximo. Você pode manter os recursos do Azure Digital Twins configurados aqui e ignorar o restante desta seção.
  • Se você quiser continuar usando a instância do Azure Digital Twins deste artigo, mas limpar todos os seus modelos, gêmeos e relacionamentos, execute o seguinte comando az dt job deletion CLI:

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

    Se você quiser excluir apenas alguns desses elementos, poderá usar os comandos az dt twin relationship delete, az dt twin delete e az dt model delete para excluir seletivamente apenas os elementos que deseja remover.

  • Se você não precisar de nenhum dos recursos criados neste tutorial, poderá excluir a instância do Azure Digital Twins e todos os outros recursos deste artigo com o comando az group delete CLI. Isso exclui todos os recursos do Azure em um grupo de recursos, bem como o próprio grupo de recursos.

    Importante

    A eliminação de um grupo de recursos é irreversível. O grupo de recursos e todos os recursos nele contidos são eliminados permanentemente. Confirme que não elimina acidentalmente o grupo de recursos ou recursos errados.

    Abra o Azure Cloud Shell ou uma janela da CLI local e execute o seguinte comando para excluir o grupo de recursos e tudo o que ele contém.

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

Você também pode querer excluir a pasta do projeto de sua máquina local.

Próximos passos

Neste tutorial, você criou um aplicativo cliente de console .NET do zero. Você escreveu código para este aplicativo cliente para executar as ações básicas em uma instância do Azure Digital Twins.

Continue para o próximo tutorial para explorar as coisas que você pode fazer com esse aplicativo cliente de exemplo: