如何通过 IOT 集线器从 Xamarin PCL 项目将文件上传到 azure Blob 存储

Posted

技术标签:

【中文标题】如何通过 IOT 集线器从 Xamarin PCL 项目将文件上传到 azure Blob 存储【英文标题】:How to upload a file to azure Blob storage through IOT hub from a Xamarin PCL project 【发布时间】:2018-02-15 00:37:38 【问题描述】:

所以我需要将此 json 文件从我的 IotHub 上传到我的 AzureBlob 存储。 到目前为止,我有一个存储帐户和一个链接到我的 IoT 中心的容器。 我有一个链接到 3 个平台项目(androidios 和 UWP)的 PCL 项目。 在我的 PCL 项目中,我有一个 deviceClient 用于发送遥测数据。

我尝试使用来自https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-file-upload的这段代码

private static async void SendToBlobAsync()

    string fileName = "data.json";
    Console.WriteLine("Uploading file: 0", fileName);
    var watch = System.Diagnostics.Stopwatch.StartNew();

    using (var sourceData = new FileStream(@"image.jpg", FileMode.Open))
    
        await deviceClient.UploadToBlobAsync(fileName, sourceData);
    

    watch.Stop();
    Console.WriteLine("Time to upload file: 0ms\n",batch.ElapsedMilliseconds);

但我没有在 IntelliSense 上获得方法“UploadToBlobAsync”。

我正在使用 VS2017。

已添加 NuGet 包:Microsoft.Azure.Devices.Client.PCL

我的 IOTHubHelper 类引用了 Microsoft.Azure.Devices.Client;

【问题讨论】:

【参考方案1】:

已添加 NuGet 包:Microsoft.Azure.Devices.Client.PCL

但我没有在 IntelliSense 上获得方法“UploadToBlobAsync”。

作为Microsoft.Azure.Devices.Client的源代码Azure/azure-iot-sdk-csharp约DeviceClient.cs定义如下:

#if !PCL
        /// <summary>
        /// Uploads a stream to a block blob in a storage account associated with the IoTHub for that device.
        /// If the blob already exists, it will be overwritten.
        /// </summary>
        /// <param name="blobName"></param>
        /// <param name="source"></param>
        /// <returns>AsncTask</returns>
        public Task UploadToBlobAsync(String blobName, System.IO.Stream source)
        
            if (String.IsNullOrEmpty(blobName))
            
                throw Fx.Exception.ArgumentNull("blobName");
            
            if (source == null)
            
                throw Fx.Exception.ArgumentNull("source");
            
            if (blobName.Length > 1024)
            
                throw Fx.Exception.Argument("blobName", "Length cannot exceed 1024 characters");
            
            if (blobName.Split('/').Count() > 254)
            
                throw Fx.Exception.Argument("blobName", "Path segment count cannot exceed 254");
            

            HttpTransportHandler httpTransport = null;

#if !WINDOWS_UWP
            //We need to add the certificate to the fileUpload httpTransport if DeviceAuthenticationWithX509Certificate
            if (this.Certificate != null)
            
                Http1TransportSettings transportSettings = new Http1TransportSettings();
                transportSettings.ClientCertificate = this.Certificate;
                httpTransport = new HttpTransportHandler(null, iotHubConnectionString, transportSettings);
            
            else
            
                httpTransport = new HttpTransportHandler(iotHubConnectionString);
            
#else 
            httpTransport = new HttpTransportHandler(iotHubConnectionString);
#endif
            return httpTransport.UploadToBlobAsync(blobName, source);
        
#endif

注意: PCL 库不支持UploadToBlobAsync 函数。我假设您可以将 PCL 迁移到 .NET Standard 库并使用 Microsoft.Azure.Devices.Client 将文件上传到 Azure Blob 存储。此外,您可以关注tutorial,了解使用 .NET Standard 构建 Xamarin.Forms 应用程序。

【讨论】:

【参考方案2】:

方法 Microsoft.Azure.Devices.Client.DeviceClient.UploadToBlobAsync 基本上是通过 Azure IoT 中心对 Blob 上传会话的 REST API 调用进行封装。本次会议的顺序分为 3 个步骤,例如: 第 1 步。从 Azure IoT 中心获取上传信息参考(开放会话) 第 2 步。根据收到的参考信息上传 blob 第 3 步。关闭发布上传过程结果的会话。

以下代码 sn -p 显示了在 PCL 项目中实现上述步骤的示例:

    private async Task UploadToBlobAsync(string blobName, Stream source, string iothubnamespace, string deviceId, string deviceKey)
    
        using(HttpClient client = new HttpClient())
        
            // create authorization header
            string deviceSasToken = GetSASToken($"iothubnamespace.azure-devices.net/devices/deviceId", deviceKey, null, 1);
            client.DefaultRequestHeaders.Add("Authorization", deviceSasToken);

            // step 1. get the upload info
            var payload = JsonConvert.SerializeObject(new  blobName = blobName ); 
            var response = await client.PostAsync($"https://iothubnamespace.azure-devices.net/devices/deviceId/files?api-version=2016-11-14", new StringContent(payload, Encoding.UTF8, "application/json"));                
            var infoType = new  correlationId = "", hostName = "", containerName = "", blobName = "", sasToken = "" ;
            var uploadInfo = JsonConvert.DeserializeAnonymousType(await response.Content.ReadAsStringAsync(), infoType);

            // step 2. upload blob
            var uploadUri = $"https://uploadInfo.hostName/uploadInfo.containerName/uploadInfo.blobNameuploadInfo.sasToken";
            client.DefaultRequestHeaders.Add("x-ms-blob-type", "blockblob");
            client.DefaultRequestHeaders.Remove("Authorization");
            response = await client.PutAsync(uploadUri, new StreamContent(source));

            // step 3. send completed
            bool isUploaded = response.StatusCode == System.Net.HttpStatusCode.Created;
            client.DefaultRequestHeaders.Add("Authorization", deviceSasToken);
            payload = JsonConvert.SerializeObject(new  correlationId = uploadInfo.correlationId, statusCode = isUploaded ? 0 : -1, statusDescription = response.ReasonPhrase, isSuccess = isUploaded );
            response = await client.PostAsync($"https://iothubnamespace.azure-devices.net/devices/deviceId/files/notifications?api-version=2016-11-14", new StringContent(payload, Encoding.UTF8, "application/json"));
        
    

对于授权头,我们需要一个sasToken,所以下面的代码sn-p展示了它的实现:

    private string GetSASToken(string resourceUri, string key, string keyName = null, uint hours = 24)
    
        var expiry = Convert.ToString((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds + 3600 * hours);
        string stringToSign = System.Net.WebUtility.UrlEncode(resourceUri) + "\n" + expiry;
        HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key));

        var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
        var sasToken = keyName == null ?
            String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr=0&sig=1&se=2", System.Net.WebUtility.UrlEncode(resourceUri), System.Net.WebUtility.UrlEncode(signature), expiry) :
            String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr=0&sig=1&se=2&skn=3", System.Net.WebUtility.UrlEncode(resourceUri), System.Net.WebUtility.UrlEncode(signature), expiry, keyName);
        return sasToken;
    

请注意,上述实现不处理步骤 2 中的重试机制。

【讨论】:

以上是关于如何通过 IOT 集线器从 Xamarin PCL 项目将文件上传到 azure Blob 存储的主要内容,如果未能解决你的问题,请参考以下文章