Condividi tramite


Analizzare e convalidare i modelli con la libreria di parser DTDL

Questo articolo descrive come analizzare e convalidare i modelli di Gemelli digitali di Azure usando la libreria parser .NET.

I modelli in Gemelli digitali di Azure vengono definiti usando il linguaggio DTDL (Digital Twin Definition Language) basato su JSON-LD.

Dopo aver creato un modello, è consigliabile convalidare i modelli offline prima di caricarli nell'istanza di Gemelli digitali di Azure.

Per convalidare i modelli, viene fornita una libreria di analisi DTDL sul lato client .NET in NuGet: DTDLParser. È possibile usare la libreria parser direttamente nel codice C#. È anche possibile visualizzare l'uso di esempio del parser in DTDLParserResolveSample in GitHub.

Informazioni sulla libreria parser .NET

La libreria DTDLParser fornisce l'accesso al modello alle definizioni DTDL, essenzialmente fungendo da equivalente alla reflection C# per DTDL. Questa libreria può essere usata indipendentemente da qualsiasi SDK di Gemelli digitali di Azure, in particolare per la convalida DTDL in un oggetto visivo o in un editor di testo. È utile assicurarsi che i file di definizione del modello siano validi prima di provare a caricarli nel servizio.

Per usare la libreria del parser, specificare un set di documenti DTDL. In genere, è possibile recuperare questi documenti del modello dal servizio, ma è anche possibile che siano disponibili in locale, se il client è responsabile del caricamento nel servizio in primo luogo.

Ecco il flusso di lavoro generale per l'uso del parser:

  1. Recuperare alcuni o tutti i documenti DTDL dal servizio.
  2. Passare i documenti DTDL restituiti in memoria al parser.
  3. Il parser convaliderà il set di documenti passati e restituirà informazioni dettagliate sull'errore. Questa funzionalità è utile negli scenari dell'editor.
  4. Usare le API del parser per continuare ad analizzare i modelli inclusi nel set di documenti.

Le funzionalità del parser includono:

  • Ottenere tutte le interfacce del modello implementate (il contenuto della sezione dell'interfaccia extends ).
  • Ottenere tutte le proprietà, i dati di telemetria, i comandi, i componenti e le relazioni dichiarati nel modello. Questo comando ottiene anche tutti i metadati inclusi in queste definizioni e prende in considerazione l'ereditarietà (extends sezioni).
  • Ottenere tutte le definizioni di modello complesse.
  • Determinare se un modello è assegnabile da un altro modello.

Nota

Plug and Play IoT dispositivi usano una piccola variante di sintassi per descrivere le funzionalità. Questa variante di sintassi è un subset compatibile semanticamente del DTDL usato in Gemelli digitali di Azure. Quando si usa la libreria parser, non è necessario sapere quale variante di sintassi è stata usata per creare il DTDL per il gemello digitale. Il parser restituirà sempre, per impostazione predefinita, lo stesso modello sia per Plug and Play IoT che per la sintassi di Gemelli digitali di Azure.

Codice con la libreria del parser

È possibile usare direttamente la libreria del parser, per elementi come la convalida dei modelli nella propria applicazione o per la generazione di interfaccia utente dinamica, basata su modello, dashboard e report.

Per supportare l'esempio di codice del parser riportato di seguito, considerare diversi modelli definiti in un'istanza di Gemelli digitali di Azure:

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

Il codice seguente illustra un esempio di come usare la libreria parser per riflettere su queste definizioni in 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;                
                }
            }
        }
    }
}

Passaggi successivi

Dopo aver scritto i modelli, vedere come caricarli (ed eseguire altre operazioni di gestione) con le API Dei modelli di Gemelli digitali di Azure: