Administración de Digital Twins

Las entidades de su entorno se representan mediante gemelos digitales. La administración de los gemelos digitales puede incluir la creación, modificación y eliminación.

Este artículo se centra en la administración de gemelos digitales. Para trabajar con relaciones y con el grafo de gemelos en conjunto, consulte Administración del grafo de gemelos y las relaciones.

Sugerencia

Todas las funciones del SDK cuentan con versiones sincrónicas y asincrónicas.

Requisitos previos

Para poder seguir los pasos que se describen en este artículo y trabajar con Azure Digital Twins, es preciso configurar una instancia de Azure Digital Twins y los permisos necesarios para usarla. Si ya tiene una instancia configurada de Azure Digital Twins, puede usarla y pasar a la sección siguiente. De lo contrario, siga las instrucciones que se indican en Configuración de una instancia y autenticación. Las instrucciones contienen información que le ayudará a comprobar que ha completado cada paso correctamente.

Una vez configurada la instancia, anote el nombre de host de esta. El nombre de host se encuentra en Azure Portal.

Interfaces para desarrolladores

En este artículo se describe cómo completar diferentes operaciones de administración con el SDK de .NET (C#). También puede crear estas mismas llamadas de administración con los otros SDK de lenguaje descritos en API y SDK de Azure Digital Twins.

Otras interfaces de desarrollador que se pueden usar para completar estas operaciones incluyen:

Visualización

Azure Digital Twins Explorer es una herramienta visual para explorar los datos en el grafo de Azure Digital Twins. Puede usar el explorador para ver, consultar y editar los modelos, los gemelos y las relaciones.

Para obtener información sobre la herramienta Azure Digital Twins Explorer, vea Azure Digital Twins Explorer. Para obtener pasos detallados sobre el uso de sus características, consulte Uso de Azure Digital Twins Explorer.

Este es el aspecto de la visualización:

Screenshot of Azure Digital Twins Explorer showing sample models and twins.

Creación de un gemelo digital

Para crear un gemelo, use el método CreateOrReplaceDigitalTwinAsync() en el cliente de servicio de la siguiente manera:

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

Para crear un gemelo digital, debe proporcionar lo siguiente:

  • Un valor de identificador que quiere asignar al gemelo digital (definirá ese identificador al crear el gemelo).
  • El modelo que quiere usar.
  • Cualquier inicialización deseada de datos gemelos, incluidos...
    • Propiedades (inicialización opcional): si lo desea, puede establecer los valores iniciales de las propiedades del gemelo digital. Las propiedades se tratan como opcionales y se pueden establecer más adelante, pero tenga en cuenta que no aparecerán como parte de un gemelo hasta que se hayan establecido.
    • Componentes (inicialización necesaria si están presentes en un gemelo): si el gemelo contiene componentes, se tendrán que inicializar al crearlo. Pueden ser objetos vacíos, pero los componentes en sí deben existir.

El modelo y los valores iniciales de las propiedades se proporcionan mediante el parámetro initData, que es una cadena JSON que contiene los datos pertinentes. Para más información sobre cómo estructurar este objeto, vaya a la sección siguiente.

Sugerencia

Después de crear o actualizar un gemelo, puede haber una latencia de hasta 10 segundos antes de que los cambios se reflejen en las consultas. La API GetDigitalTwin (que se describe más adelante en este artículo) no experimenta este retraso, por lo que debe usar la llamada a la API en lugar de realizar una consulta para ver los gemelos recién creados si necesita una respuesta instantánea.

Inicialización del modelo y las propiedades

Puede inicializar las propiedades de un gemelo en el momento en que este se crea.

La API de creación de gemelos acepta un objeto serializado en una descripción JSON válida de las propiedades gemelas. Consulte Gemelos digitales y el grafo de gemelos para obtener una descripción del formato JSON de un gemelo.

En primer lugar, puede crear un objeto de datos para representar el gemelo y los datos de sus propiedades. Puede crear un objeto de parámetro manualmente o mediante una clase auxiliar proporcionada. Este es un ejemplo de cada uno.

Creación de gemelos con datos creados manualmente

Sin el uso de ninguna clase auxiliar personalizada, puede representar las propiedades de un gemelo en un elemento Dictionary<string, object>, donde string es el nombre de la propiedad y object es un objeto que representa la propiedad y su 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}");
    }
}

Creación de gemelos con la clase auxiliar

La clase auxiliar BasicDigitalTwin permite almacenar los campos de propiedades directamente en un objeto "gemelo". Es posible que desee compilar la lista de propiedades mediante un Dictionary<string, object>, que luego se puede agregar al objeto gemelo como su CustomProperties directamente.

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:

Los objetos BasicDigitalTwin contienen un campo Id. Puede dejar este campo vacío, pero si agrega un valor de id., debe coincidir con el parámetro de id. pasado a la llamada CreateOrReplaceDigitalTwinAsync(). Por ejemplo:

twin.Id = "myRoomId";

Creación de gemelos de forma masiva con la API de importación de trabajos

Puede usar import Jobs API para crear muchos gemelos a la vez en una sola llamada API. Este método requiere el uso de Azure Blob Storage y permisos de escritura en la instancia de Azure Digital Twins para gemelos y trabajos masivos.

Sugerencia

La API De trabajos de importación también permite importar modelos y relaciones en la misma llamada, para crear todas las partes de un grafo a la vez. Para obtener más información sobre este proceso, consulte Carga de modelos, gemelos y relaciones de forma masiva con la API de importación de trabajos.

Para importar gemelos de forma masiva, debe estructurar los gemelos (y cualquier otro recurso incluido en el trabajo de importación masiva) como un archivo NDJSON . La Twins sección viene después de la Models sección (y antes de la Relationships sección). Los gemelos definidos en el archivo pueden hacer referencia a modelos que se definen en este archivo o que ya están presentes en la instancia y, opcionalmente, pueden incluir la inicialización de las propiedades del gemelo.

Puede ver un archivo de importación de ejemplo y un proyecto de ejemplo para crear estos archivos en la introducción a la API de trabajos de importación.

A continuación, el archivo debe cargarse en un blob en anexos en Azure Blob Storage. Para obtener instrucciones sobre cómo crear un contenedor de Azure Storage, consulte Creación de un contenedor. A continuación, cargue el archivo mediante el método de carga preferido (algunas opciones son el comando AzCopy, la CLI de Azure o Azure Portal).

Una vez cargado el archivo NDJSON en el contenedor, obtenga su dirección URL dentro del contenedor de blobs. Usará este valor más adelante en el cuerpo de la llamada API de importación masiva.

Esta es una captura de pantalla que muestra el valor de dirección URL de un archivo de blob en Azure Portal:

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

A continuación, el archivo se puede usar en una llamada API de trabajos de importación. Proporcione la dirección URL de almacenamiento de blobs del archivo de entrada y una nueva dirección URL de almacenamiento de blobs para indicar dónde desea que se almacene el registro de salida después de que el servicio lo cree.

Obtención de datos para un gemelo digital

Puede acceder a los detalles de cualquier gemelo digital mediante una llamada al método GetDigitalTwin(), como se describe a continuación:

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

Esta llamada devuelve los datos del gemelo en forma de un tipo de objeto fuertemente tipado, como BasicDigitalTwin. BasicDigitalTwin es una clase auxiliar de serialización incluida con el SDK, que devuelve los metadatos y propiedades principales del gemelo en formato preparado. Siempre puede deserializar los datos gemelos mediante la biblioteca JSON que prefiera, como System.Text.Json o Newtonsoft.Json. Las clases auxiliares hacen más cómodo el acceso básico a un gemelo.

Nota:

BasicDigitalTwin utiliza atributos System.Text.Json. Para usar BasicDigitalTwin con el elemento DigitalTwinsClient, debe inicializar el cliente con el constructor predeterminado, o bien, si desea personalizar la opción del serializador, use JsonObjectSerializer.

La clase de asistente de BasicDigitalTwin también proporciona acceso a las propiedades definidas en el gemelo, a través de un Dictionary<string, object>. Para enumerar las propiedades del gemelo, puede 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}");
}

Solo se devuelven las propiedades que se han establecido al menos una vez cuando se recupera un gemelo con el método GetDigitalTwin().

Sugerencia

El displayName para un gemelo es parte de sus metadatos del modelo, por lo que no se mostrará al obtener los datos de la instancia gemela. Para ver este valor, puede recuperarlo del modelo.

Para recuperar varios gemelos mediante una sola llamada API, consulte los ejemplos de Query API en Consulta del grafo de gemelos.

Tenga en cuenta el siguiente modelo (escrito en el Lenguaje de definición de gemelos digitales (DTDL)) que define un objeto Moon:

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

El resultado de llamar a object result = await client.GetDigitalTwinAsync("my-moon"); un gemelo de tipo Luna podría tener este aspecto:

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

Las propiedades definidas del gemelo digital se devuelven como propiedades de nivel superior en el gemelo digital. Los metadatos o la información del sistema que no forman parte de la definición de DTDL se devuelven con un prefijo $. Las propiedades de metadatos incluyen los valores siguientes:

  • $dtId: el identificador del gemelo digital en esta instancia de Azure Digital Twins
  • $etag: un campo HTTP estándar asignado por el servidor web. Esto se actualiza a un nuevo valor cada vez que se actualiza el gemelo, lo que puede resultar útil para determinar si los datos del gemelo se han actualizado en el servidor desde una comprobación anterior. Puede usar If-Match para realizar las actualizaciones y eliminaciones que solo se completan si el valor ETag de la entidad coincide con el valor ETag proporcionado. Para obtener más información sobre estas operaciones, consulte la documentación de DigitalTwins Update y DigitalTwins Delete.
  • $metadata: un conjunto de propiedades de metadatos, que puede incluir lo siguiente:
    • $model, el DTMI del modelo del gemelo digital.
    • lastUpdateTime para las propiedades del gemelo. Se trata de una marca de tiempo que indica la fecha y hora en que Azure Digital Twins procesó el mensaje de actualización de la propiedad.
    • sourceTime para las propiedades del gemelo. Se trata de una propiedad opcional y grabable que representa la marca de tiempo cuando se observó la actualización de la propiedad en el mundo real.

Puede obtener más información sobre los campos contenidos en un gemelo digital en formato JSON de gemelo digital. Puede obtener más información sobre las clases auxiliares de serialización como BasicDigitalTwin en API y SDK de Azure Digital Twins.

Visualización de todos los gemelos digitales

Para ver todos los gemelos digitales de la instancia, use una consulta. Puede ejecutar una consulta con las API de consulta o los comandos de la CLI.

Este es el cuerpo de la consulta básica que devuelve una lista de todos los gemelos digitales de la instancia:

SELECT * FROM DIGITALTWINS

Actualización de un gemelo digital

Para actualizar las propiedades de un gemelo digital, escriba la información que quiere reemplazar en formato de revisión de JSON. Para obtener una lista completa de las operaciones de la revisión de JSON que se pueden usar, como replace, add yremove, consulte las operaciones de la revisión de JSON.

Después de crear el documento de revisión de JSON que contiene información de actualización, pase el documento al método UpdateDigitalTwin():

await client.UpdateDigitalTwinAsync(twinId, updateTwinData);

Una sola llamada de revisión puede actualizar tantas propiedades de un solo gemelo como se quiera (incluso todas ellas). Si necesita actualizar las propiedades en varios gemelos, necesita una llamada de actualización independiente para cada gemelo.

Sugerencia

Después de crear o actualizar un gemelo, puede haber una latencia de hasta 10 segundos antes de que los cambios se reflejen en las consultas. La API de GetDigitalTwin (que se describe anteriormente en este artículo) no experimenta este retraso, por lo que debe usar la llamada API en lugar de realizar una consulta para ver los gemelos recién actualizados si necesita una respuesta instantánea.

Este es un ejemplo de código de revisión de JSON. En este documento se reemplazan los valores de las propiedades mass y radius del gemelo digital al que se aplica. En este ejemplo se muestra la operación replace de la revisión de JSON, que reemplaza el valor de una propiedad existente.

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

Al actualizar un gemelo a partir de un proyecto de código mediante el SDK de .NET, puede crear revisiones de JSON mediante la clase JsonPatchDocument del SDK de .NET para Azure. Este es un ejemplo de cómo crear un documento de revisión de JSON y usar UpdateDigitalTwin() en el código del proyecto.

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

Sugerencia

Puede mantener las marcas de tiempo de origen en los gemelos digitales actualizando el campo $metadata.<property-name>.sourceTime con el proceso descrito en esta sección. Para obtener más información sobre este campo y otros campos que se pueden escribir en gemelos digitales, consulte Formato JSON de gemelo digital.

Actualización de las subpropiedades en los componentes de gemelos digitales

Recuerde que un modelo puede contener componentes, lo que permite que se compone de otros modelos.

Para revisar las propiedades de los componentes de un gemelo digital, puede usar la sintaxis de ruta de acceso en la revisión de JSON:

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

Actualización de las subpropiedades en las propiedades de tipo objeto

