private async Task<bool> SendMessageAndWaitForResponse(ServiceClient serviceClient, string deviceId, UpdateAccessKeyRequest updateAccessKey) { var serviceMessage = new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(updateAccessKey))); serviceMessage.Ack = DeliveryAcknowledgement.Full; serviceMessage.MessageId = Guid.NewGuid().ToString(); var feedbackReceiver = serviceClient.GetFeedbackReceiver(); var feedbackReceived = false; var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(60)).Token; var feedbackTask = Task.Run(async () => { while (!feedbackReceived && !cancellationToken.IsCancellationRequested) { var feedbackBatch = await feedbackReceiver.ReceiveAsync(TimeSpan.FromSeconds(0.5)); if (feedbackBatch != null) { feedbackReceived = feedbackBatch.Records.Any(fm => fm.DeviceId == deviceId && fm.OriginalMessageId == serviceMessage.MessageId); if (feedbackReceived) { await feedbackReceiver.CompleteAsync(feedbackBatch); } } } }, cancellationToken); await Task.WhenAll( feedbackTask, serviceClient.SendAsync(deviceId, serviceMessage)); return feedbackReceived; }
public async Task<ActionResult> RenewKeys(string id) { var registryManager = RegistryManager.CreateFromConnectionString(ConfigurationManager.AppSettings["IoTHubConnectionString"]); var device = await registryManager.GetDeviceAsync(id); var serviceClient = ServiceClient.CreateFromConnectionString(ConfigurationManager.AppSettings["IoTHubConnectionString"]); // First tell the device to use the secondary key var updateAccessKey = new UpdateAccessKeyRequest { AccessKey = device.Authentication.SymmetricKey.SecondaryKey }; var accepted = await SendMessageAndWaitForResponse(serviceClient, id, updateAccessKey); if (accepted) { // Since the device is know using the secondary key, // we can update the primary key without disruption for the device updateAccessKey = new UpdateAccessKeyRequest { AccessKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())) }; var originialKey = device.Authentication.SymmetricKey.PrimaryKey; device.Authentication.SymmetricKey.PrimaryKey = updateAccessKey.AccessKey; var updatedDevice = await registryManager.UpdateDeviceAsync(device, true); accepted = await SendMessageAndWaitForResponse(serviceClient, id, updateAccessKey); // If the device could not change the AccessKey, make sure we keep using the original one if (!accepted) { device.Authentication.SymmetricKey.PrimaryKey = originialKey; updatedDevice = await registryManager.UpdateDeviceAsync(device, true); } } return View(accepted); }