From d1f232a198ce9895a2846b71ce7940f04249a2fc Mon Sep 17 00:00:00 2001 From: MatthewGerber Date: Wed, 16 Jan 2019 12:28:13 -0500 Subject: [PATCH] Make Estimote Cloud interactions asynchronous with timeouts to avoid blocking UI. --- .../Extensions/WebRequestExtensions.cs | 38 +++++++++++++++++++ .../Probes/Location/EstimoteBeaconProbe.cs | 9 +++-- Sensus.Shared/Sensus.Shared.projitems | 1 + .../UI/EstimoteBeaconProbeBeaconsPage.cs | 4 +- Sensus.Shared/UI/ProbePage.cs | 4 +- 5 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 Sensus.Shared/Extensions/WebRequestExtensions.cs diff --git a/Sensus.Shared/Extensions/WebRequestExtensions.cs b/Sensus.Shared/Extensions/WebRequestExtensions.cs new file mode 100644 index 000000000..071239719 --- /dev/null +++ b/Sensus.Shared/Extensions/WebRequestExtensions.cs @@ -0,0 +1,38 @@ +// Copyright 2014 The Rector & Visitors of the University of Virginia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Net; +using System.Threading.Tasks; + +namespace Sensus.Extensions +{ + public static class WebRequestExtensions + { + public static async Task GetResponseAsync(this WebRequest webRequest, TimeSpan? timeout = null) + { + Task webResponseTask = webRequest.GetResponseAsync(); + Task timeoutTask = Task.Delay((int)(timeout?.TotalMilliseconds ?? int.MaxValue)); + + Task completedTask = await Task.WhenAny(webResponseTask, timeoutTask); + + if (completedTask == timeoutTask) + { + throw new TimeoutException("Timed out."); + } + + return await webResponseTask; + } + } +} \ No newline at end of file diff --git a/Sensus.Shared/Probes/Location/EstimoteBeaconProbe.cs b/Sensus.Shared/Probes/Location/EstimoteBeaconProbe.cs index 11326b961..2a6402eee 100644 --- a/Sensus.Shared/Probes/Location/EstimoteBeaconProbe.cs +++ b/Sensus.Shared/Probes/Location/EstimoteBeaconProbe.cs @@ -24,6 +24,7 @@ using Newtonsoft.Json.Linq; using Sensus.Concurrent; using System.Threading.Tasks; +using Sensus.Extensions; namespace Sensus.Probes.Location { @@ -180,7 +181,7 @@ protected override async Task InitializeAsync() } } - public List GetBeaconTagsFromCloud() + public async Task> GetBeaconTagsFromCloudAsync(TimeSpan? timeout = null) { List tags = new List(); @@ -191,7 +192,7 @@ public List GetBeaconTagsFromCloud() request.Method = "GET"; request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(EstimoteCloudAppId + ":" + EstimoteCloudAppToken))); - using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) + using (HttpWebResponse response = await request.GetResponseAsync(timeout) as HttpWebResponse) { if (response.StatusCode != HttpStatusCode.OK) { @@ -235,7 +236,7 @@ public List GetBeaconTagsFromCloud() return tags; } - public List GetLocationsFromCloud() + public async Task> GetLocationsFromCloudAsync(TimeSpan? timeout) { List locations = new List(); @@ -246,7 +247,7 @@ public List GetLocationsFromCloud() request.Method = "GET"; request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(EstimoteCloudAppId + ":" + EstimoteCloudAppToken))); - using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) + using (HttpWebResponse response = await request.GetResponseAsync(timeout) as HttpWebResponse) { if (response.StatusCode != HttpStatusCode.OK) { diff --git a/Sensus.Shared/Sensus.Shared.projitems b/Sensus.Shared/Sensus.Shared.projitems index 044490ef8..f2dc0e85d 100644 --- a/Sensus.Shared/Sensus.Shared.projitems +++ b/Sensus.Shared/Sensus.Shared.projitems @@ -272,6 +272,7 @@ + diff --git a/Sensus.Shared/UI/EstimoteBeaconProbeBeaconsPage.cs b/Sensus.Shared/UI/EstimoteBeaconProbeBeaconsPage.cs index eb8b2d835..832975a96 100644 --- a/Sensus.Shared/UI/EstimoteBeaconProbeBeaconsPage.cs +++ b/Sensus.Shared/UI/EstimoteBeaconProbeBeaconsPage.cs @@ -60,7 +60,7 @@ public EstimoteBeaconProbeBeaconsPage(EstimoteBeaconProbe probe) List beaconTags; try { - beaconTags = estimoteBeaconProbe.GetBeaconTagsFromCloud(); + beaconTags = await estimoteBeaconProbe.GetBeaconTagsFromCloudAsync(TimeSpan.FromSeconds(10)); if (beaconTags.Count == 0) { @@ -69,7 +69,7 @@ public EstimoteBeaconProbeBeaconsPage(EstimoteBeaconProbe probe) } catch (Exception ex) { - await SensusServiceHelper.Get().FlashNotificationAsync("Cannot add beacon: " + ex); + await SensusServiceHelper.Get().FlashNotificationAsync("Failed to add beacon: " + ex.Message); return; } diff --git a/Sensus.Shared/UI/ProbePage.cs b/Sensus.Shared/UI/ProbePage.cs index 2dcb2c810..4694b5cd8 100644 --- a/Sensus.Shared/UI/ProbePage.cs +++ b/Sensus.Shared/UI/ProbePage.cs @@ -207,7 +207,7 @@ public ProbePage(Probe probe) List locations; try { - locations = estimoteBeaconProbe.GetLocationsFromCloud(); + locations = await estimoteBeaconProbe.GetLocationsFromCloudAsync(TimeSpan.FromSeconds(10)); if (locations.Count == 0) { @@ -216,7 +216,7 @@ public ProbePage(Probe probe) } catch (Exception ex) { - await SensusServiceHelper.Get().FlashNotificationAsync("Cannot set location: " + ex); + await SensusServiceHelper.Get().FlashNotificationAsync("Failed to set location: " + ex.Message); return; }