WeatherInformation WP8
authorgu.martinm@gmail.com <gu.martinm@gmail.com>
Fri, 15 Aug 2014 21:25:10 +0000 (23:25 +0200)
committergu.martinm@gmail.com <gu.martinm@gmail.com>
Fri, 15 Aug 2014 21:25:10 +0000 (23:25 +0200)
Using ConfigureAwait(false) for async methods.
Updates in database.

WindowsPhone/WeatherInformation/WeatherInformation/App.xaml.cs
WindowsPhone/WeatherInformation/WeatherInformation/MainPage.xaml.cs
WindowsPhone/WeatherInformation/WeatherInformation/MapPage.xaml.cs
WindowsPhone/WeatherInformation/WeatherInformation/Model/Location.cs
WindowsPhone/WeatherInformation/WeatherInformation/Model/Services/CustomHTTPClient.cs

index 592dcc6..b10cfec 100644 (file)
@@ -98,110 +98,6 @@ namespace WeatherInformation
             }
         }
 
-        public bool IsStoredDataFresh()
-        {
-            // Check to see if the data is fresh.
-            // This example uses 30 seconds as the valid time window to make it easy to test. 
-            // Real apps will use a larger window.
-
-            // Check the time elapsed since data was last saved to isolated storage.
-            TimeSpan TimeSinceLastSave = TimeSpan.FromSeconds(0);
-            if (IsolatedStorageSettings.ApplicationSettings.Contains("DataLastSavedTime"))
-            {
-                DateTime dataLastSaveTime = (DateTime)IsolatedStorageSettings.ApplicationSettings["DataLastSavedTime"];
-                TimeSinceLastSave = DateTime.Now - dataLastSaveTime;
-            }
-
-            if (TimeSinceLastSave.TotalSeconds < 30)
-            {
-                return true;
-            }
-
-            return false;
-        }
-
-        public WeatherData GetIsolatedStoredData()
-        {
-            string JSONRemoteCurrentWeather = null;
-            string JSONRemoteForecastWeather = null;
-            string city = null;
-            string country = null;
-
-            using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
-            {
-                if (isoStore.FileExists("JSONRemoteCurrentWeatherFile.txt") &&
-                    isoStore.FileExists("JSONRemoteForecastWeatherFile.txt") &&
-                    isoStore.FileExists("CityFile.txt") &&
-                    isoStore.FileExists("CountryFile.txt"))
-                {
-                    using (IsolatedStorageFileStream file = isoStore.OpenFile("JSONRemoteCurrentWeatherFile.txt", FileMode.Open))
-                    using (StreamReader sr = new StreamReader(file))
-                    {
-                        // This method loads the data from isolated storage, if it is available.
-                        JSONRemoteCurrentWeather = sr.ReadLine();
-                    }
-
-                    using (IsolatedStorageFileStream file = isoStore.OpenFile("CityFile.txt", FileMode.Open))
-                    using (StreamReader sr = new StreamReader(file))
-                    {
-                        // This method loads the data from isolated storage, if it is available.
-                        city = sr.ReadLine();
-                    }
-
-                    using (IsolatedStorageFileStream file = isoStore.OpenFile("CountryFile.txt", FileMode.Open))
-                    using (StreamReader sr = new StreamReader(file))
-                    {
-                        // This method loads the data from isolated storage, if it is available.
-                        country = sr.ReadLine();
-                    }
-                }
-            }
-
-            if (!string.IsNullOrEmpty(JSONRemoteCurrentWeather) && !string.IsNullOrEmpty(JSONRemoteForecastWeather))
-            {
-                // TODO: I am repeating this code 2 times. What could I do to improve it?
-                var parser = new ServiceParser(new JsonParser());
-                var weatherData = parser.WeatherDataParser(JSONRemoteForecastWeather, JSONRemoteCurrentWeather);
-                weatherData.City = city ?? "";
-                weatherData.Country = country ?? "";
-
-                return weatherData;
-            }
-
-            return null;
-        }
-
-        // no way of moving temporary file atomically with IsolatedStorageFile. LINUX OWNS MICROSOFT.
-        private void SaveDataToIsolatedStorage(string fileName, string value)
-        {
-            string pathToTemporaryFile = CreateTemporaryFile(fileName);
-
-            SaveDataToTemporaryFile(pathToTemporaryFile, value);
-
-            using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
-            {
-                // NO FUCKING WAY, MoveFile throws exception if destination file exists!!!!
-                // And documentation doesn't say anything... ROFL
-                // Linux OWNS Microsoft...
-                // If there are corrupted files do not blame me.... Unbelievable....
-                if (isoStore.FileExists(fileName))
-                {
-                    isoStore.DeleteFile(fileName);
-                }
-                isoStore.MoveFile(pathToTemporaryFile, fileName);
-            }
-        }
-
-        private string CreateTemporaryFile(string fileName)
-        {
-            using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
-            {
-                isoStore.CreateDirectory("tmp");
-            }
-
-            return Path.Combine("tmp", fileName);
-        }
-
         private void SaveDataToTemporaryFile(string pathToTemporaryFile, string value)
         {
             using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
@@ -270,9 +166,6 @@ namespace WeatherInformation
 
         // Código para ejecutar cuando la aplicación se desactiva (se envía a segundo plano)
         // Este código no se ejecutará cuando la aplicación se cierre
-        // TODO: no siempre pasa por aqui cuando se lanza una nueva ventana de la misma aplicación.
-        //       Y POR ESO HAY PROBLEMAS CON GetDataAsync PORQUE ESTO NO TIENE NADA DE NADA Y DEVUELVE NULL
-        //       Y SIEMPRE HACE UNA PETICIÓN AL SERVIDOR :(
         private void Application_Deactivated(object sender, DeactivatedEventArgs e)
         {
             // If there is data in the application member variable...
@@ -282,33 +175,17 @@ namespace WeatherInformation
                 if (!string.IsNullOrEmpty(weatherData.JSONRemoteCurrent) &&
                     !string.IsNullOrEmpty(weatherData.JSONRemoteForecast))
                 {
-                    // TODO: too many files? Remember there is a time limit for running this method!!! :/
-
                     // Store it in the State dictionary.
                     PhoneApplicationService.Current.State["JSONRemoteForecastWeather"] = weatherData.JSONRemoteForecast;
 
-                    // Also store it in isolated storage, in case the application is never reactivated.
-                    SaveDataToIsolatedStorage("JSONRemoteForecastWeatherFile.txt", weatherData.JSONRemoteForecast);
-
                     // Store it in the State dictionary.
                     PhoneApplicationService.Current.State["JSONRemoteCurrentWeather"] = weatherData.JSONRemoteCurrent;
 
-                    // Also store it in isolated storage, in case the application is never reactivated.
-                    SaveDataToIsolatedStorage("JSONRemoteCurrentWeatherFile.txt", weatherData.JSONRemoteCurrent);
-
                     // Store it in the State dictionary.
                     PhoneApplicationService.Current.State["City"] = weatherData.City;
 
-                    // Also store it in isolated storage, in case the application is never reactivated.
-                    SaveDataToIsolatedStorage("CityFile.txt", weatherData.City);
-
                     // Store it in the State dictionary.
                     PhoneApplicationService.Current.State["Country"] = weatherData.Country;
-
-                    // Also store it in isolated storage, in case the application is never reactivated.
-                    SaveDataToIsolatedStorage("CountryFile.txt", weatherData.Country);
-
-                    IsolatedStorageSettings.ApplicationSettings["DataLastSavedTime"] = DateTime.Now;
                 }
             }
         }
@@ -319,29 +196,6 @@ namespace WeatherInformation
         {
             // Asegurarse de que el estado de la aplicación requerida persiste aquí.
             // The application will not be tombstoned, so save only to isolated storage.
-            var weatherData = ApplicationDataObject;
-            if (weatherData != null)
-            {
-                if (!string.IsNullOrEmpty(weatherData.JSONRemoteForecast) &&
-                    !string.IsNullOrEmpty(weatherData.JSONRemoteCurrent))
-                {
-                    // TODO: too many files? Remember there is a time limit for running this method!!! :/
-
-                    // Also store it in isolated storage, in case the application is never reactivated.
-                    SaveDataToIsolatedStorage("JSONRemoteForecastWeatherFile.txt", weatherData.JSONRemoteForecast);
-
-                    // Also store it in isolated storage, in case the application is never reactivated.
-                    SaveDataToIsolatedStorage("JSONRemoteCurrentWeatherFile.txt", weatherData.JSONRemoteCurrent);
-
-                    // Also store it in isolated storage, in case the application is never reactivated.
-                    SaveDataToIsolatedStorage("CityFile.txt", weatherData.City);
-
-                    // Also store it in isolated storage, in case the application is never reactivated.
-                    SaveDataToIsolatedStorage("CountryFile.txt", weatherData.Country);
-
-                    IsolatedStorageSettings.ApplicationSettings["DataLastSavedTime"] = DateTime.Now;
-                }
-            }
         }
 
         // Código para ejecutar si hay un error de navegación
