简体   繁体   English

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

[英]How to upload a file to azure Blob storage through IOT hub from a Xamarin PCL project

So I need to upload this json file to my AzureBlob storage from my IotHub. 因此,我需要将这个json文件从IotHub上传到AzureBlob存储。 So far I have a storage account and a container linked to my IoT HUb. 到目前为止,我有一个存储帐户和一个链接到IoT HUb的容器。 I have a PCL project that is linked to 3 platform projects(Android, iOS, and UWP). 我有一个PCL项目,该项目链接到3个平台项目(Android,iOS和UWP)。 In my PCL project, I have a deviceClient that otherwise sends telemetry data. 在我的PCL项目中,我有一个deviceClient,否则将发送遥测数据。

I tried using this piece of code from https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-file-upload 我尝试从https://docs.microsoft.com/zh-cn/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: {0}ms\n",batch.ElapsedMilliseconds);
}

But I don't get the method "UploadToBlobAsync" on the IntelliSense. 但是我没有在IntelliSense上获得方法“ UploadToBlobAsync”。

I am using VS2017. 我正在使用VS2017。

NuGet packages added: Microsoft.Azure.Devices.Client.PCL NuGet软件包已添加:Microsoft.Azure.Devices.Client.PCL

My IOTHubHelper Class has the reference to Microsoft.Azure.Devices.Client; 我的IOTHubHelper类具有对Microsoft.Azure.Devices.Client的引用;

NuGet packages added: Microsoft.Azure.Devices.Client.PCL NuGet软件包已添加:Microsoft.Azure.Devices.Client.PCL

But I don't get the method "UploadToBlobAsync" on the IntelliSense. 但是我没有在IntelliSense上获得方法“ UploadToBlobAsync”。

As the srouce code Azure/azure-iot-sdk-csharp for Microsoft.Azure.Devices.Client about DeviceClient.cs defined as follows: 作为srouce代码天青/天青-IOT-SDK-CSHARPMicrosoft.Azure.Devices.ClientDeviceClient.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

Note: The UploadToBlobAsync function is not supported under the PCL library. 注意: PCL库不支持UploadToBlobAsync函数。 I assumed that you could migrate your PCL to the .NET Standard library and use Microsoft.Azure.Devices.Client for uploading a file to your Azure Blob storage. 我假定您可以将PCL迁移到.NET Standard库,并使用Microsoft.Azure.Devices.Client将文件上传到Azure Blob存储。 Additionally, you could follow this tutorial about building Xamarin.Forms Apps with .NET Standard. 此外,您可以按照有关使用.NET Standard构建Xamarin.Forms应用程序的教程进行操作

The method Microsoft.Azure.Devices.Client.DeviceClient.UploadToBlobAsync is basically a wrapper around the REST API calls for blob uploading session via the Azure IoT Hub. 方法Microsoft.Azure.Devices.Client.DeviceClient.UploadToBlobAsync基本上是用于通过Azure IoT中心进行Blob上传会话的REST API调用的包装。 The sequence of this session is divided into the 3 steps such as: Step 1 . 该会话的顺序分为3个步骤,例如: 步骤1 Get the upload info reference from the Azure IoT Hub (open session) Step 2 . 从Azure IoT中心(打开的会话) 步骤2中获取上传信息参考。 uploading a blob based on the received reference info Step 3 . 根据收到的参考信息上传Blob。 步骤3 Close the session posting a result of the upload process. 关闭发布上载过程结果的会话。

The following code snippet shows an example of the above steps implemented in PCL project: 以下代码段显示了在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.blobName}{uploadInfo.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"));
        }
    }

for authorization header we need a sasToken, so the following code snippet shows its implementation: 对于授权标头,我们需要一个sasToken,因此以下代码片段显示了其实现:

    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;
    }

Note, that the above implementation doesn't handle a retrying mechanism in the step 2. 请注意,上述实现在步骤2中不处理重试机制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM