如何通过 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 存储的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Xamarin 表格 pcl 的网格中插入背景图像

如何从xamarin表单应用程序中的PCL项目访问android原生布局文件?

如何从 Xamarin.forms pcl 中的 Url 检索 json 字符串

如何从 Xamarin.forms pcl 中的 Url 检索 json 字符串

如何在 xamarin 跨平台应用程序中创建具有 sqlite 支持的 PCL

如何将json.net添加到Xamarin Forms,本地项目或PCL上?