index b133b16..897a531 100644 (file)
@@ -76,20 +76,25 @@ namespace WeatherInformation
             // set the page's data object from the application member variable.
             // TODO: I am setting and getting ApplicationDataObject from different threads!!!! What if I do not see its last value? Do I need synchronization? :/
             WeatherData weatherData = (Application.Current as WeatherInformation.App).ApplicationDataObject;
-            if (weatherData != null &&
-                !locationItem.IsNewLocation &&
-                // TODO: NO ESTOY USANDO GetIsolatedStoredData!!!!!! :(
-                (Application.Current as WeatherInformation.App).IsStoredDataFresh())
+            if (!IsDataFresh(locationItem.LastRemoteDataUpdate) || weatherData == null)
             {
-                UpdateUI();
-            }
-            else
-            {
-                // Otherwise, call the method that loads data.
-                await GetDataAsync(locationItem);
-                // Call UpdateApplicationData on the UI thread.
-                Dispatcher.BeginInvoke(() => UpdateUI());
+                // Load remote data (aynchronous way by means of async/await)
+
+                // Gets the data from the web.
+                // TODO: multiple threads writing/reading same data :(
+                (Application.Current as WeatherInformation.App).ApplicationDataObject =
+                    await GetRemoteDataAsync(locationItem).ConfigureAwait(false);
+
+                using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
+                {
+                    locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
+                    locationItem.LastRemoteDataUpdate = DateTime.UtcNow;
+                    db.SubmitChanges();
+                }
             }
+
+            // Call UpdateUI on the UI thread.
+            Dispatcher.BeginInvoke(() => UpdateUI());
         }
 
         void UpdateUI()
@@ -109,14 +114,6 @@ namespace WeatherInformation
                 }
 
                 _mainViewModel.LoadData(weatherData);
-
-                Location locationItem = null;
-                using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
-                {
-                    locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
-                    locationItem.IsNewLocation = false;
-                    db.SubmitChanges();
-                }
             }
         }
 
@@ -131,17 +128,10 @@ namespace WeatherInformation
             NavigationService.Navigate(new Uri(uri, UriKind.Relative));
         }
 
-        async private Task GetDataAsync(Location locationItem)
-        {
-            // Gets the data from the web.
-            // TODO: multiple threads writing/reading same data :(
-            (Application.Current as WeatherInformation.App).ApplicationDataObject = await LoadDataAsync(locationItem);
-        }
-
         /// <summary>
         /// Retrieve remote weather data.
         /// </summary>
-        async public Task<WeatherData> LoadDataAsync(Location locationItem)
+        async public Task<WeatherData> GetRemoteDataAsync(Location locationItem)
         {
             double latitude = locationItem.Latitude;
             double longitude = locationItem.Longitude;
@@ -152,12 +142,12 @@ namespace WeatherInformation
             string formattedForecastURL = String.Format(
                 CultureInfo.InvariantCulture, AppResources.URIAPIOpenWeatherMapForecast,
                 AppResources.APIVersionOpenWeatherMap, latitude, longitude, resultsNumber);
-            string JSONRemoteForecastWeather = await httpClient.GetWeatherDataAsync(formattedForecastURL);
+            string JSONRemoteForecastWeather = await httpClient.GetWeatherDataAsync(formattedForecastURL).ConfigureAwait(false);
 
             string formattedCurrentURL = String.Format(
                 CultureInfo.InvariantCulture, AppResources.URIAPIOpenWeatherMapCurrent,
                 AppResources.APIVersionOpenWeatherMap, latitude, longitude, resultsNumber);
-            string JSONRemoteCurrentWeather = await httpClient.GetWeatherDataAsync(formattedCurrentURL);
+            string JSONRemoteCurrentWeather = await httpClient.GetWeatherDataAsync(formattedCurrentURL).ConfigureAwait(false);
 
             var parser = new ServiceParser(new JsonParser());
             var weatherData = parser.WeatherDataParser(JSONRemoteForecastWeather, JSONRemoteCurrentWeather);
@@ -167,6 +157,24 @@ namespace WeatherInformation
             return weatherData;
         }
 
+        private bool IsDataFresh(DateTime? lastUpdate)
+        {
+            if (lastUpdate == null)
+            {
+                return false;
+            }
+
+            // Check the time elapsed since data was last saved to isolated storage.
+            TimeSpan TimeSinceLastSave = DateTime.UtcNow - lastUpdate.Value;
+
+            if (TimeSinceLastSave.TotalSeconds < 30)
+            {
+                return true;
+            }
+
+            return false;
+        }
+
         private void Location_Click(object sender, EventArgs e)
         {
             NavigationService.Navigate(new Uri("/MapPage.xaml", UriKind.Relative));
index 1131802..585d39e 100644 (file)
@@ -180,8 +180,8 @@ namespace WeatherInformation
                     locationItem.VerticalAccuracy = geocoordinate.VerticalAccuracy;
                     locationItem.Speed = geocoordinate.Speed;
                     locationItem.Course = geocoordinate.Course;
-                    locationItem.IsNewLocation = true;
                     locationItem.IsSelected = true;
+                    locationItem.LastRemoteDataUpdate = null;
                 }
                 else
                 {
@@ -196,8 +196,8 @@ namespace WeatherInformation
                         VerticalAccuracy = geocoordinate.VerticalAccuracy,
                         Speed = geocoordinate.Speed,
                         Course = geocoordinate.Course,
-                        IsNewLocation = true,
                         IsSelected = true,
+                        LastRemoteDataUpdate = null,
                     };
 
                     // Add a location item to the local database.
index 43f93c6..d68a1cc 100644 (file)
@@ -225,21 +225,21 @@ namespace WeatherInformation.Model
             }
         }
 
-        private bool _isNewLocation;
-        [Column(CanBeNull = false)]
-        public bool IsNewLocation
+        private DateTime? _lastRemoteDataUpdate;
+        [Column(CanBeNull = true)]
+        public DateTime? LastRemoteDataUpdate
         {
             get
             {
-                return _isNewLocation;
+                return _lastRemoteDataUpdate;
             }
             set
             {
-                if (_isNewLocation != value)
+                if (_lastRemoteDataUpdate != value)
                 {
-                    NotifyPropertyChanging("IsNewLocation");
-                    _isNewLocation = value;
-                    NotifyPropertyChanged("IsNewLocation");
+                    NotifyPropertyChanging("LastRemoteDataUpdate");
+                    _lastRemoteDataUpdate = value;
+                    NotifyPropertyChanged("LastRemoteDataUpdate");
                 }
             }
         }
index aa98917..28cd3e1 100644 (file)
@@ -48,7 +48,7 @@ namespace WeatherInformation.Model.Services
                 // TODO: HttpCompletionOption, without it, by default, I am buffering the received data.
                 //       in this case it is not a problem but when receiving loads of bytes I do not
                 //       think it is a great idea to buffer all of them... :(
-                using (HttpResponseMessage response = await client.GetAsync(uriWindowsCacheSucks))
+                using (HttpResponseMessage response = await client.GetAsync(uriWindowsCacheSucks).ConfigureAwait(false))
                 {
                     response.EnsureSuccessStatusCode();