Skip to main content

使用.Net Device SDK从设备上向Azure IoT Hub上传文件

分类:  Azure物联网 标签:  #Azure #IoT Hub # 发布于: 2023-06-13 20:51:56

如果需要从设备上向IoT Hub上传文件,首先需要配置文件上传的功能,也需要创建一个和Azure IoT Hub在同一个区域的Storage Account, 关于如何创建Storage Accountblob, 您可以参考文档:https://docs.microsoft.com/zh-cn/azure/storage/common/storage-account-create?tabs=azure-portal, 创建好之后找到您的Azure IoT Hub, 从左边找到File Upload这个功能,进行配置,如下图:


配置好了之后就,保存退出,然后我们开始使用.Net Device SDK从设备上向IoT Hub上传文件。

创建一个新的项目

首先使用如下的命令取得设备simDevice的连接字符串,当然这之前你需要先创建好Azure IoT Hub资源以及该设备:

az iot hub device-identity connection-string show --device-id simDevice --hub-name MyIoThubByCli

得到连接字符串之后,先保存起来,后面的代码中需要使用到这个连接字符串。

使用下述的命令创建我们的项目:

dotnet new console -o FileUploadSample
cd FileUploadSample
dotnet add package Microsoft.Azure.Devices.Client
dotnet add package Azure.Storage.Blobs
code .

打开VS code或者其他编辑器之后,在根目录下添加一个文件GlobalUsing.cs, 打开该文件,添加如下的引用:

global using Microsoft.Azure.Devices.Client;
global using System.Text.Json;
global using System.Text;
global using System.Text.Json.Serialization;
global using System.Diagnostics;
global using Microsoft.Azure.Devices.Shared;
global using Azure.Storage.Blobs.Models;
global using Azure.Storage.Blobs.Specialized;
global using FileUploadSample;

在根目录下创建一个UploadSample.cs的文件,以下述内容替换:

namespace FileUploadSample;
public class UploadSample
{
    private readonly DeviceClient _deviceClient;

    public UploadSample(DeviceClient deviceClient)
    {
        _deviceClient = deviceClient;
    }

    public async Task RunSampleAsync()
    {
        const string filePath = "TestPayload.txt";

        using var fileStreamSource = new FileStream(filePath, FileMode.Open);
        var fileName = Path.GetFileName(fileStreamSource.Name);

        Console.WriteLine($"上传文件: {fileName}");

        var fileUploadTime = Stopwatch.StartNew();

        var fileUploadSasUriRequest = new FileUploadSasUriRequest
        {
            BlobName = fileName
        };

        // Note: GetFileUploadSasUriAsync and CompleteFileUploadAsync will use HTTPS as protocol regardless of the DeviceClient protocol selection.
        Console.WriteLine("取得SAS URL, 用于上传,要预先配置file upload。");
        FileUploadSasUriResponse sasUri = await _deviceClient.GetFileUploadSasUriAsync(fileUploadSasUriRequest);
        Uri uploadUri = sasUri.GetBlobUri();

        Console.WriteLine($"成功从IoT Hub中取得SAS URI:{uploadUri}");

        try
        {
            Console.WriteLine($"使用Azure Storage SDK 和取得的SAS URI上传文件: {fileName} ");

            var blockBlobClient = new BlockBlobClient(uploadUri);
            await blockBlobClient.UploadAsync(fileStreamSource, new BlobUploadOptions());
        }
        catch (Exception ex)
        {
            Console.WriteLine($"上传失败: {ex}");

            var failedFileUploadCompletionNotification = new FileUploadCompletionNotification
            {
                CorrelationId = sasUri.CorrelationId,

                IsSuccess = false,

                StatusCode = 500,

                StatusDescription = ex.Message
            };

            //使用Azure Stoarege SDK上传完之后,必须要释放URI, IoT Hub的SAS URI对多少个设备可以上传文件有限制。
            //同时上传完了之后,还会给IoT Hub发通知。
            await _deviceClient.CompleteFileUploadAsync(failedFileUploadCompletionNotification);
            Console.WriteLine("通知IoT Hub上传失败,可以释放SAS URI");

            fileUploadTime.Stop();
            return;
        }

        Console.WriteLine("成功上传至Azure Storage");

        var successfulFileUploadCompletionNotification = new FileUploadCompletionNotification
        {
            CorrelationId = sasUri.CorrelationId,

            IsSuccess = true,

            StatusCode = 200,

            StatusDescription = "Success"
        };

        //同样需要调用完成的方法,释放SAS URI
        await _deviceClient.CompleteFileUploadAsync(successfulFileUploadCompletionNotification);
        Console.WriteLine("通知IoT Hub上传成功,并释放SAS URI");

        fileUploadTime.Stop();

        Console.WriteLine($"上传文件时间: {fileUploadTime.Elapsed}.");
    }
}

需要注意的是:

  • 文件上传的实际动作还是由Azure Storage SDK完成。
  • Storage 上传的SAS URI是由Azure IoT Hub提供。
  • Azure IoT HubSAS URI可使用的设备数有限制,因此无论上传成功还是失败,都要及时释放。
  • 注意如何释放SAS URI的。

打开Program.cs, 使用如下的内容替换:

Console.WriteLine("使用SAS Key连接字符串连接Azure IoT Hub, 从设备上上传文件:");

string s_connectionString = "HostName=MyIoTHubByCli.azure-devices.cn;DeviceId=simDevice;SharedAccessKey=WyuzYpZa7ekyaAp/6bJlccOgzCHc7KwDNZ56d26jiHY=";

//验证连接字符串是否是正确的
ValidateConnectionString(args);

DeviceClient s_deviceClient = DeviceClient.CreateFromConnectionString(s_connectionString);

using var deviceClient = DeviceClient.CreateFromConnectionString(
                s_connectionString,
                TransportType.Mqtt);


var sample = new UploadSample(deviceClient);
await sample.RunSampleAsync();
await deviceClient.CloseAsync();

Console.WriteLine("Done.");

void ValidateConnectionString(string[] appArgs)
{
    if ( appArgs.Any() )
    {
        try 
        {
            var cs = IotHubConnectionStringBuilder.Create(appArgs[0]);
            s_connectionString = cs.ToString();

        } catch ( Exception )
        {
            Console.WriteLine($"错误:无法识别连接字符串参数 `{appArgs[0]}");
            Environment.Exit(-1);
        }

    }
    else
    {
        try 
        {
            _ = IotHubConnectionStringBuilder.Create(s_connectionString);
        } catch(Exception )
        {
            Console.WriteLine("这个Demo需要使用连接字符串连接到Azure IoT Hub");
            Environment.Exit(-1);
        }
    }
}