Exemple #1
0
        private async Task CreateFactoryAsync()
        {
            _logger.LogInformation("Creating Factory...");

            var twinData = new BasicDigitalTwin();

            twinData.Metadata.ModelId = "dtmi:com:contoso:factory;1";
            twinData.Id = FactoryTwinId;

            twinData.Contents.Add("FactoryName", FactoryTwinId);
            twinData.Contents.Add("Country", "Germany");
            twinData.Contents.Add("ZipCode", "80807");
            twinData.Contents.Add("GeoLocation", new
            {
                Latitude  = 50.1787166,
                Longitude = 12.55770
            });

            await CreateOrReplaceTwinAsync(twinData);

            var relationship = new BasicRelationship
            {
                TargetId = FactoryAreaTwinId,
                Name     = "has_area"
            };

            string relId = $"{FactoryTwinId}-has_area-{relationship.TargetId}";

            await CreateOrReplaceRelationshipAsync(FactoryTwinId, relId, relationship);
        }
Exemple #2
0
        private async Task CreateProductionLineAsync()
        {
            _logger.LogInformation("Creating Production Line...");

            var twinData = new BasicDigitalTwin();

            twinData.Metadata.ModelId = "dtmi:com:contoso:factory:production_line;1";
            twinData.Id = ProductionLineTwinId;

            twinData.Contents.Add("LineName", ProductionLineTwinId);
            twinData.Contents.Add("Efficiency", 50);
            twinData.Contents.Add("CurrentProductId", "1234");
            twinData.Contents.Add("LineOperationStatus", 1);

            await CreateOrReplaceTwinAsync(twinData);

            var relationship = new BasicRelationship
            {
                TargetId = ConveyorTwinId,
                Name     = "contains_conveyor"
            };

            string relId = $"{ProductionLineTwinId}-contains_conveyor-{relationship.TargetId}";

            await CreateOrReplaceRelationshipAsync(ProductionLineTwinId, relId, relationship);
        }
        public async Task DigitalTwins_CreateOrReplaceTwinFailsWhenIfNoneMatchStar()
        {
            DigitalTwinsClient client = GetClient();

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange
                // create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(client, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // act

                // create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // act
                Func <Task> act = async() =>
                {
                    // "ifNoneMatch = *" header should cause the server to throw 412 since an entity does match
                    await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin, ETag.All).ConfigureAwait(false);
                };

                // assert
                act.Should().Throw <RequestFailedException>()
                .And.Status.Should().Be((int)HttpStatusCode.PreconditionFailed);
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // cleanup
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
        public async Task Query_GetTwinAliasing()
        {
            DigitalTwinsClient client = GetClient();

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // Create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(client, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // Create a room twin, with property "IsOccupied": true
                string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync(roomTwinId, roomTwin).ConfigureAwait(false);

                await WaitIfLiveAsync(TimeSpan.FromSeconds(10));

                // Use aliasing in the query to test deserialization when each digital twin in the response will be wrapped by the alias name.
                string queryString = $"SELECT D FROM DIGITALTWINS D";

                // act
                AsyncPageable <AliasedBasicDigitalTwin> asyncPageableResponse = client.QueryAsync <AliasedBasicDigitalTwin>(queryString);
                await foreach (AliasedBasicDigitalTwin twin in asyncPageableResponse)
                {
                    twin.Twin.Id.Should().NotBeNull();
                }
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
        public static async Task <string> FindOrCreateTwinAsync(string dtmi, string regId, ILogger log)
        {
            // Create Digital Twins client
            var cred   = new ManagedIdentityCredential(adtAppId);
            var client = new DigitalTwinsClient(
                new Uri(adtInstanceUrl),
                cred,
                new DigitalTwinsClientOptions
            {
                Transport = new HttpClientTransport(singletonHttpClientInstance)
            });

            // Find existing DigitalTwin with registration ID

            try
            {
                // Get DigitalTwin with Id `regId`
                BasicDigitalTwin dt = await GetDigitalTwin <BasicDigitalTwin>(regId).ConfigureAwait(false);

                // Check to make sure it is of model type `dtmi`
                if (StringComparer.OrdinalIgnoreCase.Equals(dtmi, dt.Metadata.ModelId))
                {
                    return(dt.Id);
                }

                // Found DigitalTwin with `regId` but it is not of model type `dtmi`
                log.LogInformation($"Found DigitalTwin {dt.Id} but it is not of model {dtmi}");
            }
            catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.NotFound)
            {
                log.LogInformation($"Did not find DigitalTwin {dt.Id}");
            }

            // Either the DigitalTwin was not found, or we found it but it is of a different model type
            // Create or replace it with what it needs to be, meaning if it was not found a brand new DigitalTwin will be created
            // and if it was of a different model, it will replace that existing DigitalTwin
            // If it was intended to only create the DigitalTwin if there is no matching DigitalTwin with the same Id,
            // ETag.All could have been used as the ifNonMatch parameter to the CreateOrReplaceDigitalTwinAsync method call.
            // Read more in the CreateOrReplaceDigitalTwinAsync documentation here:
            // https://docs.microsoft.com/en-us/dotnet/api/azure.digitaltwins.core.digitaltwinsclient.createorreplacedigitaltwinasync?view=azure-dotnet
            BasicDigitalTwin dt = await client.CreateOrReplaceDigitalTwinAsync(
                regId,
                new BasicDigitalTwin
            {
                Metadata = { ModelId = dtmi },
                Contents =
                {
                    { "Temperature", 0.0 }
                }
            }
                ).ConfigureAwait(false);

            log.LogInformation($"Digital Twin '{dtId}' created.");
            return(dt.Id);
        }
Exemple #6
0
        public async Task Query_ValidQuery_Success()
        {
            DigitalTwinsClient client = GetClient();

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // Create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await client.CreateModelsAsync(new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // Create a room twin, with property "IsOccupied": true
                string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                string queryString = "SELECT * FROM digitaltwins where IsOccupied = true";

                // act
                AsyncPageable <string> asyncPageableResponse = client.QueryAsync(queryString);

                // assert
                await foreach (string response in asyncPageableResponse)
                {
                    JsonElement jsonElement = JsonSerializer.Deserialize <JsonElement>(response);
                    JsonElement isOccupied  = jsonElement.GetProperty("IsOccupied");
                    isOccupied.GetRawText().Should().Be("true");
                }
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
        public async Task DigitalTwins_CreateOrReplaceTwinSucceedsWithNoIfNoneMatchHeader()
        {
            DigitalTwinsClient client = GetClient();

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange
                // create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(client, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // act

                // create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // Deliberately not passing in ifNoneMatch header, request should succeed because of that
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);
            }
            catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.PreconditionFailed)
            {
                throw new AssertionException("CreateOrReplaceDigitalTwin should not fail with PreconditionFailed when ifNoneMatch header wasn't set", ex);
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // cleanup
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemple #8
0
        private async Task CreateOrReplaceTwinAsync(BasicDigitalTwin twinData)
        {
            try
            {
                await _client.CreateOrReplaceDigitalTwinAsync(twinData.Id, twinData);

                _logger.LogInformation($"Created twin: {twinData.Id}");
            }
            catch (RequestFailedException e)
            {
                _logger.LogError($"Create twin error: {e.Status}: {e.Message}");
            }
        }
        /// <summary>
        /// Create a twin with the specified properties
        /// </summary>
        public static async Task CreateTwin(DigitalTwinsClient client)
        {
            Console.Write("vehicleId: ");
            string vehicleID = Console.ReadLine();

            Console.Write("modelId: ");
            string dtmi = Console.ReadLine();

            try
            {
                Response <ModelData> res = client.GetModel(dtmi);
                string twinId            = string.Format("{0}-{1}", res.Value.DisplayName.Values.ElementAt(0), vehicleID);

                Console.Write("twinId (suggest {0}): ", twinId);
                twinId = Console.ReadLine();

                var twinData = new BasicDigitalTwin
                {
                    Id       = twinId,
                    Metadata =
                    {
                        ModelId = dtmi,
                    },
                };

                try
                {
                    await client.CreateDigitalTwinAsync(twinData.Id, JsonSerializer.Serialize(twinData));

                    Console.WriteLine($"Twin '{twinId}' created successfully!");
                }
                catch (RequestFailedException e)
                {
                    Console.WriteLine($"Error {e.Status}: {e.Message}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error: {ex}");
                }
            }
            catch (RequestFailedException e)
            {
                Console.WriteLine($"Error {e.Status}: {e.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }
        }
Exemple #10
0
        private async Task CreateConveyorAsync()
        {
            _logger.LogInformation("Creating Conveyor...");

            var twinData = new BasicDigitalTwin();

            twinData.Metadata.ModelId = "dtmi:com:contoso:factory:conveyor;1";

            twinData.Id = ConveyorTwinId;
            twinData.Contents.Add("ConveyorName", ConveyorTwinId);

            await CreateOrReplaceTwinAsync(twinData);

            await CreateConveyorToResourcesRelationship(TransportCount, TransportTwinIdPrefix);
            await CreateConveyorToResourcesRelationship(BufferCount, BufferTwinIdPrefix);
        }
Exemple #11
0
        public static async Task <string> FindOrCreateTwinAsync(string dtmi, string regId, ILogger log)
        {
            // Create Digital Twins client
            var cred   = new ManagedIdentityCredential(adtAppId);
            var client = new DigitalTwinsClient(
                new Uri(adtInstanceUrl),
                cred,
                new DigitalTwinsClientOptions
            {
                Transport = new HttpClientTransport(singletonHttpClientInstance)
            });

            // Find existing twin with registration ID
            string query = $"SELECT * FROM DigitalTwins T WHERE $dtId = '{regId}' AND IS_OF_MODEL('{dtmi}')";
            AsyncPageable <BasicDigitalTwin> twins = client.QueryAsync(query);
            string dtId;

            await foreach (BasicDigitalTwin digitalTwin in twins)
            {
                dtId = digitalTwin.Id;
                log.LogInformation($"Twin '{dtId}' with Registration ID '{regId}' found in DT");
                break;
            }

            if (String.IsNullOrWhiteSpace(dtId))
            {
                // Not found, so create new twin
                log.LogInformation($"Twin ID not found - setting DT ID to regID");
                dtId = regId; // use the Registration ID as the DT ID

                // Initialize the twin properties
                var digitalTwin = new BasicDigitalTwin
                {
                    Metadata = { ModelId = dtmi },
                    Contents =
                    {
                        { "Temperature", 0.0 },
                    },
                };

                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(dtId, digitalTwin);

                log.LogInformation($"Twin '{dtId}' created in DT");
            }

            return(dtId);
        }
Exemple #12
0
        private static async Task PropagateStateToAzureMapsAsync(string capabilityTwinId, string capabilityName, JToken capabilityValue, ILogger log)
        {
            // Find parent to which the capability applies, using isCapabilityOf relationships
            List <string> parentTwinIds            = new List <string>();
            AsyncPageable <BasicRelationship> rels = dtClient.GetRelationshipsAsync <BasicRelationship>(capabilityTwinId, "isCapabilityOf");

            await foreach (BasicRelationship relationship in rels)
            {
                parentTwinIds.Add(relationship.TargetId);
            }
            if (parentTwinIds.Count != 1)
            {
                log.LogInformation($"Capability twin {capabilityTwinId} isn't assigned to exactly one parent.");
                return;
            }
            string parentTwinId = parentTwinIds.First();
            Response <BasicDigitalTwin> parentTwinResponse = await dtClient.GetDigitalTwinAsync <BasicDigitalTwin>(parentTwinId);

            BasicDigitalTwin parentTwin = parentTwinResponse.Value;

            // TODO: Based on parent twin, get Azure Maps Feature ID (either from ADT model using externalIds property, or by querying Azure Maps feature service )
            string AzureMapsFeatureID = "NONEXISTENT_FIXME";

            // Load the Azure Maps stateset ID (configured in an env. variable JSON fragment) that corresponds to this capability name
            if (!azureMapsStateSets.ContainsKey(capabilityName))
            {
                log.LogInformation($"There is no configured Azure Maps stateset supporting the capability type {capabilityName}.");
                return;
            }
            string statesetID = azureMapsStateSets[capabilityName].ToString();

            // Update the maps feature stateset
            JObject postcontent = new JObject(
                new JProperty(
                    "States",
                    new JArray(
                        new JObject(
                            new JProperty("keyName", capabilityName),
                            new JProperty("value", capabilityValue.ToString()),
                            new JProperty("eventTimestamp", DateTime.UtcNow.ToString("s"))))));

            var response = await httpClient.PostAsync(
                $"https://us.atlas.microsoft.com/featureState/state?api-version=1.0&statesetID={statesetID}&featureID={AzureMapsFeatureID}&subscription-key={azureMapsSubscriptionKey}",
                new StringContent(postcontent.ToString()));

            log.LogInformation($"Azure Maps response:\n\t" + await response.Content.ReadAsStringAsync());
        }
        public async Task RunSampleAsync()
        {
            // Get and print the digital twin. If you do not know the exact structure of your digital twin, you can
            // use the BasicDgitalTwin type to deserialize it to a basic type
            BasicDigitalTwin digitalTwin = await GetAndPrintDigitalTwinAsync <BasicDigitalTwin>();

            _logger.LogDebug($"The {_digitalTwinId} digital twin has a model with ID {digitalTwin.Metadata.ModelId}.");

            // Update the targetTemperature property of the digital twin
            await UpdateTargetTemperaturePropertyAsync();

            // Add, replace then remove currentTemperature property on the digital twin. Note that the
            // currentTemperature property does not exist on the model that the device is registered with
            await UpdateCurrentTemperaturePropertyAsync();

            // Invoke the root-level command getMaxMinReport command on the digital twin
            await InvokeGetMaxMinReportCommandAsync();
        }
        private async Task CreateModelsAndTwins(DigitalTwinsClient client, string wifiModelId, string roomWithWifiModelId, string wifiComponentName, string roomWithWifiTwinId)
        {
            // Generate the payload needed to create the WiFi component model.
            string wifiModel = TestAssetsHelper.GetWifiModelPayload(wifiModelId);

            // Generate the payload needed to create the room with WiFi model.
            string roomWithWifiModel = TestAssetsHelper.GetRoomWithWifiModelPayload(roomWithWifiModelId, wifiModelId, wifiComponentName);

            // Create the room and WiFi models.
            await client.CreateModelsAsync(new List <string> {
                roomWithWifiModel, wifiModel
            }).ConfigureAwait(false);

            // Generate the payload needed to create the room with WiFi twin.
            BasicDigitalTwin roomWithWifiTwin = TestAssetsHelper.GetRoomWithWifiTwinPayload(roomWithWifiModelId, wifiComponentName);

            // Create the room with WiFi component digital twin.
            await client.CreateDigitalTwinAsync <BasicDigitalTwin>(roomWithWifiTwinId, roomWithWifiTwin).ConfigureAwait(false);
        }
Exemple #15
0
        public static async Task CommandCreateTwinAsync(string pfxPath)
        {
            DefaultAzureCredential cred  = new DefaultAzureCredential();
            DigitalTwinsClient     dtcli = new DigitalTwinsClient(new Uri("https://mobility-vss.api.wus2.digitaltwins.azure.net"), cred);

            BasicDigitalTwin twinData = new BasicDigitalTwin();

            //Note the modelId requires that the model is preloaded in the cloud
            Console.Write("modelId (dtmi): ");
            twinData.Metadata.ModelId = Console.ReadLine();

            Console.Write("twinId (e.g. lfFoglight-contosocar01): ");
            twinData.Id = Console.ReadLine();

            string payload = JsonSerializer.Serialize(twinData);

            Command cmd = new Command(pfxPath, domainName);
            await cmd.SendCommandToVehicleAsync("createtwin", payload);
        }
Exemple #16
0
        private async Task CreateTransportAsync()
        {
            _logger.LogInformation("Creating Transport Resources...");

            for (int i = 0; i < TransportCount; i++)
            {
                var twinData = new BasicDigitalTwin();
                twinData.Metadata.ModelId = "dtmi:com:contoso:factory:production_resource_engine_transport;1";
                var twinId = $"{TransportTwinIdPrefix}{i}";

                twinData.Contents.Add("PrId", twinId);
                twinData.Contents.Add("PrName", twinId);
                twinData.Contents.Add("Status", 1);
                twinData.Contents.Add("Speed", 10);
                twinData.Contents.Add("Vibration", 5);
                twinData.Id = twinId;

                await CreateOrReplaceTwinAsync(twinData);
            }
        }
        public async Task DigitalTwinOperationsWithCustomObjectSerializer_Succeeds()
        {
            // arrange

            var serializer = new TestObjectSerializer();
            DigitalTwinsClientOptions options = new DigitalTwinsClientOptions
            {
                Serializer = serializer
            };

            DigitalTwinsClient client = GetClient(options);

            serializer.WasDeserializeCalled.Should().BeFalse();
            serializer.WasSerializeCalled.Should().BeFalse();

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            // create room model
            string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);

            await CreateAndListModelsAsync(client, new List <string> {
                roomModel
            }).ConfigureAwait(false);

            // act

            // create room twin
            BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
            await client.CreateOrReplaceDigitalTwinAsync(roomTwinId, roomTwin).ConfigureAwait(false);

            roomTwin = await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomTwinId).ConfigureAwait(false);

            // assert
            roomTwin.Should().NotBeNull();
            serializer.WasDeserializeCalled.Should().BeTrue();
            serializer.WasSerializeCalled.Should().BeTrue();
        }
Exemple #18
0
        private async Task CreateBufferAsync()
        {
            _logger.LogInformation("Creating Buffer Resources...");

            for (int i = 0; i < BufferCount; i++)
            {
                var twinData = new BasicDigitalTwin();
                twinData.Metadata.ModelId = "dtmi:com:contoso:factory:production_resource_buffer_system;1";
                var twinId = $"{BufferTwinIdPrefix}{i}";

                twinData.Contents.Add("PrId", twinId);
                twinData.Contents.Add("PrName", twinId);
                twinData.Contents.Add("Status", 1);

                twinData.Contents.Add("BufferLevel", 15);
                twinData.Contents.Add("PieceCount", 50);
                twinData.Id = $"{BufferTwinIdPrefix}{i}";

                await CreateOrReplaceTwinAsync(twinData);
            }
        }
        public async Task SetPropertyValuesAsync(DigitalTwinsClient client)
        {
            // ------------------ SET TAG PROPERTY VALUES: CSHARP ---------------------
            // <TagPropertiesCsharp>
            IDictionary <string, bool> tags = new Dictionary <string, bool>
            {
                { "oceanview", true },
                { "VIP", true }
            };
            var twin = new BasicDigitalTwin
            {
                Metadata = { ModelId = "dtmi:example:Room;1" },
                Contents =
                {
                    { "Temperature",   75 },
                    { "tags",        tags },
                },
            };
            await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>("myTwinID", twin);

            // </TagPropertiesCsharp>
        }
Exemple #20
0
        /// <summary>
        /// Creates all twins specified in the \DTDL\DigitalTwins directory
        /// </summary>
        public async Task CreateAllTwinsAsync()
        {
            PrintHeader("CREATE DIGITAL TWINS");
            Dictionary <string, string> twins = FileHelper.LoadAllFilesInPath(s_twinsPath);

            // Call APIs to create the twins.
            foreach (KeyValuePair <string, string> twin in twins)
            {
                try
                {
                    BasicDigitalTwin            basicDigitalTwin = JsonSerializer.Deserialize <BasicDigitalTwin>(twin.Value);
                    Response <BasicDigitalTwin> response         = await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(twin.Key, basicDigitalTwin);

                    Console.WriteLine($"Created digital twin '{twin.Key}'.");
                    Console.WriteLine($"\tBody: {JsonSerializer.Serialize(response?.Value)}");
                }
                catch (Exception ex)
                {
                    FatalError($"Could not create digital twin '{twin.Key}' due to {ex}");
                }
            }
        }
Exemple #21
0
        private async Task CreateFactoryAreaLineAsync()
        {
            _logger.LogInformation("Creating Factory Area...");

            var twinData = new BasicDigitalTwin();

            twinData.Metadata.ModelId = "dtmi:com:contoso:factory:factory_area;1";
            twinData.Id = FactoryAreaTwinId;

            twinData.Contents.Add("AreaName", FactoryAreaTwinId);

            await CreateOrReplaceTwinAsync(twinData);

            var relationship = new BasicRelationship
            {
                TargetId = ProductionLineTwinId,
                Name     = "has_production_line"
            };

            string relId = $"{FactoryAreaTwinId}-has_production_line-{relationship.TargetId}";

            await CreateOrReplaceRelationshipAsync(FactoryAreaTwinId, relId, relationship);
        }
Exemple #22
0
        /// <summary>
        /// Creates two digital twins, and connect them with relationships.
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            // For the purpose of keeping code snippets readable to the user, hardcoded string literals are used in place of assigned variables, eg Ids.
            // Despite not being a good code practice, this prevents code snippets from being out of context for the user when making API calls that accept Ids as parameters.

            PrintHeader("RELATIONSHIP SAMPLE");
            string sampleBuildingModelId = "dtmi:com:samples:SampleBuilding;1";
            string sampleFloorModelId    = "dtmi:com:samples:SampleFloor;1";
            await ModelLifecycleSamples.TryDeleteModelAsync(client, sampleBuildingModelId);

            await ModelLifecycleSamples.TryDeleteModelAsync(client, sampleFloorModelId);

            // Create a building digital twin model.
            string buildingModelPayload = SamplesConstants.TemporaryModelWithRelationshipPayload
                                          .Replace(SamplesConstants.RelationshipTargetModelId, sampleFloorModelId)
                                          .Replace(SamplesConstants.ModelId, sampleBuildingModelId)
                                          .Replace(SamplesConstants.ModelDisplayName, "Building")
                                          .Replace(SamplesConstants.RelationshipName, "contains");

            await client.CreateModelsAsync(
                new[]
            {
                buildingModelPayload
            });

            Console.WriteLine($"Created model '{sampleBuildingModelId}'.");

            // Create a floor digital twin model.
            string floorModelPayload = SamplesConstants.TemporaryModelWithRelationshipPayload
                                       .Replace(SamplesConstants.RelationshipTargetModelId, sampleBuildingModelId)
                                       .Replace(SamplesConstants.ModelId, sampleFloorModelId)
                                       .Replace(SamplesConstants.ModelDisplayName, "Floor")
                                       .Replace(SamplesConstants.RelationshipName, "containedIn");

            await client.CreateModelsAsync(new[] { floorModelPayload });

            // Get the model we just created
            Response <DigitalTwinsModelData> getFloorModelResponse = await client.GetModelAsync(sampleFloorModelId).ConfigureAwait(false);

            Console.WriteLine($"Created model '{getFloorModelResponse.Value.Id}'");

            // Create a building digital twin.
            var buildingDigitalTwin = new BasicDigitalTwin
            {
                Id       = "buildingTwinId",
                Metadata = { ModelId = sampleBuildingModelId }
            };

            Response <BasicDigitalTwin> createDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>("buildingTwinId", buildingDigitalTwin);

            Console.WriteLine($"Created twin '{createDigitalTwinResponse.Value.Id}'.");

            // Create a floor digital.
            var floorDigitalTwin = new BasicDigitalTwin
            {
                Id       = "floorTwinId",
                Metadata = { ModelId = sampleFloorModelId }
            };

            Response <BasicDigitalTwin> createFloorDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>("floorTwinId", floorDigitalTwin);

            Console.WriteLine($"Created twin '{createFloorDigitalTwinResponse.Value.Id}'.");

            // Create a relationship between building and floor using the BasicRelationship serialization helper.

            #region Snippet:DigitalTwinsSampleCreateBasicRelationship

            var buildingFloorRelationshipPayload = new BasicRelationship
            {
                Id         = "buildingFloorRelationshipId",
                SourceId   = "buildingTwinId",
                TargetId   = "floorTwinId",
                Name       = "contains",
                Properties =
                {
                    { "Prop1", "Prop1 value" },
                    { "Prop2",             6 }
                }
            };

            Response <BasicRelationship> createBuildingFloorRelationshipResponse = await client
                                                                                   .CreateOrReplaceRelationshipAsync <BasicRelationship>("buildingTwinId", "buildingFloorRelationshipId", buildingFloorRelationshipPayload);

            Console.WriteLine($"Created a digital twin relationship '{createBuildingFloorRelationshipResponse.Value.Id}' " +
                              $"from twin '{createBuildingFloorRelationshipResponse.Value.SourceId}' to twin '{createBuildingFloorRelationshipResponse.Value.TargetId}'.");

            #endregion Snippet:DigitalTwinsSampleCreateBasicRelationship

            // You can get a relationship as a BasicRelationship type.

            #region Snippet:DigitalTwinsSampleGetBasicRelationship

            Response <BasicRelationship> getBasicRelationshipResponse = await client.GetRelationshipAsync <BasicRelationship>(
                "buildingTwinId",
                "buildingFloorRelationshipId");

            if (getBasicRelationshipResponse.GetRawResponse().Status == (int)HttpStatusCode.OK)
            {
                BasicRelationship basicRelationship = getBasicRelationshipResponse.Value;
                Console.WriteLine($"Retrieved relationship '{basicRelationship.Id}' from twin {basicRelationship.SourceId}.\n\t" +
                                  $"Prop1: {basicRelationship.Properties["Prop1"]}\n\t" +
                                  $"Prop2: {basicRelationship.Properties["Prop2"]}");
            }

            #endregion Snippet:DigitalTwinsSampleGetBasicRelationship

            // Alternatively, you can create your own custom data types and use these types when calling into the APIs.
            // This requires less code or knowledge of the type for interaction.

            // Create a relationship between floorTwinId and buildingTwinId using a custom data type.

            #region Snippet:DigitalTwinsSampleCreateCustomRelationship

            var floorBuildingRelationshipPayload = new CustomRelationship
            {
                Id       = "floorBuildingRelationshipId",
                SourceId = "floorTwinId",
                TargetId = "buildingTwinId",
                Name     = "containedIn",
                Prop1    = "Prop1 val",
                Prop2    = 4
            };

            Response <CustomRelationship> createCustomRelationshipResponse = await client
                                                                             .CreateOrReplaceRelationshipAsync <CustomRelationship>("floorTwinId", "floorBuildingRelationshipId", floorBuildingRelationshipPayload);

            Console.WriteLine($"Created a digital twin relationship '{createCustomRelationshipResponse.Value.Id}' " +
                              $"from twin '{createCustomRelationshipResponse.Value.SourceId}' to twin '{createCustomRelationshipResponse.Value.TargetId}'.");

            #endregion Snippet:DigitalTwinsSampleCreateCustomRelationship

            // Getting a relationship as a custom data type is extremely easy.

            #region Snippet:DigitalTwinsSampleGetCustomRelationship

            Response <CustomRelationship> getCustomRelationshipResponse = await client.GetRelationshipAsync <CustomRelationship>(
                "floorTwinId",
                "floorBuildingRelationshipId");

            CustomRelationship getCustomRelationship = getCustomRelationshipResponse.Value;
            Console.WriteLine($"Retrieved and deserialized relationship '{getCustomRelationship.Id}' from twin '{getCustomRelationship.SourceId}'.\n\t" +
                              $"Prop1: {getCustomRelationship.Prop1}\n\t" +
                              $"Prop2: {getCustomRelationship.Prop2}");

            #endregion Snippet:DigitalTwinsSampleGetCustomRelationship

            // Get all relationships in the graph where buildingTwinId is the source of the relationship.

            #region Snippet:DigitalTwinsSampleGetAllRelationships

            AsyncPageable <BasicRelationship> relationships = client.GetRelationshipsAsync <BasicRelationship>("buildingTwinId");
            await foreach (BasicRelationship relationship in relationships)
            {
                Console.WriteLine($"Retrieved relationship '{relationship.Id}' with source {relationship.SourceId}' and " +
                                  $"target {relationship.TargetId}.\n\t" +
                                  $"Prop1: {relationship.Properties["Prop1"]}\n\t" +
                                  $"Prop2: {relationship.Properties["Prop2"]}");
            }

            #endregion Snippet:DigitalTwinsSampleGetAllRelationships

            // Get all incoming relationships in the graph where buildingTwinId is the target of the relationship.

            #region Snippet:DigitalTwinsSampleGetIncomingRelationships

            AsyncPageable <IncomingRelationship> incomingRelationships = client.GetIncomingRelationshipsAsync("buildingTwinId");

            await foreach (IncomingRelationship incomingRelationship in incomingRelationships)
            {
                Console.WriteLine($"Found an incoming relationship '{incomingRelationship.RelationshipId}' from '{incomingRelationship.SourceId}'.");
            }

            #endregion Snippet:DigitalTwinsSampleGetIncomingRelationships

            // Delete the contains relationship, created earlier in the sample code, from building to floor.

            #region Snippet:DigitalTwinsSampleDeleteRelationship

            await client.DeleteRelationshipAsync("buildingTwinId", "buildingFloorRelationshipId");

            Console.WriteLine($"Deleted relationship 'buildingFloorRelationshipId'.");

            #endregion Snippet:DigitalTwinsSampleDeleteRelationship

            // Delete the containedIn relationship, created earlier in the sample code, from floor to building.
            await client.DeleteRelationshipAsync("floorTwinId", "floorBuildingRelationshipId");

            Console.WriteLine($"Deleted relationship 'floorBuildingRelationshipId'.");

            // Clean up.
            try
            {
                // Delete all twins
                await client.DeleteDigitalTwinAsync("buildingTwinId");

                await client.DeleteDigitalTwinAsync("floorTwinId");
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete twin due to {ex}.");
            }

            try
            {
                await client.DeleteModelAsync(sampleBuildingModelId);

                await client.DeleteModelAsync(sampleFloorModelId);
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete model due to {ex}.");
            }
        }
        /// <summary>
        /// Creates a digital twin with Component and upates Component
        /// </summary>
        public async Task RunSamplesAsync()
        {
            PrintHeader("COMPONENT SAMPLE");

            // For the purpose of this example we will create temporary models using a random model Ids.
            // We have to make sure these model Ids are unique within the DT instance.

            string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, DigitalTwinsClient).ConfigureAwait(false);

            string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, DigitalTwinsClient).ConfigureAwait(false);

            string dtId1 = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, DigitalTwinsClient).ConfigureAwait(false);

            string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload
                                              .Replace(SamplesConstants.ComponentId, componentModelId);

            string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload
                                     .Replace(SamplesConstants.ModelId, modelId)
                                     .Replace(SamplesConstants.ComponentId, componentModelId);

            // Then we create models
            Response <IReadOnlyList <Models.ModelData> > createModelsResponse = await DigitalTwinsClient
                                                                                .CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload })
                                                                                .ConfigureAwait(false);

            Console.WriteLine($"Successfully created models Ids {componentModelId} and {modelId} with response {createModelsResponse.GetRawResponse().Status}.");

            #region Snippet:DigitalTwinsSampleCreateBasicTwin

            // Create digital twin with Component payload using the BasicDigitalTwin serialization helper

            var basicDigitalTwin = new BasicDigitalTwin
            {
                Id = dtId1
            };
            basicDigitalTwin.Metadata.ModelId = modelId;
            basicDigitalTwin.CustomProperties.Add("Prop1", "Value1");
            basicDigitalTwin.CustomProperties.Add("Prop2", "Value2");

            var componentMetadata = new ModelProperties();
            componentMetadata.Metadata.ModelId = componentModelId;
            componentMetadata.CustomProperties.Add("ComponentProp1", "ComponentValue1");
            componentMetadata.CustomProperties.Add("ComponentProp2", "ComponentValue2");

            basicDigitalTwin.CustomProperties.Add("Component1", componentMetadata);

            string dt1Payload = JsonSerializer.Serialize(basicDigitalTwin);

            Response <string> createDt1Response = await DigitalTwinsClient.CreateDigitalTwinAsync(dtId1, dt1Payload).ConfigureAwait(false);

            Console.WriteLine($"Created digital twin {dtId1} with response {createDt1Response.GetRawResponse().Status}.");

            #endregion Snippet:DigitalTwinsSampleCreateBasicTwin

            #region Snippet:DigitalTwinsSampleCreateCustomTwin

            string dtId2 = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, DigitalTwinsClient).ConfigureAwait(false);

            var customDigitalTwin = new CustomDigitalTwin
            {
                Id       = dtId2,
                Metadata = new CustomDigitalTwinMetadata {
                    ModelId = modelId
                },
                Prop1      = "Prop1 val",
                Prop2      = "Prop2 val",
                Component1 = new Component1
                {
                    Metadata = new Component1Metadata {
                        ModelId = componentModelId
                    },
                    ComponentProp1 = "Component prop1 val",
                    ComponentProp2 = "Component prop2 val",
                }
            };
            string dt2Payload = JsonSerializer.Serialize(customDigitalTwin);

            Response <string> createDt2Response = await DigitalTwinsClient.CreateDigitalTwinAsync(dtId2, dt2Payload).ConfigureAwait(false);

            Console.WriteLine($"Created digital twin {dtId2} with response {createDt2Response.GetRawResponse().Status}.");

            #endregion Snippet:DigitalTwinsSampleCreateCustomTwin

            #region Snippet:DigitalTwinsSampleUpdateComponent

            // Update Component1 by replacing the property ComponentProp1 value
            var componentUpdateUtility = new UpdateOperationsUtility();
            componentUpdateUtility.AppendReplaceOp("/ComponentProp1", "Some new value");
            string updatePayload = componentUpdateUtility.Serialize();

            Response <string> response = await DigitalTwinsClient.UpdateComponentAsync(dtId1, "Component1", updatePayload);

            Console.WriteLine($"Updated component for digital twin {dtId1}. Update response status: {response.GetRawResponse().Status}");

            #endregion Snippet:DigitalTwinsSampleUpdateComponent

            // Get Component

            #region Snippet:DigitalTwinsSampleGetComponent

            response = await DigitalTwinsClient.GetComponentAsync(dtId1, SamplesConstants.ComponentPath).ConfigureAwait(false);

            Console.WriteLine($"Get component for digital twin: \n{response.Value}. Get response status: {response.GetRawResponse().Status}");

            #endregion Snippet:DigitalTwinsSampleGetComponent

            // Clean up

            try
            {
                await DigitalTwinsClient.DeleteDigitalTwinAsync(dtId1).ConfigureAwait(false);

                await DigitalTwinsClient.DeleteDigitalTwinAsync(dtId2).ConfigureAwait(false);
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete digital twin due to {ex}");
            }

            try
            {
                await DigitalTwinsClient.DeleteModelAsync(modelId).ConfigureAwait(false);

                await DigitalTwinsClient.DeleteModelAsync(componentModelId).ConfigureAwait(false);
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete models due to {ex}");
            }
        }
        /// <summary>
        /// Create a temporary component model, twin model and digital twin instance.
        /// Publish a telemetry message and a component telemetry message to the digital twin instance.
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            PrintHeader("PUBLISH TELEMETRY MESSAGE SAMPLE");

            // For the purpose of this example we will create temporary models using a random model Ids.
            // We will also create temporary twin instances to publish the telemetry to.

            string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, client);

            string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, client);

            string twinId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client);

            string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload
                                              .Replace(SamplesConstants.ComponentId, componentModelId);

            string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload
                                     .Replace(SamplesConstants.ModelId, modelId)
                                     .Replace(SamplesConstants.ComponentId, componentModelId);

            // Then we create the models.
            await client
            .CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload });

            // Get the models we just created
            AsyncPageable <DigitalTwinsModelData> models = client.GetModelsAsync();

            await foreach (DigitalTwinsModelData model in models)
            {
                Console.WriteLine($"Successfully created model '{model.Id}'");
            }

            // Create digital twin with Component payload.
            string twinPayload = SamplesConstants.TemporaryTwinPayload
                                 .Replace(SamplesConstants.ModelId, modelId);

            BasicDigitalTwin basicDigitalTwin = JsonSerializer.Deserialize <BasicDigitalTwin>(twinPayload);

            Response <BasicDigitalTwin> createDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(twinId, basicDigitalTwin);

            Console.WriteLine($"Created digital twin '{createDigitalTwinResponse.Value.Id}'.");

            try
            {
                #region Snippet:DigitalTwinsSamplePublishTelemetry

                // construct your json telemetry payload by hand.
                await client.PublishTelemetryAsync(twinId, Guid.NewGuid().ToString(), "{\"Telemetry1\": 5}");

                Console.WriteLine($"Published telemetry message to twin '{twinId}'.");

                #endregion Snippet:DigitalTwinsSamplePublishTelemetry

                #region Snippet:DigitalTwinsSamplePublishComponentTelemetry

                // construct your json telemetry payload by serializing a dictionary.
                var telemetryPayload = new Dictionary <string, int>
                {
                    { "ComponentTelemetry1", 9 }
                };
                await client.PublishComponentTelemetryAsync(
                    twinId,
                    "Component1",
                    Guid.NewGuid().ToString(),
                    JsonSerializer.Serialize(telemetryPayload));

                Console.WriteLine($"Published component telemetry message to twin '{twinId}'.");

                #endregion Snippet:DigitalTwinsSamplePublishComponentTelemetry
            }
            catch (Exception ex)
            {
                FatalError($"Failed to publish a telemetry message due to: {ex.Message}");
            }

            try
            {
                // Delete the twin.
                await client.DeleteDigitalTwinAsync(twinId);

                // Delete the models.
                await client.DeleteModelAsync(modelId);

                await client.DeleteModelAsync(componentModelId);
            }
            catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.NotFound)
            {
                // Digital twin or models do not exist.
            }
            catch (RequestFailedException ex)
            {
                FatalError($"Failed to delete due to: {ex.Message}");
            }
        }
Exemple #25
0
        public static async Task Run(
            [EventHubTrigger("lifecycleevents", Connection = "EVENTHUB_CONNECTIONSTRING")] EventData[] events, ILogger log)
        {
            var exceptions = new List <Exception>(events.Length);

            // Create Digital Twin client
            var cred   = new ManagedIdentityCredential(adtAppId);
            var client = new DigitalTwinsClient(
                new Uri(adtInstanceUrl),
                cred,
                new DigitalTwinsClientOptions
            {
                Transport = new HttpClientTransport(singletonHttpClientInstance)
            });

            foreach (EventData eventData in events)
            {
                try
                {
                    //log.LogDebug($"EventData: {System.Text.Json.JsonSerializer.Serialize(eventData)}");

                    string opType = eventData.Properties["opType"] as string;
                    if (opType == "deleteDeviceIdentity")
                    {
                        string deviceId = eventData.Properties["deviceId"] as string;

                        try
                        {
                            // Find twin based on the original Registration ID
                            BasicDigitalTwin digitalTwin = await client.GetDigitalTwinAsync <BasicDigitalTwin>(deviceId);

                            // In order to delete the twin, all relationships must first be removed
                            await DeleteAllRelationshipsAsync(client, digitalTwin.Id, log);

                            // Delete the twin
                            await client.DeleteDigitalTwinAsync(digitalTwin.Id, digitalTwin.ETag);

                            log.LogInformation($"Twin {digitalTwin.Id} deleted in DT");
                        }
                        catch (RequestFailedException e) when(e.Status == (int)HttpStatusCode.NotFound)
                        {
                            log.LogWarning($"Twin {deviceId} not found in DT");
                        }
                    }
                }
                catch (Exception e)
                {
                    // We need to keep processing the rest of the batch - capture this exception and continue.
                    exceptions.Add(e);
                }
            }

            if (exceptions.Count > 1)
            {
                throw new AggregateException(exceptions);
            }

            if (exceptions.Count == 1)
            {
                throw exceptions.Single();
            }
        }
