Руководство. Написание кода с помощью пакета SDK для Azure Digital Twins

Разработчики, использующие Azure Digital Twins, часто создают клиентские приложения для взаимодействия со своим экземпляром службы Azure Digital Twins. Этот учебник предназначен для разработчиков и содержит вводные сведения о программировании для службы Azure Digital Twins с помощью пакета SDK Azure Digital Twins для .NET (C#). В нем пошагово описывается процесс написания консольного клиентского приложения на C# с самого начала.

  • Настройка проекта
  • Начало создания кода проекта
  • Полный пример кода
  • Очистка ресурсов
  • Следующие шаги

Необходимые компоненты

В этом учебнике по Azure Digital Twins настройка и работа над проектом выполняется в командной строке. Поэтому для выполнения упражнений вы можете использовать любой редактор кода.

Для начала работы вам потребуется следующее.

  • Любой редактор кода.
  • .NET Core 3.1 на вашем компьютере разработчика. Вы можете скачать эту версию пакета SDK .NET Core для нескольких платформ по этой ссылке: Загрузка .NET Core 3.1.

Подготовка экземпляра Azure Digital Twins

Для работы с Azure Digital Twins в этой статье потребуется экземпляр Azure Digital Twins и необходимые разрешения для его использования. Если у вас уже настроен экземпляр Azure Digital Twins, этот экземпляр можно использовать и перейти к следующему разделу. В противном случае выполните инструкции по настройке экземпляра и аутентификации. В инструкциях приводится информация, которая поможет вам убедиться, что вы успешно выполнили каждый шаг.

После настройки экземпляра запишите имя узла экземпляра. Вы можете найти имя хоста на портале Azure.

Настройка локальных учетных данных Azure

В этом примере используется DefaultAzureCredential (часть библиотеки Azure.Identity) для аутентификации пользователей с помощью экземпляра Azure Digital Twins, запускаемого на локальном компьютере. Дополнительные сведения о различных способах аутентификации клиентского приложения в Azure Digital Twins см. в статье о записи кода аутентификации приложения.

При использовании DefaultAzureCredential пример будет искать учетные данные в локальной среде, например имя для входа Azure в локальной версии Azure CLI, в Visual Studio либо Visual Studio Code. Поэтому вам нужно войти в Azure локально с помощью одного из этих механизмов, чтобы настроить учетные данные для примера.

Если вы используете Visual Studio или Visual Studio Code для выполнения примеров кода, убедитесь, что вы вошли в этот редактор с теми же учетными данными Azure, которые вы хотите использовать для доступа к экземпляру Azure Digital Twins. Если вы используете локальное окно CLI, выполните az login команду, чтобы войти в учетную запись Azure. После этого при запуске примера кода необходимо автоматически пройти проверку подлинности.

Настройка проекта

Когда вы будете готовы к работе со своим экземпляром Azure Digital Twins, начните с настройки проекта клиентского приложения.

Откройте окно консоли на компьютере и создайте пустой каталог проекта, в котором вы хотите сохранить работу в рамках этого руководства. Присвойте этому каталогу любое имя (например, DigitalTwinsCodeTutorial).

Перейдите в новый каталог.

В этом каталоге проекта создайте пустой проект консольного приложения .NET. В командном окне можно выполнить следующую команду, чтобы создать минимальный проект C# для консоли:

dotnet new console

Эта команда создаст несколько файлов в вашем каталоге, в том числе один с именем Program.cs, где вы будете писать большую часть своего кода.

Оставьте окно командной строки открытым, так как вы будете продолжать использовать его на протяжении всей работы с учебником.

Затем добавьте в проект две зависимости, которые понадобятся для работы с Azure Digital Twins. Первая — это пакет для пакета SDK Azure Digital Twins для .NET, вторая содержит средства для проверки подлинности в Azure.

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

Начало создания кода проекта

В этом разделе описано, как написать код для своего нового проекта приложения для работы с Azure Digital Twins. Вы будете писать код для следующих действий:

  • проверки подлинности в службе;
  • отправки модели;
  • выявления ошибок;
  • создания цифровых двойников;
  • создания связей;
  • выполнения запросов цифровых двойников.

В конце руководства есть раздел, в котором приведен полный код. Вы можете использовать его в качестве справки для проверки своей программы по мере ее создания.

Для начала откройте файл Program.cs в любом редакторе кода. Вы увидите минимальный шаблон кода, который выглядит следующим образом:

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

В первую очередь добавьте несколько строк using в верхней части кода, чтобы включить необходимые зависимости.

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

Далее вы будете добавлять в этот файл код для некоторых функций.

Проверка подлинности в службе

Первое, что должно будет делать ваше приложение, — это проходить проверку подлинности в службе Azure Digital Twins. Затем можно создать класс клиента службы для доступа к функциям пакета SDK.

Для аутентификации требуется имя узла экземпляра Azure Digital Twins.

В Program.cs вставьте следующий код под строкой печати Hello, World!" в методе Main . Задайте значение для имени узла экземпляра 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");

Сохраните файл.

В командном окне запустите этот код с помощью следующей команды:

dotnet run

Эта команда восстановит зависимости при первом запуске, а затем выполнит программу.

  • Если ошибка не возникает, программа выводит сообщение "Создан клиент службы — готов к работе".
  • В этом проекте ошибки пока не обрабатываются, и при их наличии вы увидите исключение, сгенерированное кодом.

Примечание.

В настоящее время существует известная проблема, влияющая на DefaultAzureCredential класс оболочки, которая может привести к ошибке при проверке подлинности. При возникновении этой проблемы можно попробовать создать экземпляр DefaultAzureCredential с помощью следующего необязательного параметра, чтобы устранить эту проблему: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });

Дополнительные сведения об этой проблеме см. в статье об известных проблемах Azure Digital Twins.

Отправка модели

В Azure Digital Twins отсутствует встроенный словарь домена. Типы элементов в вашей среде, которые вы можете представить в Azure Digital Twins, определяются вами с помощью моделей. Модели похожи на классы в объектно-ориентированных языках программирования. Они предоставляют определяемые пользователем шаблоны для цифровых двойников, экземпляры которых будут затем создаваться на основе этих шаблонов. Они написаны на языке, подобном JSON, который называется DTDL.

При создании решения Azure Digital Twins в первую очередь необходимо определить хотя бы одну модель в файле DTDL.

В каталоге, в котором вы создали проект, создайте файл JSON с именем SampleModel.json. Вставьте в этот файл следующий код:

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

Совет

Если для работы с этим учебником вы используете Visual Studio, можно выбрать только что созданный файл JSON и установить для свойства Копировать в выходной каталог в инспекторе свойств значение Копировать более позднюю версию или Копировать всегда. Это позволит Visual Studio найти файл JSON с путем по умолчанию, когда вы будете запускать программу клавишей F5 при работе с оставшейся частью учебника.

Совет

Вы можете проверка документы модели, чтобы убедиться, что DTDL является допустимым с помощью библиотеки DTDLParser. Дополнительные сведения об использовании этой библиотеки см. в разделе "Анализ и проверка моделей".

Теперь добавьте еще немного кода в Program.cs, чтобы отправить созданную модель в свой экземпляр Azure Digital Twins.

Сначала добавьте несколько инструкций using в начало файла:

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

Затем подготовьте использование асинхронных методов в пакете SDK службы C#, изменив сигнатуру метода Main, чтобы разрешить асинхронное выполнение.

static async Task Main(string[] args)
{

Примечание.

Использование async не является строго обязательным, так как пакет SDK предоставляет также и синхронные версии всех вызовов. В упражнениях этого учебника используется async.

Далее идет первый фрагмент кода, который взаимодействует со службой Azure Digital Twins. Этот код загружает с диска созданный вами файл DTDL и отправляет его в ваш экземпляр службы Azure Digital Twins.

Вставьте следующий код под кодом проверки подлинности, который вы добавили ранее.

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

В командном окне запустите программу с помощью следующей команды:

dotnet run

В выходных данных появится текст "Отправить модель", указывающий на выполнение этого фрагмента кода. Но выходные данные, в которых сообщается об успешности отправки, пока отсутствуют.

Чтобы добавить вывод сообщения об успешности отправки всех моделей в экземпляр, добавьте следующий код сразу после предыдущего раздела:

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

Прежде чем снова запустить программу для проверки этого нового кода, вспомните, что в последний раз, когда программа запускалась, вы уже отправили свою модель. В Azure Digital Twins нельзя отправить одну и ту же модель дважды, — когда вы попытаетесь сделать это, программа выдаст исключение.

Учитывая эту информацию, запустите программу еще раз с помощью следующей команды в своем командном окне:

dotnet run

Программа должна выдать исключение. Когда вы пытаетесь отправить уже отправленную модель, служба возвращает через REST API ошибку "неверный запрос". В результате пакет SDK клиента Azure Digital Twins, в свою очередь, генерирует исключение для каждого кода возврата службы, кроме успешного.

В следующем разделе говорится об исключениях, подобных этому, и о том, как обрабатывать их в вашем коде.

Перехват ошибок

Чтобы предотвратить сбой программы, можно добавить код исключения вокруг кода отправки модели. Заключите существующий клиентский вызов await client.CreateModelsAsync(typeList) в обработчик 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}");
}

Снова запустите программу в dotnet run командном окне. Вы увидите, что вы вернетесь к дополнительным сведениям о проблеме отправки модели, включая код ошибки, указывающий на это ModelIdAlreadyExists.

Начиная с этого момента все вызовы методов службы в этом учебнике будут заключаться в обработчики try/catch.

Создание цифровых двойников

Теперь, когда модель отправлена в Azure Digital Twins, вы можете использовать это определение модели для создания цифровых двойников. Цифровые двойники являются экземплярами модели и представляют сущности в вашей бизнес-среде — такие как датчики на ферме, комнаты в здании или фары автомобиля. В этом разделе создается несколько цифровых двойников на основе модели, которую вы отправили ранее.

