From 6a8d65fd07a8f5233b1f8cba396e3adf8171bf8a Mon Sep 17 00:00:00 2001 From: "David R. Williamson" Date: Thu, 4 Jun 2020 17:46:15 -0700 Subject: [PATCH] samples(adt): more misc changes per Azure SDK review (#12532) --- .../Azure.DigitalTwins.Core.netstandard2.0.cs | 6 +- .../ComponentSamples.cs | 74 +++++++---- .../DigitalTwinsLifecycleSamples.cs | 12 +- .../ModelLifecycleSamples.cs | 3 +- .../Azure.DigitalTwins.Core/samples/Readme.md | 124 +++++++++++------- .../src/DigitalTwinsClient.cs | 41 ++++-- .../src/Serialization/BasicDigitalTwin.cs | 48 ++++--- .../src/Serialization/DigitalTwinMetadata.cs | 2 +- .../src/Serialization/ModelProperties.cs | 4 +- 9 files changed, 203 insertions(+), 111 deletions(-) diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/api/Azure.DigitalTwins.Core.netstandard2.0.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/api/Azure.DigitalTwins.Core.netstandard2.0.cs index faaa813f09fb..493fbee45b21 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/api/Azure.DigitalTwins.Core.netstandard2.0.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/api/Azure.DigitalTwins.Core.netstandard2.0.cs @@ -150,15 +150,15 @@ public DigitalTwinMetadata() { } [System.Text.Json.Serialization.JsonPropertyNameAttribute("$model")] public string ModelId { get { throw null; } set { } } [System.Text.Json.Serialization.JsonExtensionDataAttribute] - public System.Collections.Generic.IDictionary WriteableProperties { get { throw null; } set { } } + public System.Collections.Generic.IDictionary WriteableProperties { get { throw null; } } } public partial class ModelProperties { public ModelProperties() { } [System.Text.Json.Serialization.JsonExtensionDataAttribute] - public System.Collections.Generic.IDictionary CustomProperties { get { throw null; } set { } } + public System.Collections.Generic.IDictionary CustomProperties { get { throw null; } } [System.Text.Json.Serialization.JsonPropertyNameAttribute("$metadata")] - public Azure.DigitalTwins.Core.Serialization.DigitalTwinMetadata Metadata { get { throw null; } set { } } + public Azure.DigitalTwins.Core.Serialization.DigitalTwinMetadata Metadata { get { throw null; } } } public partial class UpdateOperationsUtility { diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ComponentSamples.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ComponentSamples.cs index 383f0fb421b3..8d3fe70e3fb5 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ComponentSamples.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ComponentSamples.cs @@ -36,30 +36,47 @@ public async Task RunSamplesAsync(DigitalTwinsClient client) .Replace(SamplesConstants.ComponentId, componentModelId); // Then we create models - Response> createModelsResponse = await client - .CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload }); - Console.WriteLine($"Successfully created models Ids {componentModelId} and {modelId} with response {createModelsResponse.GetRawResponse().Status}."); + Response> createModelsResponse = await client.CreateModelsAsync( + new[] + { + newComponentModelPayload, + newModelPayload + }); + Console.WriteLine($"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 + var basicTwin = new BasicDigitalTwin { - Id = basicDtId + Id = basicDtId, + // model Id of digital twin + Metadata = { ModelId = modelId }, + CustomProperties = + { + // digital twin properties + { "Prop1", "Value1" }, + { "Prop2", 987 }, + // component + { + "Component1", + new ModelProperties + { + // model Id of component + Metadata = { ModelId = componentModelId }, + // component properties + CustomProperties = + { + { "ComponentProp1", "Component value 1" }, + { "ComponentProp2", 123 }, + }, + } + }, + }, }; - basicDigitalTwin.Metadata.ModelId = modelId; - basicDigitalTwin.CustomProperties.Add("Prop1", "Value1"); - basicDigitalTwin.CustomProperties.Add("Prop2", 987); - - var componentMetadata = new ModelProperties(); - componentMetadata.Metadata.ModelId = componentModelId; - componentMetadata.CustomProperties.Add("ComponentProp1", "ComponentValue1"); - componentMetadata.CustomProperties.Add("ComponentProp2", 123); - - basicDigitalTwin.CustomProperties.Add("Component1", componentMetadata); - string basicDtPayload = JsonSerializer.Serialize(basicDigitalTwin); + string basicDtPayload = JsonSerializer.Serialize(basicTwin); Response createBasicDtResponse = await client.CreateDigitalTwinAsync(basicDtId, basicDtPayload); Console.WriteLine($"Created digital twin {basicDtId} with response {createBasicDtResponse.GetRawResponse().Status}."); @@ -81,21 +98,25 @@ public async Task RunSamplesAsync(DigitalTwinsClient client) string component1RawText = ((JsonElement)basicDt.CustomProperties["Component1"]).GetRawText(); var component1 = JsonSerializer.Deserialize>(component1RawText); - Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id} with ETag {basicDt.ETag} " + - $"and Prop1: '{basicDt.CustomProperties["Prop1"]}', Prop2: {basicDt.CustomProperties["Prop2"]}," + - $"ComponentProp1: '{component1["ComponentProp1"]}', ComponentProp2: {component1["ComponentProp2"]}"); + Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id}:\n\t" + + $"ETag: {basicDt.ETag}\n\t" + + $"Prop1: {basicDt.CustomProperties["Prop1"]}\n\t" + + $"Prop2: {basicDt.CustomProperties["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 - string customDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client); - var customDigitalTwin = new CustomDigitalTwin + var customTwin = new CustomDigitalTwin { Id = customDtId, Metadata = new CustomDigitalTwinMetadata { ModelId = modelId }, @@ -108,7 +129,7 @@ public async Task RunSamplesAsync(DigitalTwinsClient client) ComponentProp2 = 123, } }; - string dt2Payload = JsonSerializer.Serialize(customDigitalTwin); + string dt2Payload = JsonSerializer.Serialize(customTwin); Response createCustomDtResponse = await client.CreateDigitalTwinAsync(customDtId, dt2Payload); Console.WriteLine($"Created digital twin {customDtId} with response {createCustomDtResponse.GetRawResponse().Status}."); @@ -124,9 +145,12 @@ public async Task RunSamplesAsync(DigitalTwinsClient client) if (getCustomDtResponse.GetRawResponse().Status == (int)HttpStatusCode.OK) { CustomDigitalTwin customDt = JsonSerializer.Deserialize(getCustomDtResponse.Value); - Console.WriteLine($"Retrieved and deserialized digital twin {customDt.Id} with ETag {customDt.ETag} " + - $"and Prop1: '{customDt.Prop1}', Prop2: {customDt.Prop2}," + - $"ComponentProp1: '{customDt.Component1.ComponentProp1}', ComponentProp2: {customDt.Component1.ComponentProp2}"); + 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 diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsLifecycleSamples.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsLifecycleSamples.cs index c1febb41259a..6e016a8b3ea4 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsLifecycleSamples.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsLifecycleSamples.cs @@ -354,12 +354,14 @@ public async Task ConnectTwinsTogetherAsync() // We deserialize as BasicRelationship to get the entire custom relationship (custom relationship properties). IEnumerable relationships = JsonSerializer.Deserialize>(relationshipSet.Value); + #region Snippet:DigitalTwinsSampleCreateRelationship + + // From loaded relationships, get the source Id and Id from each one, + // and create it with full relationship payload foreach (BasicRelationship relationship in relationships) { try { - #region Snippet:DigitalTwinsSampleCreateRelationship - string serializedRelationship = JsonSerializer.Serialize(relationship); await client.CreateRelationshipAsync( @@ -367,15 +369,15 @@ await client.CreateRelationshipAsync( relationship.Id, serializedRelationship); - #endregion Snippet:DigitalTwinsSampleCreateRelationship - - Console.WriteLine($"Linked {serializedRelationship}"); + Console.WriteLine($"Linked twin {relationship.SourceId} to twin {relationship.TargetId} as '{relationship.Name}'"); } catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.Conflict) { Console.WriteLine($"Relationship {relationship.Id} already exists: {ex.Message}"); } } + + #endregion Snippet:DigitalTwinsSampleCreateRelationship } } diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ModelLifecycleSamples.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ModelLifecycleSamples.cs index 295fa6e20e55..785b67bd8ee7 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ModelLifecycleSamples.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ModelLifecycleSamples.cs @@ -79,10 +79,9 @@ public async Task RunSamplesAsync(DigitalTwinsClient client) try { await client.DecommissionModelAsync(sampleModelId); - Console.WriteLine($"Successfully decommissioned model {sampleModelId}"); } - catch (Exception ex) + catch (RequestFailedException ex) { FatalError($"Failed to decommision model {sampleModelId} due to:\n{ex}"); } diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/Readme.md b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/Readme.md index 7d07589c8c88..78496e312cc3 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/Readme.md +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/Readme.md @@ -1,13 +1,16 @@ # Digital Twins Samples -You can explore azure digital twin APIs (using the SDK) using the samples project. +You can explore azure digital twin APIs (using the client library) using the samples project. + Sample project demonstrates the following: -* Create, get, and decommission models -* Create, query, and delete a Digital Twin -* Get and update components for a Digital Twin -* Create, get, and delete relationships between Digital Twins -* Create, get, and delete event routes for Digital Twin -* Publish telemetry messages to a Digital Twin and Digital Twin component + +- Instantiate the client +- Create, get, and decommission models +- Create, query, and delete a digital twin +- Get and update components for a digital twin +- Create, get, and delete relationships between digital twins +- Create, get, and delete event routes for digital twin +- Publish telemetry messages to a digital twin and digital twin component ## Creating the digital twins client @@ -16,6 +19,9 @@ In the sample below, you can set `AdtEndpoint`, `TenantId`, `ClientId`, and `Cli The client requires an instance of [TokenCredential](https://docs.microsoft.com/en-us/dotnet/api/azure.core.tokencredential?view=azure-dotnet). In this samples, we illustrate how to use one derived class: ClientSecretCredential. +> Note: In order to access the data plane for the Digital Twins service, the entity must be given permissions. +> To do this, use the Azure CLI command: `az dt rbac assign-role --assignee '' --role owner -n ''` + ```C# Snippet:DigitalTwinsSampleCreateServiceClientWithClientSecret // By using the ClientSecretCredential, a specified application Id can login using a // client secret. @@ -42,7 +48,8 @@ It provides an opportunity to override default behavior including: ### Create models -Let's create models using the code below. You need to pass in List containing list of json models. Check out sample models [here](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models) +Let's create models using the code below. You need to pass in `List` containing list of json models. +Check out sample models [here](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models). ```C# Snippet:DigitalTwinsSampleCreateModels Response> response = await client.CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload }); @@ -51,7 +58,7 @@ Console.WriteLine($"Successfully created a model with Id: {newComponentModelId}, ### List models -Using `GetModelsAsync`, all created models are returned as AsyncPageable +Using `GetModelsAsync`, all created models are returned as `AsyncPageable`. ```C# Snippet:DigitalTwinsSampleGetModels AsyncPageable allModels = client.GetModelsAsync(); @@ -61,7 +68,7 @@ await foreach (ModelData model in allModels) } ``` -Use `GetModelAsync` with model's unique identifier to get a specific model +Use `GetModelAsync` with model's unique identifier to get a specific model. ```C# Snippet:DigitalTwinsSampleGetModel Response sampleModel = await client.GetModelAsync(sampleModelId); @@ -75,10 +82,9 @@ To decommision a model, pass in a model Id for the model you want to decommision try { await client.DecommissionModelAsync(sampleModelId); - Console.WriteLine($"Successfully decommissioned model {sampleModelId}"); } -catch (Exception ex) +catch (RequestFailedException ex) { FatalError($"Failed to decommision model {sampleModelId} due to:\n{ex}"); } @@ -113,34 +119,46 @@ It uses functionality from the `System.Text.Json` library to maintain any unmapp ```C# Snippet:DigitalTwinsSampleCreateBasicTwin // Create digital twin with component payload using the BasicDigitalTwin serialization helper -var basicDigitalTwin = new BasicDigitalTwin +var basicTwin = new BasicDigitalTwin { - Id = basicDtId + Id = basicDtId, + // model Id of digital twin + Metadata = { ModelId = modelId }, + CustomProperties = + { + // digital twin properties + { "Prop1", "Value1" }, + { "Prop2", 987 }, + // component + { + "Component1", + new ModelProperties + { + // model Id of component + Metadata = { ModelId = componentModelId }, + // component properties + CustomProperties = + { + { "ComponentProp1", "Component value 1" }, + { "ComponentProp2", 123 }, + }, + } + }, + }, }; -basicDigitalTwin.Metadata.ModelId = modelId; -basicDigitalTwin.CustomProperties.Add("Prop1", "Value1"); -basicDigitalTwin.CustomProperties.Add("Prop2", 987); - -var componentMetadata = new ModelProperties(); -componentMetadata.Metadata.ModelId = componentModelId; -componentMetadata.CustomProperties.Add("ComponentProp1", "ComponentValue1"); -componentMetadata.CustomProperties.Add("ComponentProp2", 123); - -basicDigitalTwin.CustomProperties.Add("Component1", componentMetadata); -string basicDtPayload = JsonSerializer.Serialize(basicDigitalTwin); +string basicDtPayload = JsonSerializer.Serialize(basicTwin); Response createBasicDtResponse = await client.CreateDigitalTwinAsync(basicDtId, basicDtPayload); Console.WriteLine($"Created digital twin {basicDtId} with response {createBasicDtResponse.GetRawResponse().Status}."); ``` 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. +By specifying your properties and types directly, it requires less code or knowledge of the type for interaction. +You can review the [CustomDigitalTwin definition](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/CustomDigitalTwin.cs). ```C# Snippet:DigitalTwinsSampleCreateCustomTwin -string customDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client); -var customDigitalTwin = new CustomDigitalTwin +var customTwin = new CustomDigitalTwin { Id = customDtId, Metadata = new CustomDigitalTwinMetadata { ModelId = modelId }, @@ -153,7 +171,7 @@ var customDigitalTwin = new CustomDigitalTwin ComponentProp2 = 123, } }; -string dt2Payload = JsonSerializer.Serialize(customDigitalTwin); +string dt2Payload = JsonSerializer.Serialize(customTwin); Response createCustomDtResponse = await client.CreateDigitalTwinAsync(customDtId, dt2Payload); Console.WriteLine($"Created digital twin {customDtId} with response {createCustomDtResponse.GetRawResponse().Status}."); @@ -175,9 +193,12 @@ if (getBasicDtResponse.GetRawResponse().Status == (int)HttpStatusCode.OK) string component1RawText = ((JsonElement)basicDt.CustomProperties["Component1"]).GetRawText(); var component1 = JsonSerializer.Deserialize>(component1RawText); - Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id} with ETag {basicDt.ETag} " + - $"and Prop1: '{basicDt.CustomProperties["Prop1"]}', Prop2: {basicDt.CustomProperties["Prop2"]}," + - $"ComponentProp1: '{component1["ComponentProp1"]}', ComponentProp2: {component1["ComponentProp2"]}"); + Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id}:\n\t" + + $"ETag: {basicDt.ETag}\n\t" + + $"Prop1: {basicDt.CustomProperties["Prop1"]}\n\t" + + $"Prop2: {basicDt.CustomProperties["Prop2"]}\n\t" + + $"ComponentProp1: {component1["ComponentProp1"]}\n\t" + + $"ComponentProp2: {component1["ComponentProp2"]}"); } ``` @@ -185,8 +206,7 @@ Getting and deserializing a digital twin into a custom data type is extremely ea Custom types provide the best possible experience. ```C# Snippet:DigitalTwinsSampleCreateCustomTwin -string customDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client); -var customDigitalTwin = new CustomDigitalTwin +var customTwin = new CustomDigitalTwin { Id = customDtId, Metadata = new CustomDigitalTwinMetadata { ModelId = modelId }, @@ -199,7 +219,7 @@ var customDigitalTwin = new CustomDigitalTwin ComponentProp2 = 123, } }; -string dt2Payload = JsonSerializer.Serialize(customDigitalTwin); +string dt2Payload = JsonSerializer.Serialize(customTwin); Response createCustomDtResponse = await client.CreateDigitalTwinAsync(customDtId, dt2Payload); Console.WriteLine($"Created digital twin {customDtId} with response {createCustomDtResponse.GetRawResponse().Status}."); @@ -267,7 +287,7 @@ await client.DeleteDigitalTwinAsync(twin.Key); ### Update digital twin components -To update a component or in other words to replace, remove and/or add a component property or subproperty within Digital Twin, you would need Id of a digital twin, component name and application/json-patch+json operations to be performed on the specified digital twin's component. Here is the sample code on how to do it. +To update a component or in other words to replace, remove and/or add a component property or subproperty within Digital Twin, you would need Id of a digital twin, component name and application/json-patch+json operations to be performed on the specified digital twin's component. Here is the sample code on how to do it. ```C# Snippet:DigitalTwinsSampleUpdateComponent // Update Component1 by replacing the property ComponentProp1 value @@ -282,7 +302,7 @@ Console.WriteLine($"Updated component for digital twin {basicDtId}. Update respo ### Get digital twin components -Get a component by providing name of a component and Id of digital twin it belongs to. +Get a component by providing name of a component and Id of digital twin to which it belongs. ```C# Snippet:DigitalTwinsSampleGetComponent response = await client.GetComponentAsync(basicDtId, SamplesConstants.ComponentPath); @@ -297,16 +317,30 @@ Console.WriteLine($"Get component for digital twin: \n{response.Value}. Get resp `CreateRelationshipAsync` creates a relationship on a digital twin provided with Id of a digital twin, name of relationship such as "contains", Id of an relationship such as "FloorContainsRoom" and an application/json relationship to be created. Must contain property with key "$targetId" to specify the target of the relationship. Sample payloads for relationships can be found [here](https://github.com/Azure/azure-sdk-for-net-pr/blob/feature/IoT-ADT/sdk/iot/Azure.Iot.DigitalTwins/samples/DigitalTwinServiceClientSample/DTDL/Relationships/HospitalRelationships.json "RelationshipExamples"). ```C# Snippet:DigitalTwinsSampleCreateRelationship -string serializedRelationship = JsonSerializer.Serialize(relationship); +// From loaded relationships, get the source Id and Id from each one, +// and create it with full relationship payload +foreach (BasicRelationship relationship in relationships) +{ + try + { + string serializedRelationship = JsonSerializer.Serialize(relationship); -await client.CreateRelationshipAsync( - relationship.SourceId, - relationship.Id, - serializedRelationship); + await client.CreateRelationshipAsync( + relationship.SourceId, + relationship.Id, + serializedRelationship); + + Console.WriteLine($"Linked twin {relationship.SourceId} to twin {relationship.TargetId} as '{relationship.Name}'"); + } + catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.Conflict) + { + Console.WriteLine($"Relationship {relationship.Id} already exists: {ex.Message}"); + } +} ``` ### List digital twin relationships -`GetrelationshipsAsync` and `GetIncomingRelationshipsAsync` lists all the relationships and all incoming relationships respectively of a digital twin +`GetrelationshipsAsync` and `GetIncomingRelationshipsAsync` lists all the relationships and all incoming relationships respectively of a digital twin. ```C# Snippet:DigitalTwinsSampleGetRelationships AsyncPageable relationships = client.GetRelationshipsAsync(twin.Key); @@ -332,6 +366,8 @@ var eventRoute = new EventRoute(eventhubEndpointName) Response createEventRouteResponse = await client.CreateEventRouteAsync(_eventRouteId, eventRoute); ``` +For more information on the event route filter language, see the "how to manage routes" [filter events documentation](https://github.com/Azure/azure-digital-twins/blob/private-preview/Documentation/how-to-manage-routes.md#filter-events). + ### List event routes List a specific event route given event route Id or all event routes setting options with `GetEventRouteAsync` and `GetEventRoutesAsync`. diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClient.cs index e7b1a4dc2ba3..43c56f41fb31 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClient.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClient.cs @@ -140,9 +140,12 @@ protected DigitalTwinsClient() /// if (getCustomDtResponse.GetRawResponse().Status == (int)HttpStatusCode.OK) /// { /// CustomDigitalTwin customDt = JsonSerializer.Deserialize<CustomDigitalTwin>(getCustomDtResponse.Value); - /// Console.WriteLine($"Retrieved and deserialized digital twin {customDt.Id} with ETag {customDt.ETag} " + - /// $"and Prop1: '{customDt.Prop1}', Prop2: {customDt.Prop2}," + - /// $"ComponentProp1: '{customDt.Component1.ComponentProp1}', ComponentProp2: {customDt.Component1.ComponentProp2}"); + /// 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}"); /// } /// /// @@ -188,8 +191,7 @@ public virtual Response GetDigitalTwin(string digitalTwinId, Cancellatio /// /// /// - /// string customDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client); - /// var customDigitalTwin = new CustomDigitalTwin + /// var customTwin = new CustomDigitalTwin /// { /// Id = customDtId, /// Metadata = new CustomDigitalTwinMetadata { ModelId = modelId }, @@ -202,7 +204,7 @@ public virtual Response GetDigitalTwin(string digitalTwinId, Cancellatio /// ComponentProp2 = 123, /// } /// }; - /// string dt2Payload = JsonSerializer.Serialize(customDigitalTwin); + /// string dt2Payload = JsonSerializer.Serialize(customTwin); /// /// Response<string> createCustomDtResponse = await client.CreateDigitalTwinAsync(customDtId, dt2Payload); /// Console.WriteLine($"Created digital twin {customDtId} with response {createCustomDtResponse.GetRawResponse().Status}."); @@ -744,12 +746,26 @@ public virtual Response DeleteRelationship(string digitalTwinId, string relation /// /// /// - /// string serializedRelationship = JsonSerializer.Serialize(relationship); + /// // From loaded relationships, get the source Id and Id from each one, + /// // and create it with full relationship payload + /// foreach (BasicRelationship relationship in relationships) + /// { + /// try + /// { + /// string serializedRelationship = JsonSerializer.Serialize(relationship); + /// + /// await client.CreateRelationshipAsync( + /// relationship.SourceId, + /// relationship.Id, + /// serializedRelationship); /// - /// await client.CreateRelationshipAsync( - /// relationship.SourceId, - /// relationship.Id, - /// serializedRelationship); + /// Console.WriteLine($"Linked twin {relationship.SourceId} to twin {relationship.TargetId} as '{relationship.Name}'"); + /// } + /// catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.Conflict) + /// { + /// Console.WriteLine($"Relationship {relationship.Id} already exists: {ex.Message}"); + /// } + /// } /// /// public virtual Task> CreateRelationshipAsync(string digitalTwinId, string relationshipId, string relationship, CancellationToken cancellationToken = default) @@ -1000,10 +1016,9 @@ public virtual Response GetModel(string modelId, CancellationToken ca /// try /// { /// await client.DecommissionModelAsync(sampleModelId); - /// /// Console.WriteLine($"Successfully decommissioned model {sampleModelId}"); /// } - /// catch (Exception ex) + /// catch (RequestFailedException ex) /// { /// FatalError($"Failed to decommision model {sampleModelId} due to:\n{ex}"); /// } diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicDigitalTwin.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicDigitalTwin.cs index 63d60498c253..9c01cf34ec22 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicDigitalTwin.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicDigitalTwin.cs @@ -14,22 +14,35 @@ namespace Azure.DigitalTwins.Core.Serialization /// /// // Create digital twin with component payload using the BasicDigitalTwin serialization helper /// - /// var basicDigitalTwin = new BasicDigitalTwin + /// var basicTwin = new BasicDigitalTwin /// { - /// Id = basicDtId + /// Id = basicDtId, + /// // model Id of digital twin + /// Metadata = { ModelId = modelId }, + /// CustomProperties = + /// { + /// // digital twin properties + /// { "Prop1", "Value1" }, + /// { "Prop2", 987 }, + /// // component + /// { + /// "Component1", + /// new ModelProperties + /// { + /// // model Id of component + /// Metadata = { ModelId = componentModelId }, + /// // component properties + /// CustomProperties = + /// { + /// { "ComponentProp1", "Component value 1" }, + /// { "ComponentProp2", 123 }, + /// }, + /// } + /// }, + /// }, /// }; - /// basicDigitalTwin.Metadata.ModelId = modelId; - /// basicDigitalTwin.CustomProperties.Add("Prop1", "Value1"); - /// basicDigitalTwin.CustomProperties.Add("Prop2", 987); /// - /// var componentMetadata = new ModelProperties(); - /// componentMetadata.Metadata.ModelId = componentModelId; - /// componentMetadata.CustomProperties.Add("ComponentProp1", "ComponentValue1"); - /// componentMetadata.CustomProperties.Add("ComponentProp2", 123); - /// - /// basicDigitalTwin.CustomProperties.Add("Component1", componentMetadata); - /// - /// string basicDtPayload = JsonSerializer.Serialize(basicDigitalTwin); + /// string basicDtPayload = JsonSerializer.Serialize(basicTwin); /// /// Response<string> createBasicDtResponse = await client.CreateDigitalTwinAsync(basicDtId, basicDtPayload); /// Console.WriteLine($"Created digital twin {basicDtId} with response {createBasicDtResponse.GetRawResponse().Status}."); @@ -47,9 +60,12 @@ namespace Azure.DigitalTwins.Core.Serialization /// string component1RawText = ((JsonElement)basicDt.CustomProperties["Component1"]).GetRawText(); /// var component1 = JsonSerializer.Deserialize<IDictionary<string, object>>(component1RawText); /// - /// Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id} with ETag {basicDt.ETag} " + - /// $"and Prop1: '{basicDt.CustomProperties["Prop1"]}', Prop2: {basicDt.CustomProperties["Prop2"]}," + - /// $"ComponentProp1: '{component1["ComponentProp1"]}', ComponentProp2: {component1["ComponentProp2"]}"); + /// Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id}:\n\t" + + /// $"ETag: {basicDt.ETag}\n\t" + + /// $"Prop1: {basicDt.CustomProperties["Prop1"]}\n\t" + + /// $"Prop2: {basicDt.CustomProperties["Prop2"]}\n\t" + + /// $"ComponentProp1: {component1["ComponentProp1"]}\n\t" + + /// $"ComponentProp2: {component1["ComponentProp2"]}"); /// } /// /// diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/DigitalTwinMetadata.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/DigitalTwinMetadata.cs index a63fdb81f0c4..9ad50b073ddb 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/DigitalTwinMetadata.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/DigitalTwinMetadata.cs @@ -23,6 +23,6 @@ public class DigitalTwinMetadata /// /// For your convenience, the value of each dictionary object can be turned into an instance of . [JsonExtensionData] - public IDictionary WriteableProperties { get; set; } = new Dictionary(); + public IDictionary WriteableProperties { get; } = new Dictionary(); } } diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/ModelProperties.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/ModelProperties.cs index 8d4102ad1274..0b243fab7661 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/ModelProperties.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/ModelProperties.cs @@ -15,12 +15,12 @@ public class ModelProperties /// Information about the model a digital twin conforms to. This field is present on every digital twin. /// [JsonPropertyName("$metadata")] - public DigitalTwinMetadata Metadata { get; set; } = new DigitalTwinMetadata(); + public DigitalTwinMetadata Metadata { get; } = new DigitalTwinMetadata(); /// /// Additional properties of the digital twin. This field will contain any properties of the digital twin that are not already defined by the other strong types of this class. /// [JsonExtensionData] - public IDictionary CustomProperties { get; set; } = new Dictionary(); + public IDictionary CustomProperties { get; } = new Dictionary(); } }