Skip to content

Latest commit

 

History

History
168 lines (127 loc) · 6.26 KB

Tutorial04_InspectObjectModelAsync.md

File metadata and controls

168 lines (127 loc) · 6.26 KB

Inspect object model asynchronously

The ModelParser class is used to determine whether one or more DTDL models are valid, to identify specific modeling errors, and to enable inspection of model contents. This tutorial walks through the last of these uses: how to access elements and properties in the object model. A synchronous version of this tutorial is also available.

Create a ModelParser

To parse a DTDL model, you need to instantiate a ModelParser. No arguments are required.

var modelParser = new ModelParser();

Obtain the JSON text of a DTDL model

The DTDL language is syntactically JSON. The ModelParser expects a single string or an asynchronous enumeration of strings. The single string or each value in the enumeration is JSON text of a DTDL model.

string jsonText =
@"{
  ""@context"": ""dtmi:dtdl:context;3"",
  ""@id"": ""dtmi:example:anInterface;1"",
  ""@type"": ""Interface"",
  ""contents"": [
    {
      ""@type"": ""Property"",
      ""name"": ""expectedDistance"",
      ""schema"": ""double""
    },
    {
      ""@type"": ""Telemetry"",
      ""name"": ""currentDistance"",
      ""schema"": ""double""
    }
  ]
}";

Submit the JSON text to the ModelParser

The main asynchronous method on the ModelParser is ParseAsync(). One argument is required, which can be either a string or an asynchronous enumeration of strings containing the JSON text to parse as DTDL.

var parseTask = modelParser.ParseAsync(jsonText);

The return value is a Task, whose completion must be awaited before proceeding. If the submitted model is complete and valid, no exception will be thrown. Proper code should catch and process exceptions as shown in other tutorials such as this one, but for simplicity the present tutorial omits exception handling.

parseTask.Wait();
IReadOnlyDictionary<Dtmi, DTEntityInfo> objectModel = parseTask.Result;

Display elements in object model

The object model is a collection of objects in a class hierarchy rooted at DTEntityInfo. All DTDL elements derive from the DTDL abstract type Entity, and each DTDL type has a corresponding C# class whose name has a prefix of "DT" (for Digital Twins) and a suffix of "Info". The elements in the object model are indexed by their identifiers, which have type Dtmi. The following snippet displays the identifiers of all elements in the object model:

Console.WriteLine($"{objectModel.Count} elements in model:");
foreach (KeyValuePair<Dtmi, DTEntityInfo> modelElement in objectModel)
{
    Console.WriteLine(modelElement.Key);
}

For the JSON text above, this snippet displays:

4 elements in model:
dtmi:example:anInterface:_contents:__expectedDistance;1
dtmi:example:anInterface:_contents:__currentDistance;1
dtmi:example:anInterface;1
dtmi:dtdl:instance:Schema:double;2

Of these four identifiers, only dtmi:example:anInterface;1 is present in the DTDL source model. The identifiers for the contents named "expectedDistance" and "currentDistance" are auto-generated by the ModelParser following rules that guarantee their uniqueness. The identifier dtmi:dtdl:instance:Schema:double;2 represents an element in the DTDL language model for the schema 'double', as can be seen by using the ModelParser.GetTermOrUri() static method:

Console.WriteLine(ModelParser.GetTermOrUri(new Dtmi("dtmi:dtdl:instance:Schema:double;2")));

This snippet displays:

double

Drill down on one element

An individual element can be looked up in the object model by its identifier:

var anInterfaceId = new Dtmi("dtmi:example:anInterface;1");
var anInterface = (DTInterfaceInfo)objectModel[anInterfaceId];

The Interface in the DTDL model above has two 'contents' values, and these can been seen in the object model property Contents on the DTInterfaceInfo class:

foreach (KeyValuePair<string, DTContentInfo> contentElement in anInterface.Contents)
{
    Console.WriteLine($"name \"{contentElement.Key}\" => {contentElement.Value.Id}");
}

This snippet displays:

name "expectedDistance" => dtmi:example:anInterface:_contents:__expectedDistance;1
name "currentDistance" => dtmi:example:anInterface:_contents:__currentDistance;1

Drill down on property values of the element

The DTDL type of each element is expressed via the property EntityKind on the DTEntityInfo base class, which has type enum DTEntityKind:

foreach (KeyValuePair<string, DTContentInfo> contentElement in anInterface.Contents)
{
    Console.WriteLine($"name \"{contentElement.Key}\" => {contentElement.Value.EntityKind}");
}

This snippet displays:

name "expectedDistance" => Property
name "currentDistance" => Telemetry

Each of the content values can be accessed either by name via the Contents property on DTInterfaceInfo:

string expectedDistanceName = "expectedDistance";
var expectedDistance = (DTPropertyInfo)anInterface.Contents[expectedDistanceName];

Or by identifier via the object model:

Dtmi currentDistanceId = new Dtmi("dtmi:example:anInterface:_contents:__currentDistance;1");
var currentDistance = (DTTelemetryInfo)objectModel[currentDistanceId];

Both approaches yield the indicated element's object, from which other properties can be accessed, such as the schema of each content:

Console.WriteLine($"expectedDistance schema is {expectedDistance.Schema.Id}");
Console.WriteLine($"currentDistance schema is {currentDistance.Schema.Id}");

This snippet displays:

expectedDistance schema is dtmi:dtdl:instance:Schema:double;2
currentDistance schema is dtmi:dtdl:instance:Schema:double;2