Затем добавьте следующий код в конец метода Main, чтобы создать и инициализировать три цифровых двойника на основе этой модели.

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

В командном окне запустите программу с помощью команды dotnet run. В выходных данных найдите сообщения о том, что sampleTwin-0, sampleTwin-1 и sampleTwin-2 созданы.

Затем снова выполните программу.

Обратите внимание, что при повторном создании двойников ошибки не возникают, даже если двойники уже существуют после первого запуска. В отличие от создания модели, создание двойников на уровне REST — это вызов PUT с семантикой upsert. Использование этого типа вызова REST означает, что попытка повторного создания уже имеющегося двойника приведет к замене исходного двойника. Сообщение об ошибке при этом не выводится.

Создание отношений

Далее вы можете создать связи между этими двойниками, чтобы подключить их к графу двойников. Графы двойников используются для представления всей вашей среды.

Добавьте новый статический метод в Program класс Main под методом (код теперь имеет два метода):

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

Затем добавьте следующий код в конец метода Main, чтобы вызвать метод CreateRelationship и использовать только что написанный код:

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

В командном окне запустите программу с помощью команды dotnet run. В выходных данных найдите сведения об успешном создании двух связей.

В Azure Digital Twins нельзя создать связь, если связь с таким идентификатором уже существует. Поэтому если вы запустите программу несколько раз, при создании связи возникнут исключения. Этот код перехватывает исключения и игнорирует их.

Список связей

Следующий код, который вы добавите, позволит увидеть список созданных связей.

Добавьте в класс 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}");
    }
}

Затем добавьте следующий код в конец метода Main для вызова кода ListRelationships:

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

В командном окне запустите программу с помощью команды dotnet run. Отобразится список всех созданных вами связей в выходных данных. Он будет выглядеть так:

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

Запрашивание цифровых двойников

Главной особенностью Azure Digital Twins является возможность просто и эффективно запрашивать граф двойников, чтобы получать ответы о вашей среде.

В последнем разделе кода, который вы добавите в этом учебнике, выполняется запрос к экземпляру Azure Digital Twins. Запрос, используемый в этом примере, возвращает все цифровые двойники в экземпляре.

Добавьте этот оператор using, чтобы обеспечить использование класса JsonSerializer для представления сведений о цифровом двойнике:

using System.Text.Json;

Затем добавьте следующий код в конец метода Main:

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

В командном окне запустите программу с помощью команды dotnet run. В выходных данных должны быть указаны все цифровые двойники в этом экземпляре.

Примечание.

После внесения изменений в данные в графе может возникнуть задержка до 10 секунд, прежде чем изменения будут отражены в запросах.

API DigitalTwins отражает изменения немедленно, поэтому, если вам нужен мгновенный ответ, используйте запрос API (DigitalTwins GetById) или вызов пакета SDK (GetDigitalTwin) для получения данных двойника вместо запроса.

Полный пример кода

На этом этапе у вас есть готовое клиентское приложение, которое может выполнять базовые действия в Azure Digital Twins. Для справки ниже приведен полный код программы в файле Program.cs.

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>
    }
}

Очистка ресурсов

По завершении работы с этим руководством вы можете выбрать ресурсы, которые нужно удалить, в зависимости от планируемых действий.

  • Если в планируете перейти к следующему руководству, экземпляр из текущего руководства можно использовать при работе со следующим. Вы можете оставить настроенные здесь ресурсы Azure Digital Twins и пропустить оставшуюся часть этого раздела.
  • Если вы хотите продолжить использование экземпляра Azure Digital Twins из этой статьи, но удалите все его модели, двойники и связи, выполните следующую команду az dt job deletion CLI:

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

    Если требуется удалить только некоторые из этих элементов, можно использовать az dt twin relationship delete, az dt twin delete и az dt model delete , чтобы выборочно удалить только те элементы, которые нужно удалить.

  • Если вам не нужен какой-либо из ресурсов, созданных в этом руководстве, можно удалить экземпляр Azure Digital Twins и все остальные ресурсы из этой статьи с помощью команды az group delete CLI. При этом будут удалены все ресурсы Azure в группе ресурсов, а также сама группа.

    Важно!

    Удаление группы ресурсов — процесс необратимый. Группа ресурсов и все содержащиеся в ней ресурсы удаляются без возможности восстановления. Будьте внимательны, чтобы случайно не удалить не ту группу ресурсов или не те ресурсы.

    Откройте Azure Cloud Shell или локальное окно CLI и выполните следующую команду, чтобы удалить группу ресурсов и все, что она содержит.

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

Также, возможно, потребуется удалить папку проекта с вашего локального компьютера.

Следующие шаги

В этом руководстве вы с нуля создали консольное клиентское приложение консоли .NET. Вы написали код для этого клиентского приложения, чтобы выполнять базовые действия в экземпляре Azure Digital Twins.

Перейдите к следующему учебнику, чтобы изучить действия, которые можно выполнять с помощью такого примера клиентского приложения: