如何通过 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 个平台项目(android、ios 和 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项目访问android原生布局文件?
如何从 Xamarin.forms pcl 中的 Url 检索 json 字符串
如何从 Xamarin.forms pcl 中的 Url 检索 json 字符串