Los modelos pueden contener propiedades que son de un tipo de objeto. Esos objetos pueden tener sus propias propiedades y es posible que desee actualizar una de esas subpropiedades que pertenecen a la propiedad de tipo de objeto. Este proceso es similar al proceso para actualizar las subpropiedades en los componentes, pero puede requerir algunos pasos adicionales.

Considere un modelo con una propiedad de tipo objeto, ObjectProperty. ObjectProperty tiene una propiedad de cadena denominada StringSubProperty.

Cuando se crea un gemelo con este modelo, no es necesario crear una instancia de ObjectProperty en ese momento. Si no se crea una instancia de la propiedad de objeto al crearse el gemelo, tampoco se crea una ruta de acceso predeterminada para acceder a ObjectProperty y su StringSubProperty para una operación de revisión. Debe agregar la ruta de acceso a ObjectProperty sí mismo para poder actualizar sus propiedades.

Esto se puede hacer con una operación de revisión add de JSON, como la siguiente:

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

Nota:

Si ObjectProperty tiene más de una propiedad, debe incluirlas todas en el campo value de esta operación, aunque solo vaya a actualizar una:

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

Una vez hecho esto, existe una ruta de acceso a StringSubProperty, que a partir de ahora se podrá actualizar directamente con una operación replace típica:

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

Aunque el primer paso no es necesario en los casos ObjectProperty en los que se creó una instancia del gemelo, se recomienda usarlo cada vez que actualice una subpropiedad por primera vez, ya que es posible que no siempre sepa con certeza si la propiedad del objeto se creó inicialmente o no.

Actualización de un modelo de gemelo digital

La función UpdateDigitalTwin() también puede usarse para migrar un gemelo digital a un modelo diferente.

Por ejemplo, tenga en cuenta el siguiente documento de revisión de JSON que reemplaza el campo $model de los metadatos del gemelo digital:

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

Esta operación solo se realiza correctamente si el gemelo digital modificado por la revisión se ajusta al nuevo modelo.

Considere el ejemplo siguiente:

  1. Imagine un gemelo digital con un modelo de foo_old. foo_old define una masa de propiedad necesaria.
  2. El nuevo modelo foo_new define una masa de propiedades y agrega una nueva temperatura de propiedad necesaria.
  3. Después de la revisión, el gemelo digital debe tener ambas propiedades mass y temperature.

La revisión para esta situación debe actualizar tanto el modelo como la propiedad temperature del gemelo, de la siguiente manera:

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

Actualización del valor sourceTime de una propiedad

Opcionalmente, puede decidir usar el sourceTime campo en las propiedades gemelas para registrar marcas de tiempo para cuando se observan actualizaciones de propiedades en el mundo real. Azure Digital Twins admite de forma nativa sourceTime en los metadatos de cada propiedad de gemelos. El valor sourceTime debe cumplir con el formato de fecha y hora ISO 8601. Para obtener más información sobre este campo y otros campos en gemelos digitales, consulte Formato JSON de gemelo digital.

La versión estable mínima de la API de REST para admitir este campo es la del 31-05-2022. Para trabajar con este campo mediante los SDK de Azure Digital Twins, se recomienda usar la versión más reciente del SDK para asegurarse de que este campo esté incluido.

Este es un ejemplo de un documento de revisión de JSON que actualiza el valor y el campo sourceTime de una propiedad Temperature:

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

Para actualizar el campo sourceTime de una propiedad que forma parte de un componente, incluya el componente al principio de la ruta de acceso. En el ejemplo anterior, podría hacer esto cambiando el valor de ruta de /$metadata/Temperature/sourceTime a myComponent/$metadata/Temperature/sourceTime.

Nota:

Si actualiza sourceTime y el valor en una propiedad y, después, solo actualiza el valor de la propiedad, se conservará la marca de tiempo sourceTime de la primera actualización.

Control de las llamadas de actualización en conflicto

Azure Digital Twins garantiza que todas las solicitudes entrantes se procesan una tras otra. Esto significa que, incluso para el caso de que varias funciones intenten actualizar la misma propiedad en un gemelo al mismo tiempo, no es necesario que escriba código de bloqueo explícito para controlar el conflicto.

Este comportamiento se basa en cada gemelo.

Por ejemplo, imagine un escenario en el que llegan estas tres llamadas al mismo tiempo:

  • Escribir propiedad A en Gemelo1
  • Escribir propiedad B en Gemelo1
  • Escribir propiedad A en Gemelo2

Las dos llamadas que modifican Gemelo1 se ejecutan una tras otra, y se generan mensajes para cada cambio. La llamada a modificar Twin2 se puede ejecutar simultáneamente sin ningún conflicto, tan pronto como llegue.

Eliminación de un gemelo digital

Puede eliminar gemelos con el método DeleteDigitalTwin(). Sin embargo, solo puede eliminar un gemelo si este no tiene más relaciones. Por lo tanto, elimine primero las relaciones de entrada y salida del gemelo.

Este es un ejemplo del código para eliminar gemelos y sus relaciones. La llamada al SDK DeleteDigitalTwin está resaltada para aclarar dónde se encuentra en el contexto de un ejemplo más amplio.

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

Eliminación de todos los gemelos digitales

Para obtener un ejemplo de cómo eliminar todos los gemelos a la vez, descargue la aplicación de ejemplo que se usa en Exploración de los conceptos básicos mediante una aplicación cliente de ejemplo. El archivo CommandLoop.cs realiza esta acción en una función CommandDeleteAllTwins().

Nota:

Si desea eliminar todos los modelos, gemelos y relaciones de una instancia a la vez, use la API Eliminar trabajos.

Ejemplo de código de gemelo digital ejecutable

Puede usar el ejemplo de código ejecutable siguiente para crear un gemelo, actualizar sus detalles y eliminar el gemelo.

Configuración de archivos del proyecto de ejemplo

El fragmento de código usa una definición de modelo de ejemplo Room.json. Para descargar el archivo del modelo a fin de poder usarlo en el código, use este vínculo para ir directamente a él en GitHub. Luego haga clic con el botón derecho en cualquier lugar de la pantalla, seleccione Guardar como en el menú contextual del explorador y use la ventana Guardar como para guardar el archivo como Room.json.

Después cree un nuevo proyecto de aplicación de consola en Visual Studio o el editor que prefiera.

Luego copie el código siguiente del ejemplo ejecutable en el proyecto:

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:

Actualmente hay un problema conocido que afecta a la clase contenedora DefaultAzureCredential que puede dar lugar a un error durante la autenticación. Si se produce este problema, puede intentar crear instancias de DefaultAzureCredential con el siguiente parámetro opcional para resolverlo: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });

Para más información sobre este problema, consulte Problemas conocidos de Azure Digital Twins.

Configurar proyecto

Luego siga estos pasos para configurar el código del proyecto:

  1. Agregue el archivo Room.json descargado anteriormente al proyecto y reemplace el marcador de posición <path-to> en el código para indicar al programa dónde encontrarlo.

  2. Reemplace el marcador de posición <your-instance-hostname> por el nombre de host de la instancia de Azure Digital Twins.

  3. Agregue dos dependencias al proyecto que son necesarios para trabajar con Azure Digital Twins. La primera es el paquete del SDK de Azure Digital Twins para .NET y la segunda proporciona herramientas para ayudar con la autenticación en Azure.

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

También debe configurar las credenciales locales si desea ejecutar el ejemplo directamente. La siguiente sección le indicará cómo hacerlo.

Configuración de credenciales locales de Azure

En este ejemplo se usa DefaultAzureCredential (parte de la biblioteca de Azure.Identity) para autenticar a los usuarios mediante la instancia de Azure Digital Twins cuando la ejecuta en la máquina local. Para más información sobre las distintas formas en que una aplicación cliente puede autenticarse con Azure Digital Twins, consulte Escritura de código de autenticación de aplicación.

Con DefaultAzureCredential, el ejemplo buscará las credenciales en el entorno local; por ejemplo, un inicio de sesión de Azure en una DefaultAzureCredential local o en Visual Studio o Visual Studio Code. Por este motivo, debe iniciar sesión en Azure localmente mediante uno de estos mecanismos para configurar las credenciales del ejemplo.

Si usa Visual Studio o Visual Studio Code para ejecutar códigos de ejemplo, asegúrese de que inicia sesión en ese editor con las mismas credenciales de Azure que quiere usar para acceder a la instancia de Azure Digital Twins. Si usa una ventana local de la CLI, ejecute el comando az login para iniciar sesión en la cuenta de Azure. Después de ejecutar el código de ejemplo, debería autenticarse automáticamente.

Ejecución del ejemplo

Ahora que se ha completado la instalación, puede ejecutar el proyecto de código de ejemplo.

Esta es la salida de la consola del programa anterior:

Screenshot of the console output showing that the twin is created, updated, and deleted.

Pasos siguientes

Consulte cómo crear y administrar relaciones entre los gemelos digitales: