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); }
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); }
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}"); } } }
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}"); } }
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); }
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); }
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); }
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); }
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(); }
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> }
/// <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}"); } } }
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); }
/// <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}"); } }
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(); } }
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}"); } }
/// <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("---------------"); } }