Exemple #26
0
        public async Task QueryTwinsAsync()
        {
            PrintHeader("QUERY DIGITAL TWINS");

            try
            {
                Console.WriteLine("Making a twin query and iterating over the results.");

                #region Snippet:DigitalTwinsSampleQueryTwins

                // This code snippet demonstrates the simplest way to iterate over the digital twin results, where paging
                // happens under the covers.
                AsyncPageable <string> asyncPageableResponse = client.QueryAsync("SELECT * FROM digitaltwins");

                // Iterate over the twin instances in the pageable response.
                // The "await" keyword here is required because new pages will be fetched when necessary,
                // which involves a request to the service.
                await foreach (string response in asyncPageableResponse)
                {
                    BasicDigitalTwin twin = JsonSerializer.Deserialize <BasicDigitalTwin>(response);
                    Console.WriteLine($"Found digital twin: {twin.Id}");
                }

                #endregion Snippet:DigitalTwinsSampleQueryTwins

                Console.WriteLine("Making a twin query, with query-charge header extraction.");

                #region Snippet:DigitalTwinsSampleQueryTwinsWithQueryCharge

                // This code snippet demonstrates how you could extract the query charges incurred when calling
                // the query API. It iterates over the response pages first to access to the query-charge header,
                // and then the digital twin results within each page.

                AsyncPageable <string> asyncPageableResponseWithCharge = client.QueryAsync("SELECT * FROM digitaltwins");
                int pageNum = 0;

                // The "await" keyword here is required as a call is made when fetching a new page.
                await foreach (Page <string> page in asyncPageableResponseWithCharge.AsPages())
                {
                    Console.WriteLine($"Page {++pageNum} results:");

                    // Extract the query-charge header from the page
                    if (QueryChargeHelper.TryGetQueryCharge(page, out float queryCharge))
                    {
                        Console.WriteLine($"Query charge was: {queryCharge}");
                    }

                    // Iterate over the twin instances.
                    // The "await" keyword is not required here as the paged response is local.
                    foreach (string response in page.Values)
                    {
                        BasicDigitalTwin twin = JsonSerializer.Deserialize <BasicDigitalTwin>(response);
                        Console.WriteLine($"Found digital twin: {twin.Id}");
                    }
                }

                #endregion Snippet:DigitalTwinsSampleQueryTwinsWithQueryCharge
            }
            catch (Exception ex)
            {
                FatalError($"Could not query digital twins due to {ex}");
            }
        }
