Partager via


Analyser et valider des modèles avec la bibliothèque de l’analyseur DTDL

Cet article explique comment analyser et valider des modèles Azure Digital Twins à l’aide de la bibliothèque d’analyseur .NET.

Les modèles dans Azure Digital Twins sont définis à l’aide du langage DTDL (Digital Twins Definition Language) basé sur JSON-LD.

Après la création d’un modèle, il est recommandé de valider les modèles hors connexion avant de les charger sur une instance Azure Digital Twins.

Pour vous aider à valider vos modèles, une bibliothèque d’analyse DTDL côté client .NET est fournie sur NuGet : DTDLParser. Vous pouvez utiliser la bibliothèque d’analyseur directement dans votre code C#. Vous pouvez également afficher l’exemple d’utilisation de l’analyseur dans le DTDLParserResolveSample dans GitHub.

À propos de la bibliothèque d’analyseur .NET

La bibliothèque DTDLParser fournit un accès de modèle aux définitions DTDL, agissant essentiellement comme l’équivalent de la réflexion C# pour DTDL. Vous pouvez l’utiliser indépendamment du Kit de développement logiciel (SDK) Azure Digital Twins, en particulier pour la validation de DTDL dans un éditeur visuel ou de texte. Elle est utile pour s'assurer que vos fichiers de définition de modèle sont valides avant d'essayer de les charger vers le service.

Pour utiliser la bibliothèque de l’analyseur, vous devez lui fournir un ensemble de documents DTDL. En règle générale, vous récupérez ces documents de modèle à partir du service, mais vous pouvez également les rendre disponibles localement si votre client était initialement responsable de les charger sur le service.

Voici le flux de travail général pour l'utilisation de l'analyseur :

  1. Récupérez tout ou partie des documents DTDL du service.
  2. Transmettez les documents DTDL en mémoire retournés à l’analyseur.
  3. L’analyseur valide le jeu de documents qui lui est transmis et retourne des informations détaillées sur l’erreur. Cette fonctionnalité est utile dans des scénarios d’éditeur.
  4. Utilisez les API d’analyseurs pour poursuivre l’analyse des modèles inclus dans l’ensemble de documents.

Les fonctionnalités de l’analyseur sont les suivantes :

  • Obtenir toutes les interfaces de modèle implémentées (contenu de la section extends de l’interface).
  • Obtenir l’ensemble des propriétés, de la télémétrie, des commandes, des composants et des relations déclarés dans le modèle. Cette commande obtient également toutes les métadonnées incluses dans ces définitions et prend en compte l’héritage (sectionsextends).
  • Récupérer toutes les définitions de modèle complexes.
  • Déterminer si un modèle peut être assigné à partir d’un autre.

Remarque

Les appareils IoT Plug-and-Play utilisent une petite variante de syntaxe pour décrire leur fonctionnalité. Cette variante de syntaxe est un sous-ensemble sémantiquement compatible du langage DTDL utilisé dans Azure Digital Twins. Lorsque vous utilisez la bibliothèque de l’analyseur, vous n’avez pas besoin de savoir quelle variante de syntaxe a été utilisée pour créer le DTDL pour votre jumeau numérique. Par défaut, l’analyseur retourne toujours le même modèle pour la syntaxe IoT Plug-and-Play et Azure Digital Twins.

Coder avec la bibliothèque de l’analyseur

Vous pouvez utiliser la bibliothèque de l’analyseur directement, par exemple, pour valider des modèles dans votre propre application ou pour générer une interface utilisateur, des tableaux de bord et des rapports dynamiques basés sur des modèles.

Pour prendre en charge l’exemple de code de l’analyseur ci-dessous, considérez plusieurs modèles définis dans une instance Azure Digital Twins :

