Partager via


Analyser et valider des modèles avec la bibliothèque d’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) basé sur JSON.

Après avoir créé un modèle, nous vous recommandons de valider vos modèles hors connexion avant de les charger dans votre 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’analyse 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. Cette bibliothèque peut être utilisée indépendamment de n’importe quel Kit de développement logiciel (SDK) Azure Digital Twins, en particulier pour la validation DTDL dans un visuel ou un éditeur de texte. Il est utile de s’assurer que vos fichiers de définition de modèle sont valides avant de tenter de les charger dans le service.

Pour utiliser la bibliothèque d’analyseur, vous lui fournissez 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 avoir disponibles localement, si votre client était chargé de les charger dans le service en premier lieu.

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

  1. Récupérez certains ou tous les documents DTDL du service.
  2. Transmettez les documents DTDL en mémoire retournés à l’analyseur.
  3. L’analyseur valide l’ensemble de documents transmis à celui-ci et retourne des informations d’erreur détaillées. Cette capacité est utile dans les scénarios d’éditeur.
  4. Utilisez les API d’analyseur pour continuer à analyser les modèles inclus dans l’ensemble de documents.

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

  • Obtenez toutes les interfaces de modèle implémentées (le contenu de la section extends de l’interface).
  • Obtenez toutes les propriétés, télémétrie, commandes, composants et 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 (extends sections).
  • Obtenez toutes les définitions de modèle complexes.
  • Déterminez si un modèle est assignable à partir d’un autre modèle.

Remarque

Les appareils IoT Plug-and-Play utilisent une petite variante de syntaxe pour décrire leurs fonctionnalités. Cette variante de syntaxe est un sous-ensemble sémantiquement compatible du DTDL utilisé dans Azure Digital Twins. Lorsque vous utilisez la bibliothèque d’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. L’analyseur retourne toujours, par défaut, le même modèle pour la syntaxe IoT Plug-and-Play et Azure Digital Twins.

Code avec la bibliothèque d’analyseur

Vous pouvez utiliser la bibliothèque d’analyseur directement, pour des éléments tels que la validation de modèles dans votre propre application ou la génération d’une interface utilisateur dynamique, pilotée par des modèles, des tableaux de bord et des rapports.

Pour prendre en charge l’exemple de code d’analyseur suivant, 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 d’analyseurs pour réfléchir à 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 :