Exemple #27
0
        /// <summary>
        /// Creates a digital twin with Component and upates Component
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            PrintHeader("COMPONENT SAMPLE");

            // For the purpose of this example we will create temporary models using a random model Ids.
            // We have to make sure these model Ids are unique within the DT instance.

            string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, client);

            string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, client);

            string basicDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client);

            string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload
                                              .Replace(SamplesConstants.ComponentId, componentModelId);

            string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload
                                     .Replace(SamplesConstants.ModelId, modelId)
                                     .Replace(SamplesConstants.ComponentId, componentModelId);

            // Then we create models
            await client.CreateModelsAsync(
                new[]
            {
                newComponentModelPayload,
                newModelPayload
            });

            Console.WriteLine($"Created models {componentModelId} and {modelId}.");

            #region Snippet:DigitalTwinsSampleCreateBasicTwin

            // Create digital twin with component payload using the BasicDigitalTwin serialization helper

            var basicTwin = new BasicDigitalTwin
            {
                Id = basicDtId,
                // model Id of digital twin
                Metadata = { ModelId = modelId },
                Contents =
                {
                    // digital twin properties
                    { "Prop1",          "Value1"            },
                    { "Prop2",                          987 },
                    // component
                    {
                        "Component1",
                        new BasicDigitalTwinComponent
                        {
                            // component properties
                            Contents =
                            {
                                { "ComponentProp1", "Component value 1" },
                                { "ComponentProp2",                 123 },
                            },
                        }
                    },
                },
            };

            Response <BasicDigitalTwin> createDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync(basicDtId, basicTwin);

            Console.WriteLine($"Created digital twin '{createDigitalTwinResponse.Value.Id}'.");

            #endregion Snippet:DigitalTwinsSampleCreateBasicTwin

            // You can also get a digital twin as a BasicDigitalTwin type.
            // It works well for basic stuff, but as you can see it gets more difficult when delving into
            // more complex properties, like components.

            #region Snippet:DigitalTwinsSampleGetBasicDigitalTwin

            Response <BasicDigitalTwin> getBasicDtResponse = await client.GetDigitalTwinAsync <BasicDigitalTwin>(basicDtId);

            if (getBasicDtResponse.GetRawResponse().Status == (int)HttpStatusCode.OK)
            {
                BasicDigitalTwin basicDt = getBasicDtResponse.Value;

                // Must cast Component1 as a JsonElement and get its raw text in order to deserialize it as a dictionary
                string component1RawText = ((JsonElement)basicDt.Contents["Component1"]).GetRawText();
                IDictionary <string, object> component1 = JsonSerializer.Deserialize <IDictionary <string, object> >(component1RawText);

                Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id}:\n\t" +
                                  $"ETag: {basicDt.ETag}\n\t" +
                                  $"Prop1: {basicDt.Contents["Prop1"]}\n\t" +
                                  $"Prop2: {basicDt.Contents["Prop2"]}\n\t" +
                                  $"ComponentProp1: {component1["ComponentProp1"]}\n\t" +
                                  $"ComponentProp2: {component1["ComponentProp2"]}");
            }

            #endregion Snippet:DigitalTwinsSampleGetBasicDigitalTwin

            string customDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client);

            // Alternatively, you can create your own custom data types to serialize and deserialize your digital twins.
            // By specifying your properties and types directly, it requires less code or knowledge of the type for
            // interaction.

            #region Snippet:DigitalTwinsSampleCreateCustomTwin

            var customTwin = new CustomDigitalTwin
            {
                Id         = customDtId,
                Metadata   = { ModelId = modelId },
                Prop1      = "Prop1 val",
                Prop2      = 987,
                Component1 = new MyCustomComponent
                {
                    ComponentProp1 = "Component prop1 val",
                    ComponentProp2 = 123,
                },
            };
            Response <CustomDigitalTwin> createCustomDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync(customDtId, customTwin);

            Console.WriteLine($"Created digital twin '{createCustomDigitalTwinResponse.Value.Id}'.");

            #endregion Snippet:DigitalTwinsSampleCreateCustomTwin

            // Getting a digital twin as a custom data type is extremely easy.
            // Custom types provide the best possible experience.

            #region Snippet:DigitalTwinsSampleGetCustomDigitalTwin

            Response <CustomDigitalTwin> getCustomDtResponse = await client.GetDigitalTwinAsync <CustomDigitalTwin>(customDtId);

            CustomDigitalTwin customDt = getCustomDtResponse.Value;
            Console.WriteLine($"Retrieved and deserialized digital twin {customDt.Id}:\n\t" +
                              $"ETag: {customDt.ETag}\n\t" +
                              $"Prop1: {customDt.Prop1}\n\t" +
                              $"Prop2: {customDt.Prop2}\n\t" +
                              $"ComponentProp1: {customDt.Component1.ComponentProp1}\n\t" +
                              $"ComponentProp2: {customDt.Component1.ComponentProp2}");

            #endregion Snippet:DigitalTwinsSampleGetCustomDigitalTwin

            #region Snippet:DigitalTwinsSampleUpdateComponent

            // Update Component1 by replacing the property ComponentProp1 value,
            // using an optional utility to build the payload.
            var componentJsonPatchDocument = new JsonPatchDocument();
            componentJsonPatchDocument.AppendReplace("/ComponentProp1", "Some new value");
            await client.UpdateComponentAsync(basicDtId, "Component1", componentJsonPatchDocument);

            Console.WriteLine($"Updated component for digital twin '{basicDtId}'.");

            #endregion Snippet:DigitalTwinsSampleUpdateComponent

            // Get Component

            #region Snippet:DigitalTwinsSampleGetComponent

            await client.GetComponentAsync <MyCustomComponent>(basicDtId, SamplesConstants.ComponentName);

            Console.WriteLine($"Retrieved component for digital twin '{basicDtId}'.");

            #endregion Snippet:DigitalTwinsSampleGetComponent

            // Clean up

            try
            {
                await client.DeleteDigitalTwinAsync(basicDtId);

                await client.DeleteDigitalTwinAsync(customDtId);
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete digital twin due to {ex}");
            }

            try
            {
                await client.DeleteModelAsync(modelId);

                await client.DeleteModelAsync(componentModelId);
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete models due to {ex}");
            }
        }
        public async Task Query_ValidQuery_Success()
        {
            DigitalTwinsClient client = GetClient();

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // Create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(client, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // Create a room twin, with property "IsOccupied": true
                string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync(roomTwinId, roomTwin).ConfigureAwait(false);

                // Construct a query string to find the twins with the EXACT model id and provided version. If EXACT is not specified, the query
                // call will get all twins with the same model id but that implement any version higher than the provided version
                string queryString = $"SELECT * FROM digitaltwins WHERE IS_OF_MODEL('{roomModelId}', EXACT) AND IsOccupied = true";

                // act
                AsyncPageable <BasicDigitalTwin> asyncPageableResponse = client.QueryAsync <BasicDigitalTwin>(queryString);

                // assert

                // It takes a few seconds for the service to be able to fetch digital twins through queries after being created. Hence, adding the retry logic
                var digitalTwinFound = false;
                await TestRetryHelper.RetryAsync <AsyncPageable <BasicDigitalTwin> >(async() =>
                {
                    await foreach (BasicDigitalTwin response in asyncPageableResponse)
                    {
                        digitalTwinFound = true;
                        bool isOccupied  = ((JsonElement)response.Contents["IsOccupied"]).GetBoolean();
                        isOccupied.Should().BeTrue();
                        break;
                    }

                    if (!digitalTwinFound)
                    {
                        throw new Exception($"Digital twin based on model Id {roomModelId} not found");
                    }

                    return(null);
                }, s_retryCount, s_retryDelay);

                digitalTwinFound.Should().BeTrue();
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
        public async Task Query_PaginationWorks()
        {
            DigitalTwinsClient client = GetClient();
            int    pageSize           = 5;
            string floorModelId       = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            TimeSpan QueryWaitTimeout = TimeSpan.FromMinutes(1); // Wait at most one minute for the created twins to become queryable

            try
            {
                // Create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(client, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // Create a room twin, with property "IsOccupied": true
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);

                for (int i = 0; i < pageSize * 2; i++)
                {
                    string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

                    await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);
                }

                string queryString = "SELECT * FROM digitaltwins";

                // act
                CancellationTokenSource queryTimeoutCancellationToken = new CancellationTokenSource(QueryWaitTimeout);
                bool queryHasExpectedCount = false;
                while (!queryHasExpectedCount)
                {
                    if (queryTimeoutCancellationToken.IsCancellationRequested)
                    {
                        throw new AssertionException($"Timed out waiting for at least {pageSize + 1} twins to be queryable");
                    }

                    AsyncPageable <BasicDigitalTwin> asyncPageableResponse = client.QueryAsync <BasicDigitalTwin>(queryString, queryTimeoutCancellationToken.Token);
                    int count = 0;
                    await foreach (Page <BasicDigitalTwin> queriedTwinPage in asyncPageableResponse.AsPages(pageSizeHint: pageSize))
                    {
                        count += queriedTwinPage.Values.Count;
                    }

                    // Once at least (page + 1) twins are query-able, then page size control can be tested.
                    queryHasExpectedCount = count >= pageSize + 1;
                }

                // assert
                // Test that page size hint works, and that all returned pages either have the page size hint amount of
                // elements, or have no continuation token (signaling that it is the last page)
                int pageCount = 0;
                await foreach (Page <BasicDigitalTwin> page in client.QueryAsync <BasicDigitalTwin>(queryString).AsPages(pageSizeHint: pageSize))
                {
                    pageCount++;
                    if (page.ContinuationToken != null)
                    {
                        page.Values.Count.Should().Be(pageSize, "Unexpected page size for a non-terminal page");
                    }
                }

                pageCount.Should().BeGreaterThan(1, "Expected more than one page of query results");
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
        static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            string             adtInstanceUrl = "<youradturl>";
            var                credential     = new DefaultAzureCredential();
            DigitalTwinsClient client         = new DigitalTwinsClient(new Uri(adtInstanceUrl), credential);

            Console.WriteLine($"Service client created – ready to go");
            // uploading data
            Console.WriteLine();
            Console.WriteLine($"Upload a model");
            var    typeList = new List <string>();
            string dtdl     = File.ReadAllText("new.json");

            typeList.Add(dtdl);
            // Upload the model to the service
            try
            {
                await client.CreateModelsAsync(typeList);
            }
            catch (RequestFailedException rex)
            {
                Console.WriteLine($"Load model: {rex.Status}:{rex.Message}");
            }
            // now lets add more models based on the one just uploaded
            // Initialize twin data
            BasicDigitalTwin twinData = new BasicDigitalTwin();

            twinData.Metadata.ModelId = "dtmi:example:SampleModel;1";
            twinData.Contents.Add("data", $"Hello World!");

            string prefix = "sampleTwin-";

            for (int i = 0; i < 3; i++)
            {
                try
                {
                    twinData.Id = $"{prefix}{i}";
                    await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(twinData.Id, twinData);

                    Console.WriteLine($"Created twin: {prefix}{i}");
                }
                catch (RequestFailedException rex)
                {
                    Console.WriteLine($"Create twin error: {rex.Status}:{rex.Message}");
                }
            }
            // Connect the twins with relationships
            await CreateRelationship(client, "sampleTwin-0", "sampleTwin-1");
            await CreateRelationship(client, "sampleTwin-0", "sampleTwin-2");

            //List the relationships
            await ListRelationships(client, "sampleTwin-0");

            // Run a query for all twins
            string query = "SELECT * FROM digitaltwins";
            AsyncPageable <BasicDigitalTwin> result = client.QueryAsync <BasicDigitalTwin>(query);

            Console.WriteLine("---------------");
            await foreach (BasicDigitalTwin twin in result)
            {
                Console.WriteLine(JsonSerializer.Serialize(twin));
                Console.WriteLine("---------------");
            }
        }