Please refer to the root README for a high level introduction of this sample. This document covers the details of the specific dotnet
implementation.
The COMMON_SETUP.md file contains more detailed references on how to provision the required resources (e.g., IoT Hub, device identity, Storage Account, blob container).
This platform solution also requires
Start the simulated device client
The IoTClientDeviceBlobExtensionNetCore
project can be run as a console application which simulates a connected device.
- Retrieve the device connection string for your IoT Hub device
- One option is to execute the following Azure CLI command
az iot hub device-identity connection-string show --hub-name YourIoTHubName --device-id MyNodeDevice --output table
- Another option is to retrieve the connection string from the Azure Portal as described in the Create a device identity documentation.
- One option is to execute the following Azure CLI command
- Open the
IoTClientDeviceBlobExtensionNetCore
project- Add the device connection string to this line in
Program.cs
:static string DeviceConnectionString = "Put Device Connection string here";
- Build and run the program
- Add the device connection string to this line in
At this point, your client device is connected to IoT Hub and is registered to receive updates for its associated device twin.
Deploy the back-end solution as an Azure Functions
The IoTHubExtension
project is meant to be hosted as an Azure Function. One of the easiest ways to deploy this would be:
- Open the
IoTHubExtension
project in VS Code - Install the Azure Functions extension for VS Code
- Use the Azure Functions extension to create and deploy a function
NOTE: Be sure that you perform a
dotnet build
anddotnet publish
before deploying the Azure Function. Also, when the VS Code Extension for Azure Functions prompts for a folder to zip and deploy, choose the publish folder (e.g.,./bin/Debug/netcoreapp3.1/publish
) rather than the root project directory. The output should show something similar toSyncing 1 function triggers with payload size 153 bytes successful.
The important part here is that it has synced 1 function trigger.
Configure the Azure Function
The Azure Function relies on one connection string, two environment variables, and the path into which blobs will be uploaded.
The environment variables and connection strings can be managed from the Application Settings for the function app.
- Under Connection Strings, add
BlobStorageConnectionString
, and set the value to a connection string for your storage account. You can find your storage account's connection strings in the Azure portal. Navigate to your storage account. SelectSecurity + networking
>Access keys
in your storage account's menu blade to see connection strings for both primary and secondary access keys. - Under Application Settings, add
iotHubConnectionString
and set it to an iothubowner connection string. - Also under Application Settings, add
iotHubDeviceQuery
and set it to a value likeSELECT * FROM devices WHERE deviceId='twinblob'
wheretwinblob
will be the id of your device. For more information on forming device queries, see the Query language documentation.
The path into which blobs will be uploaded is managed directly in the code. By default, the BlobTrigger
expects the blobs to be placed within a container named extensions
. If you wish to use a different container name, edit the following line from BlobTriggerTwinUpdater.cs
, changing extensions
to whatever you want the container name to be.
public static void Run([BlobTrigger("extensions/{Uri}", Connection = "BlobStorageConnectionString")]CloudBlockBlob myBlob, string Uri, ILogger log)
Apply a new blob
Create or update a blob under the storage account and path configured above. You might use Storage Explorer, the Azure Portal, or the Azure CLI.
If you left the client running, you should see the new artwork displayed in the console.
- Opens the device client connection (
DeviceClient.CreateFromConnectionString
) - Gets the device twin (
Client.GetTwinAsync
) - Initializes a
BlobExtension
, an abstraction provided in this project to handle each twin update and raise a secondary event after the blob asset is retrieved
The BlobExtension
acts on the updated properties.
- Subscribes to device twin updates (
client.SetDesiredPropertyUpdateCallbackAsync
) - When the twin is updated
- Downloads the new blob (
DownloadTextAsync
) - Raises its
BlobPropertyUpdated
event with details about the new blob asset - Patches the twin's reported properties to acknowledge the update (
client.UpdateReportedPropertiesAsync
)
- Downloads the new blob (
This example uses an Azure Function triggered from blob updates. The function iterates over the results of a device query to patch each twin.
- The function is triggered by updates to blobs in the configured container (
BlobTrigger
) - A new SAS URL is generated for the blob (
GetSharedAccessSignature
) - A device query is performed against the IoT Hub device registry (
registryManager.CreateQuery
) - For each returned device twin (
query.GetNextAsTwinAsync
), the twin's desired properties are updated with the new SAS URL (twin.Properties.Desired = ...
) - The patched twins are submitted back to the IoT Hub registry (
registryManager.UpdateTwins2Async
)
As alternatives, consider
- the
nodejs
example in this repo includes the upload of the blob and generation of the SAS URL. It also submits a job to IoT Hub, offloading the responsibility of applying the update to each matched twin - the
python
example in this repo uses the Azure CLI to replace the twin for a single device by id