[
    {
      "@context": "dtmi:dtdl:context;3",
      "@id": "dtmi:com:contoso:coffeeMaker;1",
      "@type": "Interface",
      "contents": [
        {
          "@type": "Component",
          "name": "coffeeMaker",
          "schema": "dtmi:com:contoso:coffeeMakerInterface;1"
        }
      ]
    },
    {
      "@context": "dtmi:dtdl:context;3",
      "@id": "dtmi:com:contoso:coffeeMakerInterface;1",
      "@type": "Interface",
      "contents": [
        {
          "@type": "Property",
          "name": "waterTemp",
          "schema": "double"
        }
      ]
    },
    {
      "@context": "dtmi:dtdl:context;3",
      "@id": "dtmi:com:contoso:coffeeBar;1",
      "@type": "Interface",
      "contents": [
        {
          "@type": "Relationship",
          "name": "foo",
          "target": "dtmi:com:contoso:coffeeMaker;1"
        },
        {
          "@type": "Property",
          "name": "capacity",
          "schema": "integer"
        }
      ]
    }
  ]

Le code suivant montre un exemple d’utilisation de la bibliothèque de l’analyseur pour refléter ces définitions en C# :

using Azure;
using Azure.DigitalTwins.Core;
using DTDLParser;
using DTDLParser.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DigitalTwins_Samples
{
    public static class ListExtensions
    {
        public static async IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<T> input)
        {
            foreach (var value in input)
            {
                yield return value;
            }
            await Task.Yield();
        }
    }

    public class ParseModelsSample
    {
        public async Task ParseDemoAsync(DigitalTwinsClient client)
        {
            try
            {
                AsyncPageable<DigitalTwinsModelData> mdata = client.GetModelsAsync(new GetModelsOptions { IncludeModelDefinition = true });
                var models = new List<string>();
                await foreach (DigitalTwinsModelData md in mdata)
                    models.Add(md.DtdlModel);
                var parser = new ModelParser();
                IReadOnlyDictionary<Dtmi, DTEntityInfo> dtdlOM = await parser.ParseAsync(models.AsAsyncEnumerable());

                var interfaces = new List<DTInterfaceInfo>();
                IEnumerable<DTInterfaceInfo> ifenum =
                    from entity in dtdlOM.Values
                    where entity.EntityKind == DTEntityKind.Interface
                    select entity as DTInterfaceInfo;
                interfaces.AddRange(ifenum);
                foreach (DTInterfaceInfo dtif in interfaces)
                {
                    PrintInterfaceContent(dtif, dtdlOM);
                }
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed due to {ex}");
                throw;
            }
        }

        public void PrintInterfaceContent(DTInterfaceInfo dtif, IReadOnlyDictionary<Dtmi, DTEntityInfo> dtdlOM, int indent = 0)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < indent; i++) sb.Append("  ");
            Console.WriteLine($"{sb}Interface: {dtif.Id} | {dtif.DisplayName}");
            IReadOnlyDictionary<string, DTContentInfo> contents = dtif.Contents;

            foreach (DTContentInfo item in contents.Values)
            {
                switch (item.EntityKind)
                {
                    case DTEntityKind.Property:
                        DTPropertyInfo pi = item as DTPropertyInfo;
                        Console.WriteLine($"{sb}--Property: {pi.Name} with schema {pi.Schema}");
                        break;
                    case DTEntityKind.Relationship:
                        DTRelationshipInfo ri = item as DTRelationshipInfo;
                        Console.WriteLine($"{sb}--Relationship: {ri.Name} with target {ri.Target}");
                        break;
                    case DTEntityKind.Telemetry:
                        DTTelemetryInfo ti = item as DTTelemetryInfo;
                        Console.WriteLine($"{sb}--Telemetry: {ti.Name} with schema {ti.Schema}");
                        break;
                    case DTEntityKind.Component:
                        DTComponentInfo ci = item as DTComponentInfo;
                        Console.WriteLine($"{sb}--Component: {ci.Id} | {ci.Name}");
                        DTInterfaceInfo component = ci.Schema;
                        PrintInterfaceContent(component, dtdlOM, indent + 1);
                        break;                
                }
            }
        }
    }
}

Étapes suivantes

Une fois que vous avez terminé d’écrire vos modèles, découvrez comment les charger (et effectuer d’autres opérations de gestion) avec les API Azure Digital Twins Models :