Manage digital twins
Entities in your environment are represented by digital twins. Managing your digital twins may include creation, modification, and removal.
This article focuses on managing digital twins; to work with relationships and the twin graph as a whole, see Manage the twin graph and relationships.
Tip
All SDK functions come in synchronous and asynchronous versions.
Prerequisites
To work with Azure Digital Twins in this article, you first need to set up an Azure Digital Twins instance. You also need the required permissions for using it. If you already have an Azure Digital Twins instance set up, you can use it instead.
Otherwise, follow the instructions in Set up an instance and authentication. The instructions contain information to help you verify that you've completed each step successfully.
After you set up your instance, make a note of the following values. You'll need these values to connect to the instance later:
- The instance's host name. You can find the host name in the Azure portal.
- The Azure subscription that you used to create the instance. Either its name or its ID will work. You can find the subscription on your instance's Overview page in the Azure portal.
Developer interfaces
This article highlights how to complete different management operations using the .NET (C#) SDK. You can also craft these same management calls using the other language SDKs described in Azure Digital Twins APIs and SDKs.
Other developer interfaces that can be used to complete these operations include:
- Azure Digital Twins Explorer
- REST API calls
- Azure CLI commands
Visualization
Azure Digital Twins Explorer is a visual tool for exploring the data in your Azure Digital Twins graph. You can use the explorer to view, query, and edit your models, twins, and relationships.
To read about the Azure Digital Twins Explorer tool, see Azure Digital Twins Explorer. For detailed steps on how to use its features, see Use Azure Digital Twins Explorer.
Here's what the visualization looks like:
Create a digital twin
To create a twin, you use the CreateOrReplaceDigitalTwinAsync() method on the service client like this:
await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinId, initData);
To create a digital twin, you need to provide:
- An ID value you want to assign to the digital twin (you're defining that ID when the twin is created)
- The model you want to use
- Any desired initialization of twin data, including...
- Properties (optional to initialize): You can set initial values for properties of the digital twin if you want. Properties are treated as optional and can be set later, but note that they won't show up as part of a twin until they've been set.
- Telemetry (recommended to initialize): You can also set initial values for telemetry fields on the twin. Although initializing telemetry isn't required, telemetry fields also won't show up as part of a twin until they've been set. This means that you'll be unable to edit telemetry values for a twin unless they've been initialized first.
- Components (required to initialize if present on twin): If your twin contains any components, these must be initialized when the twin is created. They can be empty objects, but the components themselves have to exist.
The model and any initial property values are provided through the initData parameter, which is a JSON string containing the relevant data. For more information on structuring this object, continue to the next section.
Tip
After creating or updating a twin, there may be a latency of up to 10 seconds before the changes will be reflected in queries. The GetDigitalTwin API (described later in this article) does not experience this delay, so if you need an instant response, use the API call instead of querying to see your newly-created twins.
Initialize model and properties
You can initialize the properties of a twin at the time that the twin is created.
The twin creation API accepts an object that is serialized into a valid JSON description of the twin properties. See Digital twins and the twin graph for a description of the JSON format for a twin.
First, you can create a data object to represent the twin and its property data. You can create a parameter object either manually, or by using a provided helper class. Here is an example of each.
Create twins using manually created data
Without the use of any custom helper classes, you can represent a twin's properties in a Dictionary<string, object>, where the string is the name of the property and the object is an object representing the property and its value.
// Define a custom model type for the twin to be created
internal class CustomDigitalTwin
{
[JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinId)]
public string Id { get; set; }
[JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinETag)]
public string ETag { get; set; }
[JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinMetadata)]
public MyCustomDigitalTwinMetadata Metadata { get; set; } = new MyCustomDigitalTwinMetadata();
[JsonPropertyName("temperature")]
public double Temperature { get; set; }
[JsonPropertyName("humidity")]
public double Humidity{ get; set; }
}
internal class MyCustomDigitalTwinMetadata
{
[JsonPropertyName(DigitalTwinsJsonPropertyNames.MetadataModel)]
public string ModelId { get; set; }
[JsonPropertyName("temperature")]
public DigitalTwinPropertyMetadata Temperature { get; set; }
[JsonPropertyName("humidity")]
public DigitalTwinPropertyMetadata Humidity { get; set; }
}
// Initialize properties and create the twin
public class TwinOperationsCreateTwin
{
public async Task CreateTwinAsync(DigitalTwinsClient client)
{
// Initialize the twin properties
var myTwin = new CustomDigitalTwin
{
Metadata = { ModelId = "dtmi:example:Room;1" },
Temperature = 25.0,
Humidity = 50.0,
};
// Create the twin
const string twinId = "<twin-ID>";
Response<CustomDigitalTwin> response = await client.CreateOrReplaceDigitalTwinAsync(twinId, myTwin);
Console.WriteLine($"Temperature last updated on {response.Value.Metadata.Temperature.LastUpdatedOn}");
}
}
Create twins with the helper class
The helper class of BasicDigitalTwin allows you to store property fields in a "twin" object directly. You may still want to build the list of properties using a Dictionary<string, object>, which can then be added to the twin object as its CustomProperties directly.
string twinId = "myTwinID";
var initData = new BasicDigitalTwin
{
Id = twinId,
Metadata = { ModelId = "dtmi:example:Room;1" },
// Initialize properties
Contents =
{
{ "Temperature", 25.0 },
{ "Humidity", 50.0 },
},
};
await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinId, initData);
Note
BasicDigitalTwin objects come with an Id field. You can leave this field empty, but if you do add an ID value, it needs to match the ID parameter passed to the CreateOrReplaceDigitalTwinAsync() call. For example:
twin.Id = "myRoomId";
Get data for a digital twin
You can access the details of any digital twin by calling the GetDigitalTwin() method like this:
Response<BasicDigitalTwin> twinResponse = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twinId);
twin = twinResponse.Value;
This call returns twin data as a strongly-typed object type such as BasicDigitalTwin. BasicDigitalTwin is a serialization helper class included with the SDK, which will return the core twin metadata and properties in pre-parsed form. You can always deserialize twin data using the JSON library of your choice, like System.Text.Json or Newtonsoft.Json. For basic access to a twin, however, the helper classes can make this more convenient.
Note
BasicDigitalTwin uses System.Text.Json attributes. In order to use BasicDigitalTwin with your DigitalTwinsClient, you must either initialize the client with the default constructor, or, if you want to customize the serializer option, use the JsonObjectSerializer.
The BasicDigitalTwin helper class also gives you access to properties defined on the twin, through a Dictionary<string, object>. To list properties of the twin, you can use:
BasicDigitalTwin twin;
Response<BasicDigitalTwin> twinResponse = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twinId);
twin = twinResponse.Value;
Console.WriteLine($"Model id: {twin.Metadata.ModelId}");
foreach (string prop in twin.Contents.Keys)
{
if (twin.Contents.TryGetValue(prop, out object value))
Console.WriteLine($"Property '{prop}': {value}");
}
Only properties that have been set at least once are returned when you retrieve a twin with the GetDigitalTwin() method.
Tip
The displayName for a twin is part of its model metadata, so it will not show when getting data for the twin instance. To see this value, you can retrieve it from the model.
To retrieve multiple twins using a single API call, see the query API examples in Query the twin graph.
Consider the following model (written in Digital Twins Definition Language (DTDL)) that defines a Moon:
{
"@id": "dtmi:example:Moon;1",
"@type": "Interface",
"@context": "dtmi:dtdl:context;2",
"contents": [
{
"@type": "Property",
"name": "radius",
"schema": "double",
"writable": true
},
{
"@type": "Property",
"name": "mass",
"schema": "double",
"writable": true
}
]
}
The result of calling object result = await client.GetDigitalTwinAsync("my-moon"); on a Moon-type twin might look like this:
{
"$dtId": "myMoon-001",
"$etag": "W/\"e59ce8f5-03c0-4356-aea9-249ecbdc07f9\"",
"radius": 1737.1,
"mass": 0.0734,
"$metadata": {
"$model": "dtmi:example:Moon;1",
"radius": {
"desiredValue": 1737.1,
"desiredVersion": 5,
"ackVersion": 4,
"ackCode": 200,
"ackDescription": "OK"
},
"mass": {
"desiredValue": 0.0734,
"desiredVersion": 8,
"ackVersion": 8,
"ackCode": 200,
"ackDescription": "OK"
}
}
}
The defined properties of the digital twin are returned as top-level properties on the digital twin. Metadata or system information that is not part of the DTDL definition is returned with a $ prefix. Metadata properties include the following values:
$dtId: The ID of the digital twin in this Azure Digital Twins instance$etag: A standard HTTP field assigned by the web server. This is updated to a new value every time the twin is updated, which can be useful to determine whether the twin's data has been updated on the server since a previous check. You can useIf-Matchto perform updates and deletes that only complete if the entity's etag matches the etag provided. For more information on these operations, see the documentation for DigitalTwins Update and DigitalTwins Delete.$metadata: A set of other properties, including:- The DTMI of the model of the digital twin.
- Synchronization status for each writable property. This is most useful for devices, where it's possible that the service and the device have diverging statuses (for example, when a device is offline). Currently, this property only applies to physical devices connected to IoT Hub. With the data in the metadata section, it is possible to understand the full status of a property, as well as the last modified timestamps. For more information about sync status, see this IoT Hub tutorial on synchronizing device state.
- Service-specific metadata, like from IoT Hub or Azure Digital Twins.
You can read more about the serialization helper classes like BasicDigitalTwin in Azure Digital Twins APIs and SDKs.
View all digital twins
To view all of the digital twins in your instance, use a query. You can run a query with the Query APIs or the CLI commands.
Here is the body of the basic query that will return a list of all digital twins in the instance:
SELECT * FROM DIGITALTWINS
Update a digital twin
To update properties of a digital twin, write the information you want to replace in JSON Patch format. For a full list of JSON Patch operations that can be used, including replace, add and remove, see the Operations for JSON Patch.
After crafting the JSON Patch document containing update information, pass the document into the UpdateDigitalTwin() method:
await client.UpdateDigitalTwinAsync(twinId, updateTwinData);
A single patch call can update as many properties on a single twin as you want (even all of them). If you need to update properties across multiple twins, you'll need a separate update call for each twin.
Tip
After creating or updating a twin, there may be a latency of up to 10 seconds before the changes will be reflected in queries. The GetDigitalTwin API (described earlier in this article) does not experience this delay, so use the API call instead of querying to see your newly-updated twins if you need an instant response.
Here is an example of JSON Patch code. This document replaces the mass and radius property values of the digital twin it is applied to. This example shows the JSON Patch replace operation, which replaces the value of an existing property.
[
{
"op": "replace",
"path": "/mass",
"value": 0.0799
},
{
"op": "replace",
"path": "/radius",
"value": 0.800
}
]
When updating a twin from a code project using the .NET SDK, you can create JSON patches using the Azure .NET SDK's JsonPatchDocument. Here is an example of creating a JSON Patch document and using UpdateDigitalTwin() in project code.
var updateTwinData = new JsonPatchDocument();
updateTwinData.AppendAdd("/Temperature", 25.0);
updateTwinData.AppendAdd("/myComponent/Property", "Hello");
// Un-set a property
updateTwinData.AppendRemove("/Humidity");
await client.UpdateDigitalTwinAsync("myTwin", updateTwinData).ConfigureAwait(false);
Tip
You can maintain source timestamps on your digital twins by updating the $metadata.<property-name>.sourceTime field with the process described in this section. For more information on this field and other fields that are writable on digital twins, see Digital twin JSON format.
Update sub-properties in digital twin components
Recall that a model may contain components, allowing it to be made up of other models.
To patch properties in a digital twin's components, you can use path syntax in JSON Patch:
[
{
"op": "replace",
"path": "/mycomponentname/mass",
"value": 0.0799
}
]
Update sub-properties in object-type properties
Models may contain properties that are of an object type. Those objects may have their own properties, and you may want to update one of those sub-properties belonging to the object-type property. This process is similar to the process for updating sub-properties in components, but may require some extra steps.
Consider a model with an object-type property, ObjectProperty. ObjectProperty has a string property named StringSubProperty.
When a twin is created using this model, it's not necessary to instantiate the ObjectProperty at that time. If the object property is not instantiated during twin creation, there is no default path created to access ObjectProperty and its StringSubProperty for a patch operation. You will need to add the path to ObjectProperty yourself before you can update its properties.
This can be done with a JSON Patch add operation, like this:
[
{
"op": "add",
"path": "/ObjectProperty",
"value": {"StringSubProperty":"<string-value>"}
}
]
Note
If ObjectProperty has more than one property, you should include all of them in the value field of this operation, even if you're only updating one:
... "value": {"StringSubProperty":"<string-value>", "Property2":"<property2-value>", ...}
After this has been done once, a path to StringSubProperty exists, and it can be updated directly from now on with a typical replace operation:
[
{
"op": "replace",
"path": "/ObjectProperty/StringSubProperty",
"value": "<string-value>"
}
]
Although the first step isn't necessary in cases where ObjectProperty was instantiated when the twin was created, it's recommended to use it every time you update a sub-property for the first time, since you may not always know for sure whether the object property was initially instantiated or not.
Update a digital twin's model
The UpdateDigitalTwin() function can also be used to migrate a digital twin to a different model.
For example, consider the following JSON Patch document that replaces the digital twin's metadata $model field:
[
{
"op": "replace",
"path": "/$metadata/$model",
"value": "dtmi:example:foo;1"
}
]
This operation will only succeed if the digital twin being modified by the patch conforms with the new model.
Consider the following example:
- Imagine a digital twin with a model of foo_old. foo_old defines a required property mass.
- The new model foo_new defines a property mass, and adds a new required property temperature.
- After the patch, the digital twin must have both a mass and temperature property.
The patch for this situation needs to update both the model and the twin's temperature property, like this:
[
{
"op": "replace",
"path": "/$metadata/$model",
"value": "dtmi:example:foo_new;1"
},
{
"op": "add",
"path": "/temperature",
"value": 60
}
]
Update a property's sourceTime
You may optionally decide to use the sourceTime field on twin properties to record timestamps for when property updates are observed in the real world. Azure Digital Twins natively supports sourceTime in the metadata for each twin property. For more information about this field and other fields on digital twins, see Digital twin JSON format.
The minimum REST API version to support this field is the 2021-06-30-preview version. To work with this field using the Azure Digital Twins SDKs, we recommend using the latest version of the SDK to make sure this field is included (keep in mind that the latest version of an SDK may be in beta or preview).
The sourceTime value must comply to ISO 8601 date and time format.
Here's an example of a JSON Patch document that updates both the value and the sourceTime field of a Temperature property:
[
{
"op": "replace",
"path": "/Temperature",
"value": "22.3"
},
{
"op": "replace",
"path": "/$metadata/Temperature/sourceTime",
"value": "2021-11-30T18:47:53.7648958Z"
}
]
Tip
To update the sourceTime field on a property that's part of a component, include the component at the start of the path. In the previous example, this would mean changing the path from /$metadata/Temperature/sourceTime to myComponent/$metadata/Temperature/sourceTime.
Handle conflicting update calls
Azure Digital Twins ensures that all incoming requests are processed one after the other. This means that even if multiple functions try to update the same property on a twin at the same time, there's no need for you to write explicit locking code to handle the conflict.
This behavior is on a per-twin basis.
As an example, imagine a scenario in which these three calls arrive at the same time:
- Write property A on Twin1
- Write property B on Twin1
- Write property A on Twin2
The two calls that modify Twin1 are executed one after another, and change messages are generated for each change. The call to modify Twin2 may be executed concurrently with no conflict, as soon as it arrives.
Delete a digital twin
You can delete twins using the DeleteDigitalTwin() method. However, you can only delete a twin when it has no more relationships. So, delete the twin's incoming and outgoing relationships first.
Here is an example of the code to delete twins and their relationships. The DeleteDigitalTwin SDK call is highlighted to clarify where it falls in the wider example context.
private static async Task CustomMethod_DeleteTwinAsync(DigitalTwinsClient client, string twinId)
{
await CustomMethod_FindAndDeleteOutgoingRelationshipsAsync(client, twinId);
await CustomMethod_FindAndDeleteIncomingRelationshipsAsync(client, twinId);
try
{
await client.DeleteDigitalTwinAsync(twinId);
Console.WriteLine("Twin deleted successfully");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error:{ex.Message}");
}
}
private static async Task CustomMethod_FindAndDeleteOutgoingRelationshipsAsync(DigitalTwinsClient client, string dtId)
{
// Find the relationships for the twin
try
{
// GetRelationshipsAsync will throw an error if a problem occurs
AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);
await foreach (BasicRelationship rel in rels)
{
await client.DeleteRelationshipAsync(dtId, rel.Id).ConfigureAwait(false);
Console.WriteLine($"Deleted relationship {rel.Id} from {dtId}");
}
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving or deleting relationships for {dtId} due to {ex.Message}");
}
}
private static async Task CustomMethod_FindAndDeleteIncomingRelationshipsAsync(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);
await foreach (IncomingRelationship incomingRel in incomingRels)
{
await client.DeleteRelationshipAsync(incomingRel.SourceId, incomingRel.RelationshipId).ConfigureAwait(false);
Console.WriteLine($"Deleted incoming relationship {incomingRel.RelationshipId} from {dtId}");
}
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving or deleting incoming relationships for {dtId} due to {ex.Message}");
}
}
Delete all digital twins
For an example of how to delete all twins at once, download the sample app used in the Explore the basics with a sample client app. The CommandLoop.cs file does this in a CommandDeleteAllTwins() function.
Runnable digital twin code sample
You can use the runnable code sample below to create a twin, update its details, and delete the twin.
Set up sample project files
The snippet uses a sample model definition, Room.json. To download the model file so you can use it in your code, use this link to go directly to the file in GitHub. Then, right-click anywhere on the screen, select Save as in your browser's right-click menu, and use the Save As window to save the file as Room.json.
Next, create a new console app project in Visual Studio or your editor of choice.
Then, copy the following code of the runnable sample into your project:
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Azure;
using Azure.DigitalTwins.Core;
using Azure.Identity;
using System.IO;
namespace DigitalTwins_Samples
{
class TwinOperationsSample
{
public static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
// Create the Azure Digital Twins client for API calls
string adtInstanceUrl = "https://<your-instance-hostname>";
var credentials = new DefaultAzureCredential();
var client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credentials);
Console.WriteLine($"Service client created – ready to go");
// Upload models
Console.WriteLine($"Upload a model");
string dtdl = File.ReadAllText("<path-to>/Room.json");
var models = new List<string> { dtdl };
// Upload the model to the service
await client.CreateModelsAsync(models);
// Create new digital twin
// <CreateTwin_withHelper>
string twinId = "myTwinID";
var initData = new BasicDigitalTwin
{
Id = twinId,
Metadata = { ModelId = "dtmi:example:Room;1" },
// Initialize properties
Contents =
{
{ "Temperature", 25.0 },
{ "Humidity", 50.0 },
},
};
// <CreateTwinCall>
await client.CreateOrReplaceDigitalTwinAsync<BasicDigitalTwin>(twinId, initData);
// </CreateTwinCall>
// </CreateTwin_withHelper>
Console.WriteLine("Twin created successfully");
//Print twin
Console.WriteLine("--- Printing twin details:");
await CustomMethod_FetchAndPrintTwinAsync(twinId, client);
Console.WriteLine("--------");
//Update twin data
var updateTwinData = new JsonPatchDocument();
updateTwinData.AppendAdd("/Temperature", 30.0);
// <UpdateTwinCall>
await client.UpdateDigitalTwinAsync(twinId, updateTwinData);
// </UpdateTwinCall>
Console.WriteLine("Twin properties updated");
Console.WriteLine();
//Print twin again
Console.WriteLine("--- Printing twin details (after update):");
await CustomMethod_FetchAndPrintTwinAsync(twinId, client);
Console.WriteLine("--------");
Console.WriteLine();
//Delete twin
await CustomMethod_DeleteTwinAsync(client, twinId);
}
private static async Task<BasicDigitalTwin> CustomMethod_FetchAndPrintTwinAsync(string twinId, DigitalTwinsClient client)
{
// <GetTwin>
BasicDigitalTwin twin;
// <GetTwinCall>
Response<BasicDigitalTwin> twinResponse = await client.GetDigitalTwinAsync<BasicDigitalTwin>(twinId);
twin = twinResponse.Value;
// </GetTwinCall>
Console.WriteLine($"Model id: {twin.Metadata.ModelId}");
foreach (string prop in twin.Contents.Keys)
{
if (twin.Contents.TryGetValue(prop, out object value))
Console.WriteLine($"Property '{prop}': {value}");
}
// </GetTwin>
return twin;
}
// <DeleteTwin>
private static async Task CustomMethod_DeleteTwinAsync(DigitalTwinsClient client, string twinId)
{
await CustomMethod_FindAndDeleteOutgoingRelationshipsAsync(client, twinId);
await CustomMethod_FindAndDeleteIncomingRelationshipsAsync(client, twinId);
try
{
await client.DeleteDigitalTwinAsync(twinId);
Console.WriteLine("Twin deleted successfully");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error:{ex.Message}");
}
}
private static async Task CustomMethod_FindAndDeleteOutgoingRelationshipsAsync(DigitalTwinsClient client, string dtId)
{
// Find the relationships for the twin
try
{
// GetRelationshipsAsync will throw an error if a problem occurs
AsyncPageable<BasicRelationship> rels = client.GetRelationshipsAsync<BasicRelationship>(dtId);
await foreach (BasicRelationship rel in rels)
{
await client.DeleteRelationshipAsync(dtId, rel.Id).ConfigureAwait(false);
Console.WriteLine($"Deleted relationship {rel.Id} from {dtId}");
}
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving or deleting relationships for {dtId} due to {ex.Message}");
}
}
private static async Task CustomMethod_FindAndDeleteIncomingRelationshipsAsync(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);
await foreach (IncomingRelationship incomingRel in incomingRels)
{
await client.DeleteRelationshipAsync(incomingRel.SourceId, incomingRel.RelationshipId).ConfigureAwait(false);
Console.WriteLine($"Deleted incoming relationship {incomingRel.RelationshipId} from {dtId}");
}
}
catch (RequestFailedException ex)
{
Console.WriteLine($"*** Error {ex.Status}/{ex.ErrorCode} retrieving or deleting incoming relationships for {dtId} due to {ex.Message}");
}
}
// </DeleteTwin>
}
}
Note
There's currently a known issue affecting the DefaultAzureCredential wrapper class that may result in an error while authenticating. If you encounter this issue, you can try instantiating DefaultAzureCredential with the following optional parameter to resolve it: new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeSharedTokenCacheCredential = true });
For more information about this issue, see Troubleshoot known issues.
Configure project
Next, complete the following steps to configure your project code:
Add the Room.json file you downloaded earlier to your project, and replace the
<path-to>placeholder in the code to tell your program where to find it.Replace the placeholder
<your-instance-hostname>with your Azure Digital Twins instance's host name.Add two dependencies to your project that will be needed to work with Azure Digital Twins. The first is the package for the Azure Digital Twins SDK for .NET, and the second provides tools to help with authentication against Azure.
dotnet add package Azure.DigitalTwins.Core dotnet add package Azure.Identity
You'll also need to set up local credentials if you want to run the sample directly. The next section walks through this.
Set up local Azure credentials
This sample uses DefaultAzureCredential (part of the Azure.Identity library) to authenticate users with the Azure Digital Twins instance when you run it on your local machine. For more information on different ways a client app can authenticate with Azure Digital Twins, see Write app authentication code.
With DefaultAzureCredential, the sample will search for credentials in your local environment, like an Azure sign-in in a local Azure CLI or in Visual Studio or Visual Studio Code. For this reason, you should sign in to Azure locally through one of these mechanisms to set up credentials for the sample.
If you're using Visual Studio or Visual Studio Code to run the code sample, make sure you're signed in to that editor with the same Azure credentials that you want to use to access your Azure Digital Twins instance.
Otherwise, you can install the local Azure CLI, start a command prompt on your machine, and run the az login command to sign in to your Azure account. After you sign in, when you run your code sample, it should log you in automatically.
Run the sample
Now that you've completed setup, you can run the sample code project.
Here is the console output of the above program:
Next steps
See how to create and manage relationships between your digital twins:
Povratne informacije
Pošalјite i prikažite povratne informacije za