// </FindOutgoingRelationshipsMethod> // <FindIncomingRelationshipsMethod> private static async Task <List <IncomingRelationship> > CustomMethod_FindIncomingRelationshipsAsync(DigitalTwinsClient client, string dtId) { // Find the relationships for the twin try { // GetRelationshipsAsync will throw an error if a problem occurs AsyncPageable <IncomingRelationship> incomingRels = client.GetIncomingRelationshipsAsync(dtId); var results = new List <IncomingRelationship>(); await foreach (IncomingRelationship incomingRel in incomingRels) { results.Add(incomingRel); Console.WriteLine($"Found incoming relationship: {incomingRel.RelationshipId}"); //Print its properties Response <BasicRelationship> relResponse = await client.GetRelationshipAsync <BasicRelationship>(incomingRel.SourceId, incomingRel.RelationshipId); BasicRelationship rel = relResponse.Value; Console.WriteLine($"Relationship properties:"); foreach (KeyValuePair <string, object> property in rel.Properties) { Console.WriteLine("{0} = {1}", property.Key, property.Value); } } return(results); } catch (RequestFailedException ex) { Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving incoming relationships for {dtId} due to {ex.Message}"); return(null); } }
async public void ListRelationshipProperties(DigitalTwinsClient client, string twinId, string relId, BasicDigitalTwin twin) { // ------------------ LIST PROPERTIES OF RELATIONSHIPS --------------------- // <ListRelationshipProperties> var res = await client.GetRelationshipAsync <BasicRelationship>(twinId, relId); BasicRelationship rel = res.Value; Console.WriteLine($"Relationship Name: {rel.Name}"); foreach (string prop in rel.Properties.Keys) { if (twin.Contents.TryGetValue(prop, out object value)) { Console.WriteLine($"Property '{prop}': {value}"); } } // </ListRelationshipProperties> }
/// <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 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"); // Create a building digital twin model. string buildingModelPayload = SamplesConstants.TemporaryModelWithRelationshipPayload .Replace(SamplesConstants.ModelId, "dtmi:samples:SampleBuilding;1") .Replace(SamplesConstants.ModelDisplayName, "Building") .Replace(SamplesConstants.RelationshipName, "contains") .Replace(SamplesConstants.RelationshipTargetModelId, "dtmi:samples:SampleFloor;1"); Response <IReadOnlyList <Models.ModelData> > createBuildingModelResponse = await client.CreateModelsAsync( new[] { buildingModelPayload }); Console.WriteLine($"Created model with Id dtmi:samples:SampleBuilding;1. Response status: {createBuildingModelResponse.GetRawResponse().Status}."); // Create a floor digital twin model. string floorModelPayload = SamplesConstants.TemporaryModelWithRelationshipPayload .Replace(SamplesConstants.ModelId, "dtmi:samples:SampleFloor;1") .Replace(SamplesConstants.ModelDisplayName, "Floor") .Replace(SamplesConstants.RelationshipName, "containedIn") .Replace(SamplesConstants.RelationshipTargetModelId, "dtmi:samples:SampleBuilding;1"); Response <IReadOnlyList <Models.ModelData> > createFloorModelResponse = await client.CreateModelsAsync( new[] { floorModelPayload }); Console.WriteLine($"Created model with Id dtmi:samples:SampleFloor;1. Response status: {createFloorModelResponse.GetRawResponse().Status}."); // Create a building digital twin. var buildingDigitalTwin = new BasicDigitalTwin { Id = "buildingTwinId", Metadata = { ModelId = "dtmi:samples:SampleBuilding;1" } }; string buildingDigitalTwinPayload = JsonSerializer.Serialize(buildingDigitalTwin); Response <string> createBuildingDigitalTwinResponse = await client.CreateDigitalTwinAsync("buildingTwinId", buildingDigitalTwinPayload); Console.WriteLine($"Created a digital twin with Id buildingTwinId. Response status: {createBuildingDigitalTwinResponse.GetRawResponse().Status}."); // Create a floor digital. var floorDigitalTwin = new BasicDigitalTwin { Id = "floorTwinId", Metadata = { ModelId = "dtmi:samples:SampleFloor;1" } }; string floorDigitalTwinPayload = JsonSerializer.Serialize(floorDigitalTwin); Response <string> createFloorDigitalTwinResponse = await client.CreateDigitalTwinAsync("floorTwinId", floorDigitalTwinPayload); Console.WriteLine($"Created a digital twin with Id floorTwinId. Response status: {createFloorDigitalTwinResponse.GetRawResponse().Status}."); // 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", CustomProperties = { { "Prop1", "Prop1 value" }, { "Prop2", 6 } } }; string serializedRelationship = JsonSerializer.Serialize(buildingFloorRelationshipPayload); Response <string> createRelationshipResponse = await client.CreateRelationshipAsync("buildingTwinId", "buildingFloorRelationshipId", serializedRelationship); Console.WriteLine($"Created a digital twin relationship with Id buildingFloorRelationshipId from digital twin with Id buildingTwinId to digital twin with Id floorTwinId. " + $"Response status: {createRelationshipResponse.GetRawResponse().Status}."); #endregion Snippet:DigitalTwinsSampleCreateBasicRelationship // You can get a relationship and deserialize it into a BasicRelationship. #region Snippet:DigitalTwinsSampleGetBasicRelationship Response <string> getBasicRelationshipResponse = await client.GetRelationshipAsync("buildingTwinId", "buildingFloorRelationshipId"); if (getBasicRelationshipResponse.GetRawResponse().Status == (int)HttpStatusCode.OK) { BasicRelationship basicRelationship = JsonSerializer.Deserialize <BasicRelationship>(getBasicRelationshipResponse.Value); Console.WriteLine($"Retrieved relationship with Id {basicRelationship.Id} from digital twin with Id {basicRelationship.SourceId}. " + $"Response status: {getBasicRelationshipResponse.GetRawResponse().Status}.\n\t" + $"Prop1: {basicRelationship.CustomProperties["Prop1"]}\n\t" + $"Prop2: {basicRelationship.CustomProperties["Prop2"]}"); } #endregion Snippet:DigitalTwinsSampleGetBasicRelationship // Alternatively, you can create your own custom data types to serialize and deserialize your relationships. // 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 }; string serializedCustomRelationship = JsonSerializer.Serialize(floorBuildingRelationshipPayload); Response <string> createCustomRelationshipResponse = await client.CreateRelationshipAsync("floorTwinId", "floorBuildingRelationshipId", serializedCustomRelationship); Console.WriteLine($"Created a digital twin relationship with Id floorBuildingRelationshipId from digital twin with Id floorTwinId to digital twin with Id buildingTwinId. " + $"Response status: {createCustomRelationshipResponse.GetRawResponse().Status}."); #endregion Snippet:DigitalTwinsSampleCreateCustomRelationship // Getting and deserializing a relationship into a custom data type is extremely easy. #region Snippet:DigitalTwinsSampleGetCustomRelationship Response <string> getCustomRelationshipResponse = await client.GetRelationshipAsync("floorTwinId", "floorBuildingRelationshipId"); if (getCustomRelationshipResponse.GetRawResponse().Status == (int)HttpStatusCode.OK) { CustomRelationship getCustomRelationship = JsonSerializer.Deserialize <CustomRelationship>(getCustomRelationshipResponse.Value); Console.WriteLine($"Retrieved and deserialized relationship with Id {getCustomRelationship.Id} from digital twin with Id {getCustomRelationship.SourceId}. " + $"Response status: {getCustomRelationshipResponse.GetRawResponse().Status}.\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 <string> relationships = client.GetRelationshipsAsync("buildingTwinId"); await foreach (var relationshipJson in relationships) { BasicRelationship relationship = JsonSerializer.Deserialize <BasicRelationship>(relationshipJson); Console.WriteLine($"Found relationship with Id {relationship.Id} with a digital twin source Id {relationship.SourceId} and " + $"a digital twin target Id {relationship.TargetId}. \n\t " + $"Prop1: {relationship.CustomProperties["Prop1"]}\n\t" + $"Prop2: {relationship.CustomProperties["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 with Id {incomingRelationship.RelationshipId} coming from a digital twin with Id {incomingRelationship.SourceId}."); } #endregion Snippet:DigitalTwinsSampleGetIncomingRelationships // Delete the contains relationship, created earlier in the sample code, from building to floor. #region Snippet:DigitalTwinsSampleDeleteRelationship Response deleteBuildingRelationshipResponse = await client.DeleteRelationshipAsync("buildingTwinId", "buildingFloorRelationshipId"); Console.WriteLine($"Deleted relationship with Id buildingFloorRelationshipId. Status response: {deleteBuildingRelationshipResponse.Status}."); #endregion Snippet:DigitalTwinsSampleDeleteRelationship // Delete the containedIn relationship, created earlier in the sample code, from floor to building. Response deleteFloorRelationshipResponse = await client.DeleteRelationshipAsync("floorTwinId", "floorBuildingRelationshipId"); Console.WriteLine($"Deleted relationship with Id floorBuildingRelationshipId. Status response: {deleteFloorRelationshipResponse.Status}."); // Clean up. try { // Delete all twins await client.DeleteDigitalTwinAsync("buildingTwinId"); await client.DeleteDigitalTwinAsync("floorTwinId"); } catch (RequestFailedException ex) { Console.WriteLine($"Failed to delete digital twin due to {ex}."); } try { await client.DeleteModelAsync("dtmi:samples:SampleBuilding;1"); await client.DeleteModelAsync("dtmi:samples:SampleFloor;1"); } catch (RequestFailedException ex) { Console.WriteLine($"Failed to delete model due to {ex}."); } }
public async Task Relationships_Lifecycle() { // arrange DigitalTwinsClient client = GetClient(); var floorContainsRoomRelationshipId = "FloorToRoomRelationship"; var floorCooledByHvacRelationshipId = "FloorToHvacRelationship"; var hvacCoolsFloorRelationshipId = "HvacToFloorRelationship"; var roomContainedInFloorRelationshipId = "RoomToFloorRelationship"; string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false); string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false); string hvacModelId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.HvacModelIdPrefix).ConfigureAwait(false); string floorTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.FloorTwinIdPrefix).ConfigureAwait(false); string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false); string hvacTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.HvacTwinIdPrefix).ConfigureAwait(false); try { // create floor, room and hvac model string floorModel = TestAssetsHelper.GetFloorModelPayload(floorModelId, roomModelId, hvacModelId); string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId); string hvacModel = TestAssetsHelper.GetHvacModelPayload(hvacModelId, floorModelId); await client.CreateModelsAsync(new List <string> { floorModel, roomModel, hvacModel }).ConfigureAwait(false); // create floor twin BasicDigitalTwin floorTwin = TestAssetsHelper.GetFloorTwinPayload(floorModelId); await client.CreateDigitalTwinAsync <BasicDigitalTwin>(floorTwinId, floorTwin).ConfigureAwait(false); // Create room twin BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId); await client.CreateDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false); // create hvac twin BasicDigitalTwin hvacTwin = TestAssetsHelper.GetHvacTwinPayload(hvacModelId); await client.CreateDigitalTwinAsync <BasicDigitalTwin>(hvacTwinId, hvacTwin).ConfigureAwait(false); BasicRelationship floorContainsRoomPayload = TestAssetsHelper.GetRelationshipWithPropertyPayload(roomTwinId, ContainsRelationship, "isAccessRestricted", true); BasicRelationship floorTwinCoolsRelationshipPayload = TestAssetsHelper.GetRelationshipPayload(floorTwinId, CoolsRelationship); BasicRelationship floorTwinContainedInRelationshipPayload = TestAssetsHelper.GetRelationshipPayload(floorTwinId, ContainedInRelationship); BasicRelationship floorCooledByHvacPayload = TestAssetsHelper.GetRelationshipPayload(hvacTwinId, CooledByRelationship); JsonPatchDocument floorContainsRoomUpdatePayload = new JsonPatchDocument(); floorContainsRoomUpdatePayload.AppendReplace("/isAccessRestricted", false); // CREATE relationships // create Relationship from Floor -> Room await client .CreateRelationshipAsync <BasicRelationship>( floorTwinId, floorContainsRoomRelationshipId, floorContainsRoomPayload) .ConfigureAwait(false); // create Relationship from Floor -> Hvac await client .CreateRelationshipAsync <BasicRelationship>( floorTwinId, floorCooledByHvacRelationshipId, floorCooledByHvacPayload) .ConfigureAwait(false); // create Relationship from Hvac -> Floor await client .CreateRelationshipAsync <BasicRelationship>( hvacTwinId, hvacCoolsFloorRelationshipId, floorTwinCoolsRelationshipPayload) .ConfigureAwait(false); // create Relationship from Room -> Floor await client .CreateRelationshipAsync <BasicRelationship>( roomTwinId, roomContainedInFloorRelationshipId, floorTwinContainedInRelationshipPayload) .ConfigureAwait(false); // UPDATE relationships // create Relationship from Floor -> Room await client .UpdateRelationshipAsync( floorTwinId, floorContainsRoomRelationshipId, floorContainsRoomUpdatePayload) .ConfigureAwait(false); // GET relationship Response <BasicRelationship> containsRelationshipId = await client .GetRelationshipAsync <BasicRelationship>( floorTwinId, floorContainsRoomRelationshipId) .ConfigureAwait(false); // LIST incoming relationships AsyncPageable <IncomingRelationship> incomingRelationships = client.GetIncomingRelationshipsAsync(floorTwinId); int numberOfIncomingRelationshipsToFloor = 0; await foreach (IncomingRelationship relationship in incomingRelationships) { ++numberOfIncomingRelationshipsToFloor; } numberOfIncomingRelationshipsToFloor.Should().Be(2, "floor has incoming relationships from room and hvac"); // LIST relationships AsyncPageable <string> floorRelationships = client.GetRelationshipsAsync(floorTwinId); int numberOfFloorRelationships = 0; await foreach (var relationship in floorRelationships) { ++numberOfFloorRelationships; } numberOfFloorRelationships.Should().Be(2, "floor has an relationship to room and hvac"); // LIST relationships by name AsyncPageable <string> roomTwinRelationships = client .GetRelationshipsAsync( roomTwinId, ContainedInRelationship); containsRelationshipId.Value.Id.Should().Be(floorContainsRoomRelationshipId); int numberOfRelationships = 0; await foreach (var relationship in roomTwinRelationships) { ++numberOfRelationships; } numberOfRelationships.Should().Be(1, "room has only one containedIn relationship to floor"); await client .DeleteRelationshipAsync( floorTwinId, floorContainsRoomRelationshipId) .ConfigureAwait(false); await client .DeleteRelationshipAsync( roomTwinId, roomContainedInFloorRelationshipId) .ConfigureAwait(false); await client .DeleteRelationshipAsync( floorTwinId, floorCooledByHvacRelationshipId) .ConfigureAwait(false); await client .DeleteRelationshipAsync( hvacTwinId, hvacCoolsFloorRelationshipId) .ConfigureAwait(false); Func <Task> act = async() => { await client .GetRelationshipAsync <BasicRelationship>( floorTwinId, floorContainsRoomRelationshipId) .ConfigureAwait(false); }; act.Should().Throw <RequestFailedException>() .And.Status.Should().Be((int)HttpStatusCode.NotFound); act = async() => { await client .GetRelationshipAsync <BasicRelationship>( roomTwinId, roomContainedInFloorRelationshipId) .ConfigureAwait(false); }; act.Should().Throw <RequestFailedException>(). And.Status.Should().Be((int)HttpStatusCode.NotFound); act = async() => { await client .GetRelationshipAsync <BasicRelationship>( floorTwinId, floorCooledByHvacRelationshipId) .ConfigureAwait(false); }; act.Should().Throw <RequestFailedException>(). And.Status.Should().Be((int)HttpStatusCode.NotFound); act = async() => { await client .GetRelationshipAsync <BasicRelationship>( hvacTwinId, hvacCoolsFloorRelationshipId) .ConfigureAwait(false); }; act.Should().Throw <RequestFailedException>() .And.Status.Should().Be((int)HttpStatusCode.NotFound); } finally { // clean up try { await Task .WhenAll( client.DeleteDigitalTwinAsync(floorTwinId), client.DeleteDigitalTwinAsync(roomTwinId), client.DeleteDigitalTwinAsync(hvacTwinId), client.DeleteModelAsync(hvacModelId), client.DeleteModelAsync(floorModelId), client.DeleteModelAsync(roomModelId)) .ConfigureAwait(false); } catch (Exception ex) { Assert.Fail($"Test clean up failed: {ex.Message}"); } } }