diff --git a/FileDbCache/Shared/FileDbCache.cs b/FileDbCache/Shared/FileDbCache.cs index d278375d..0ee8e092 100644 --- a/FileDbCache/Shared/FileDbCache.cs +++ b/FileDbCache/Shared/FileDbCache.cs @@ -20,7 +20,6 @@ namespace MapControl.Caching private const string expiresField = "Expires"; private readonly FileDb fileDb = new FileDb() { AutoFlush = true }; - private readonly string dbPath; public void Dispose() { @@ -29,112 +28,83 @@ namespace MapControl.Caching public void Clean() { - if (fileDb.IsOpen) - { - int deleted = fileDb.DeleteRecords(new FilterExpression(expiresField, DateTime.UtcNow, ComparisonOperatorEnum.LessThan)); + var deleted = fileDb.DeleteRecords(new FilterExpression(expiresField, DateTime.UtcNow, ComparisonOperatorEnum.LessThan)); - if (deleted > 0) - { - Debug.WriteLine("FileDbCache: Deleted {0} expired items", deleted); - fileDb.Clean(); - } + if (deleted > 0) + { + Debug.WriteLine("FileDbCache: Deleted {0} expired items.", deleted); + fileDb.Clean(); } } - private void Open() + private void Open(string path) { - if (!fileDb.IsOpen) + try { - try + fileDb.Open(path); + Debug.WriteLine("FileDbCache: Opened database " + path); + + Clean(); + } + catch + { + if (File.Exists(path)) { - fileDb.Open(dbPath); - Debug.WriteLine("FileDbCache: Opened database " + dbPath); - - Clean(); + File.Delete(path); } - catch + else { - CreateDatabase(); + Directory.CreateDirectory(Path.GetDirectoryName(path)); } + + fileDb.Create(path, new Field[] + { + new Field(keyField, DataTypeEnum.String) { IsPrimaryKey = true }, + new Field(valueField, DataTypeEnum.Byte) { IsArray = true }, + new Field(expiresField, DataTypeEnum.DateTime) + }); + + Debug.WriteLine("FileDbCache: Created database " + path); } } - private void Close() - { - if (fileDb.IsOpen) - { - fileDb.Close(); - } - } - - private void CreateDatabase() - { - Close(); - - if (File.Exists(dbPath)) - { - File.Delete(dbPath); - } - else - { - Directory.CreateDirectory(Path.GetDirectoryName(dbPath)); - } - - fileDb.Create(dbPath, new Field[] - { - new Field(keyField, DataTypeEnum.String) { IsPrimaryKey = true }, - new Field(valueField, DataTypeEnum.Byte) { IsArray = true }, - new Field(expiresField, DataTypeEnum.DateTime) - }); - - Debug.WriteLine("FileDbCache: Created database " + dbPath); - } - private Record GetRecordByKey(string key) { - Record record = null; - - if (fileDb.IsOpen) + try { - try - { - record = fileDb.GetRecordByKey(key, new string[] { valueField, expiresField }, false); - } - catch (Exception ex) - { - Debug.WriteLine("FileDbCache.GetRecordByKey(\"{0}\"): {1}", key, ex.Message); - } + return fileDb.GetRecordByKey(key, new string[] { valueField, expiresField }, false); + } + catch (Exception ex) + { + Debug.WriteLine("FileDbCache.GetRecordByKey(\"{0}\"): {1}", key, ex.Message); } - return record; + return null; } - private void AddOrUpdateRecord(string key, byte[] value, DateTime expiration) + private void AddOrUpdateRecord(string key, byte[] buffer, DateTime expiration) { - if (fileDb.IsOpen) + var fieldValues = new FieldValues(3); + fieldValues.Add(valueField, buffer ?? new byte[0]); + fieldValues.Add(expiresField, expiration); + + try { - var fieldValues = new FieldValues(3); - fieldValues.Add(valueField, value); - fieldValues.Add(expiresField, expiration); - - try + if (fileDb.GetRecordByKey(key, new string[0], false) != null) { - if (fileDb.GetRecordByKey(key, new string[0], false) != null) - { - fileDb.UpdateRecordByKey(key, fieldValues); - } - else - { - fieldValues.Add(keyField, key); - fileDb.AddRecord(fieldValues); - } - - //Debug.WriteLine("FileDbCache: Writing \"{0}\", Expires {1}", key, imageCacheItem.Expiration.ToLocalTime()); + fileDb.UpdateRecordByKey(key, fieldValues); } - catch (Exception ex) + else { - Debug.WriteLine("FileDbCache.AddOrUpdateRecord(\"{0}\"): {1}", key, ex.Message); return; + fieldValues.Add(keyField, key); + fileDb.AddRecord(fieldValues); } + + //Debug.WriteLine("FileDbCache: Writing \"{0}\", Expires {1}", key, imageCacheItem.Expiration.ToLocalTime()); + } + catch (Exception ex) + { + Debug.WriteLine("FileDbCache.AddOrUpdateRecord(\"{0}\"): {1}", key, ex.Message); return; } } } diff --git a/FileDbCache/UWP/FileDbCache.UWP.cs b/FileDbCache/UWP/FileDbCache.UWP.cs index eac150ee..13ad5bef 100644 --- a/FileDbCache/UWP/FileDbCache.UWP.cs +++ b/FileDbCache/UWP/FileDbCache.UWP.cs @@ -8,7 +8,6 @@ using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; using Windows.Storage; using Windows.Storage.Streams; -using Windows.UI.Xaml; namespace MapControl.Caching { @@ -23,24 +22,14 @@ namespace MapControl.Caching if (string.IsNullOrEmpty(fileName)) { - throw new ArgumentNullException("The parameter fileName must not be null."); + throw new ArgumentException("The parameter fileName must not be null or empty."); } - dbPath = Path.Combine(folder.Path, "TileCache.fdb"); - - Open(); - - Application.Current.Resuming += (s, e) => Open(); - Application.Current.Suspending += (s, e) => Close(); + Open(Path.Combine(folder.Path, fileName)); } public Task GetAsync(string key) { - if (key == null) - { - throw new ArgumentNullException("The parameter key must not be null."); - } - return Task.Run(() => { var record = GetRecordByKey(key); @@ -60,17 +49,7 @@ namespace MapControl.Caching public Task SetAsync(string key, IBuffer buffer, DateTime expiration) { - if (key == null) - { - throw new ArgumentNullException("The parameter key must not be null."); - } - - if (buffer == null) - { - throw new ArgumentNullException("The parameter buffer must not be null."); - } - - return Task.Run(() => AddOrUpdateRecord(key, buffer.ToArray(), expiration)); + return Task.Run(() => AddOrUpdateRecord(key, buffer?.ToArray(), expiration)); } } } diff --git a/FileDbCache/UWP/Properties/AssemblyInfo.cs b/FileDbCache/UWP/Properties/AssemblyInfo.cs index 6f344c7c..22cf3d1d 100644 --- a/FileDbCache/UWP/Properties/AssemblyInfo.cs +++ b/FileDbCache/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/FileDbCache/WPF/FileDbCache.WPF.cs b/FileDbCache/WPF/FileDbCache.WPF.cs index eddc854e..bc99b0bf 100644 --- a/FileDbCache/WPF/FileDbCache.WPF.cs +++ b/FileDbCache/WPF/FileDbCache.WPF.cs @@ -25,11 +25,7 @@ namespace MapControl.Caching path = Path.Combine(path, "TileCache.fdb"); } - dbPath = path; - - Open(); - - AppDomain.CurrentDomain.ProcessExit += (s, e) => Dispose(); + Open(path); } public override string Name @@ -153,9 +149,9 @@ namespace MapControl.Caching var imageCacheItem = value as ImageCacheItem; - if (imageCacheItem == null || imageCacheItem.Buffer == null || imageCacheItem.Buffer.Length == 0) + if (imageCacheItem == null) { - throw new ArgumentException("The parameter value must be an ImageCacheItem with a non-empty Buffer."); + throw new ArgumentException("The parameter value must be a MapControl.Caching.ImageCacheItem instance."); } AddOrUpdateRecord(key, imageCacheItem.Buffer, imageCacheItem.Expiration); diff --git a/FileDbCache/WPF/Properties/AssemblyInfo.cs b/FileDbCache/WPF/Properties/AssemblyInfo.cs index 6a32a65f..8dec1881 100644 --- a/FileDbCache/WPF/Properties/AssemblyInfo.cs +++ b/FileDbCache/WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MBTiles/UWP/Properties/AssemblyInfo.cs b/MBTiles/UWP/Properties/AssemblyInfo.cs index b2479f05..dbd9d616 100644 --- a/MBTiles/UWP/Properties/AssemblyInfo.cs +++ b/MBTiles/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MBTiles/WPF/Properties/AssemblyInfo.cs b/MBTiles/WPF/Properties/AssemblyInfo.cs index b746217e..61dd2889 100644 --- a/MBTiles/WPF/Properties/AssemblyInfo.cs +++ b/MBTiles/WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/Shared/ImageLoader.cs b/MapControl/Shared/ImageLoader.cs index 78b9e2ed..1c284ce4 100644 --- a/MapControl/Shared/ImageLoader.cs +++ b/MapControl/Shared/ImageLoader.cs @@ -58,6 +58,18 @@ namespace MapControl return image; } + internal class HttpResponse + { + public byte[] Buffer { get; } + public TimeSpan? MaxAge { get; } + + public HttpResponse(byte[] buffer, TimeSpan? maxAge) + { + Buffer = buffer; + MaxAge = maxAge; + } + } + internal static async Task GetHttpResponseAsync(Uri uri, bool continueOnCapturedContext = true) { HttpResponse response = null; @@ -65,24 +77,20 @@ namespace MapControl try { using (var responseMessage = await HttpClient - .GetAsync(uri, HttpCompletionOption.ResponseHeadersRead) - .ConfigureAwait(continueOnCapturedContext)) + .GetAsync(uri, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(continueOnCapturedContext)) { if (responseMessage.IsSuccessStatusCode) { IEnumerable tileInfo; + byte[] buffer = null; - if (responseMessage.Headers.TryGetValues("X-VE-Tile-Info", out tileInfo) && - tileInfo.Contains("no-tile")) + if (!responseMessage.Headers.TryGetValues("X-VE-Tile-Info", out tileInfo) || + !tileInfo.Contains("no-tile")) { - response = new HttpResponse(null, null); // no tile image - } - else - { - response = new HttpResponse( - await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(continueOnCapturedContext), - responseMessage.Headers.CacheControl?.MaxAge); + buffer = await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(continueOnCapturedContext); } + + response = new HttpResponse(buffer, responseMessage.Headers.CacheControl?.MaxAge); } else { @@ -97,17 +105,5 @@ namespace MapControl return response; } - - internal class HttpResponse - { - public byte[] Buffer { get; } - public TimeSpan? MaxAge { get; } - - public HttpResponse(byte[] buffer, TimeSpan? maxAge) - { - Buffer = buffer; - MaxAge = maxAge; - } - } } } \ No newline at end of file diff --git a/MapControl/UWP/ImageFileCache.UWP.cs b/MapControl/UWP/ImageFileCache.UWP.cs index 73459857..23ae1c75 100644 --- a/MapControl/UWP/ImageFileCache.UWP.cs +++ b/MapControl/UWP/ImageFileCache.UWP.cs @@ -13,23 +13,23 @@ namespace MapControl.Caching { public class ImageFileCache : IImageCache { - private StorageFolder rootFolder; + private readonly StorageFolder folder; - public ImageFileCache(StorageFolder rootFolder) + public ImageFileCache(StorageFolder folder) { - if (rootFolder == null) + if (folder == null) { throw new ArgumentNullException("The parameter rootFolder must not be null."); } - this.rootFolder = rootFolder; + this.folder = folder; - Debug.WriteLine("Created ImageFileCache in " + rootFolder.Path); + Debug.WriteLine("Created ImageFileCache in " + folder.Path); } public async Task GetAsync(string key) { - string path = null; + string path; try { @@ -38,29 +38,27 @@ namespace MapControl.Caching catch (Exception ex) { Debug.WriteLine("ImageFileCache: Invalid key {0}: {1}", key, ex.Message); + return null; } - if (path != null) + var item = await folder.TryGetItemAsync(path); + + if (item != null && item.IsOfType(StorageItemTypes.File)) { - var item = await rootFolder.TryGetItemAsync(path); + var file = (StorageFile)item; + //Debug.WriteLine("ImageFileCache: Reading " + file.Path); - if (item != null && item.IsOfType(StorageItemTypes.File)) + try { - var file = (StorageFile)item; - //Debug.WriteLine("ImageFileCache: Reading " + file.Path); - - try + return new ImageCacheItem { - return new ImageCacheItem - { - Buffer = await FileIO.ReadBufferAsync(file), - Expiration = (await file.Properties.GetImagePropertiesAsync()).DateTaken.UtcDateTime - }; - } - catch (Exception ex) - { - Debug.WriteLine("ImageFileCache: Reading {0}: {1}", file.Path, ex.Message); - } + Buffer = await FileIO.ReadBufferAsync(file), + Expiration = (await file.Properties.GetImagePropertiesAsync()).DateTaken.UtcDateTime + }; + } + catch (Exception ex) + { + Debug.WriteLine("ImageFileCache: Reading {0}: {1}", file.Path, ex.Message); } } @@ -69,31 +67,34 @@ namespace MapControl.Caching public async Task SetAsync(string key, IBuffer buffer, DateTime expiration) { - var folders = GetPathElements(key); - - try + if (buffer != null && buffer.Length > 0) // do not cache a no-tile entry { - var folder = rootFolder; + var folders = GetPathElements(key); - for (int i = 0; i < folders.Length - 1; i++) + try { - folder = await folder.CreateFolderAsync(folders[i], CreationCollisionOption.OpenIfExists); + var folder = this.folder; + + for (int i = 0; i < folders.Length - 1; i++) + { + folder = await folder.CreateFolderAsync(folders[i], CreationCollisionOption.OpenIfExists); + } + + var file = await folder.CreateFileAsync(folders[folders.Length - 1], CreationCollisionOption.ReplaceExisting); + //Debug.WriteLine("ImageFileCache: Writing {0}, Expires {1}", file.Path, expiration.ToLocalTime()); + + await FileIO.WriteBufferAsync(file, buffer); + + // Store expiration date in ImageProperties.DateTaken + var properties = await file.Properties.GetImagePropertiesAsync(); + properties.DateTaken = expiration; + + await properties.SavePropertiesAsync(); + } + catch (Exception ex) + { + Debug.WriteLine("ImageFileCache: Writing {0}: {1}", Path.Combine(folder.Path, Path.Combine(folders)), ex.Message); } - - var file = await folder.CreateFileAsync(folders[folders.Length - 1], CreationCollisionOption.ReplaceExisting); - //Debug.WriteLine("ImageFileCache: Writing {0}, Expires {1}", file.Path, expiration.ToLocalTime()); - - await FileIO.WriteBufferAsync(file, buffer); - - // Store expiration date in ImageProperties.DateTaken - var properties = await file.Properties.GetImagePropertiesAsync(); - properties.DateTaken = expiration; - - await properties.SavePropertiesAsync(); - } - catch (Exception ex) - { - Debug.WriteLine("ImageFileCache: Writing {0}: {1}", Path.Combine(rootFolder.Path, Path.Combine(folders)), ex.Message); } } diff --git a/MapControl/UWP/Properties/AssemblyInfo.cs b/MapControl/UWP/Properties/AssemblyInfo.cs index 7722ba51..53df0406 100644 --- a/MapControl/UWP/Properties/AssemblyInfo.cs +++ b/MapControl/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/UWP/TileImageLoader.UWP.cs b/MapControl/UWP/TileImageLoader.UWP.cs index 890b8f8c..45492559 100644 --- a/MapControl/UWP/TileImageLoader.UWP.cs +++ b/MapControl/UWP/TileImageLoader.UWP.cs @@ -33,22 +33,19 @@ namespace MapControl var cacheItem = await Cache.GetAsync(cacheKey).ConfigureAwait(false); var buffer = cacheItem?.Buffer; - if (buffer == null || cacheItem.Expiration < DateTime.UtcNow) + if (cacheItem == null || cacheItem.Expiration < DateTime.UtcNow) { var response = await ImageLoader.GetHttpResponseAsync(uri, false).ConfigureAwait(false); if (response != null) // download succeeded { - buffer = response.Buffer.AsBuffer(); + buffer = response.Buffer?.AsBuffer(); // may be null or empty when no tile available, but still be cached - if (buffer != null) // tile image available - { - await Cache.SetAsync(cacheKey, buffer, GetExpiration(response.MaxAge)).ConfigureAwait(false); - } + await Cache.SetAsync(cacheKey, buffer, GetExpiration(response.MaxAge)).ConfigureAwait(false); } } - if (buffer != null) + if (buffer != null && buffer.Length > 0) { await SetTileImageAsync(tile, () => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false); } diff --git a/MapControl/WPF/ImageFileCache.WPF.cs b/MapControl/WPF/ImageFileCache.WPF.cs index 2962e2db..709f9619 100644 --- a/MapControl/WPF/ImageFileCache.WPF.cs +++ b/MapControl/WPF/ImageFileCache.WPF.cs @@ -25,18 +25,18 @@ namespace MapControl.Caching FileSystemRights.FullControl, AccessControlType.Allow); private readonly MemoryCache memoryCache = MemoryCache.Default; - private readonly string rootFolder; + private readonly string folder; - public ImageFileCache(string rootFolder) + public ImageFileCache(string folder) { - if (string.IsNullOrEmpty(rootFolder)) + if (string.IsNullOrEmpty(folder)) { - throw new ArgumentException("The parameter rootFolder must not be null or empty."); + throw new ArgumentException("The parameter folder must not be null or empty."); } - this.rootFolder = rootFolder; + this.folder = folder; - Debug.WriteLine("Created ImageFileCache in " + rootFolder); + Debug.WriteLine("Created ImageFileCache in " + folder); } public override string Name @@ -162,16 +162,16 @@ namespace MapControl.Caching var imageCacheItem = value as ImageCacheItem; - if (imageCacheItem == null || imageCacheItem.Buffer == null || imageCacheItem.Buffer.Length == 0) + if (imageCacheItem == null) { - throw new ArgumentException("The parameter value must be an ImageCacheItem with a non-empty Buffer."); + throw new ArgumentException("The parameter value must be a MapControl.Caching.ImageCacheItem instance."); } memoryCache.Set(key, imageCacheItem, policy); - var path = GetPath(key); + string path; - if (path != null) + if (imageCacheItem.Buffer != null && imageCacheItem.Buffer.Length > 0 && (path = GetPath(key)) != null) { try { @@ -284,11 +284,11 @@ namespace MapControl.Caching { try { - return Path.Combine(rootFolder, Path.Combine(key.Split('\\', '/', ',', ':', ';'))); + return Path.Combine(folder, Path.Combine(key.Split('\\', '/', ',', ':', ';'))); } catch (Exception ex) { - Debug.WriteLine("ImageFileCache: Invalid key {0}/{1}: {2}", rootFolder, key, ex.Message); + Debug.WriteLine("ImageFileCache: Invalid key {0}/{1}: {2}", folder, key, ex.Message); } return null; diff --git a/MapControl/WPF/Properties/AssemblyInfo.cs b/MapControl/WPF/Properties/AssemblyInfo.cs index 4254f847..9fdaf6a1 100644 --- a/MapControl/WPF/Properties/AssemblyInfo.cs +++ b/MapControl/WPF/Properties/AssemblyInfo.cs @@ -8,8 +8,8 @@ using System.Windows; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/WPF/TileImageLoader.WPF.cs b/MapControl/WPF/TileImageLoader.WPF.cs index c34cb290..11096532 100644 --- a/MapControl/WPF/TileImageLoader.WPF.cs +++ b/MapControl/WPF/TileImageLoader.WPF.cs @@ -7,13 +7,17 @@ using System.IO; using System.Runtime.Caching; using System.Threading.Tasks; using System.Windows.Media; +using MapControl.Caching; namespace MapControl { - public class ImageCacheItem + namespace Caching { - public byte[] Buffer { get; set; } - public DateTime Expiration { get; set; } + public class ImageCacheItem + { + public byte[] Buffer { get; set; } + public DateTime Expiration { get; set; } + } } public partial class TileImageLoader @@ -38,22 +42,19 @@ namespace MapControl var cacheItem = await GetCacheAsync(cacheKey).ConfigureAwait(false); var buffer = cacheItem?.Buffer; - if (buffer == null || cacheItem.Expiration < DateTime.UtcNow) + if (cacheItem == null || cacheItem.Expiration < DateTime.UtcNow) { var response = await ImageLoader.GetHttpResponseAsync(uri, false).ConfigureAwait(false); if (response != null) // download succeeded { - buffer = response.Buffer; + buffer = response.Buffer; // may be null or empty when no tile available, but still be cached - if (buffer != null) // tile image available - { - await SetCacheAsync(cacheKey, buffer, GetExpiration(response.MaxAge)).ConfigureAwait(false); - } + await SetCacheAsync(cacheKey, buffer, GetExpiration(response.MaxAge)).ConfigureAwait(false); } } - if (buffer != null) + if (buffer != null && buffer.Length > 0) { SetTileImageAsync(tile, await ImageLoader.LoadImageAsync(buffer).ConfigureAwait(false)); } diff --git a/MapImages/Shared/ZoomLevelToOpacityConverter.cs b/MapImages/Shared/ZoomLevelToOpacityConverter.cs deleted file mode 100644 index 17899f5b..00000000 --- a/MapImages/Shared/ZoomLevelToOpacityConverter.cs +++ /dev/null @@ -1,63 +0,0 @@ -// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control -// © 2019 Clemens Fischer -// Licensed under the Microsoft Public License (Ms-PL) - -using System; -using System.Globalization; -#if WINDOWS_UWP -using Windows.UI.Xaml; -using Windows.UI.Xaml.Data; -#else -using System.Windows; -using System.Windows.Data; -#endif - -namespace MapControl.Images -{ - public class ZoomLevelToOpacityConverter : IValueConverter - { - public double MinZoomLevel { get; set; } = 0d; - public double MaxZoomLevel { get; set; } = 22d; - public double FadeZoomRange { get; set; } = 1d; - public double MaxOpacity { get; set; } = 1d; - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (!(value is double)) - { - return DependencyProperty.UnsetValue; - } - - var zoomLevel = (double)value; - var opacity = 0d; - - if (zoomLevel > MinZoomLevel && zoomLevel < MaxZoomLevel) - { - opacity = MaxOpacity; - - if (FadeZoomRange > 0d) - { - opacity = Math.Min(opacity, (zoomLevel - MinZoomLevel) / FadeZoomRange); - opacity = Math.Min(opacity, (MaxZoomLevel - zoomLevel) / FadeZoomRange); - } - } - - return opacity; - } - - public object Convert(object value, Type targetType, object parameter, string language) - { - return Convert(value, targetType, parameter, CultureInfo.InvariantCulture); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - - public object ConvertBack(object value, Type targetType, object parameter, string language) - { - throw new NotSupportedException(); - } - } -} diff --git a/MapImages/UWP/MapImages.UWP.csproj b/MapImages/UWP/MapImages.UWP.csproj index f1d2065b..f1d3b7c2 100644 --- a/MapImages/UWP/MapImages.UWP.csproj +++ b/MapImages/UWP/MapImages.UWP.csproj @@ -46,9 +46,6 @@ WorldFileImage.cs - - ZoomLevelToOpacityConverter.cs - diff --git a/MapImages/UWP/Properties/AssemblyInfo.cs b/MapImages/UWP/Properties/AssemblyInfo.cs index bc56bdfd..fefde313 100644 --- a/MapImages/UWP/Properties/AssemblyInfo.cs +++ b/MapImages/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapImages/WPF/MapImages.WPF.csproj b/MapImages/WPF/MapImages.WPF.csproj index 9d661ecf..a5b2dc63 100644 --- a/MapImages/WPF/MapImages.WPF.csproj +++ b/MapImages/WPF/MapImages.WPF.csproj @@ -54,9 +54,6 @@ WorldFileImage.cs - - ZoomLevelToOpacityConverter.cs - diff --git a/MapImages/WPF/Properties/AssemblyInfo.cs b/MapImages/WPF/Properties/AssemblyInfo.cs index f8dbde18..c296f1ec 100644 --- a/MapImages/WPF/Properties/AssemblyInfo.cs +++ b/MapImages/WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapProjections/UWP/Properties/AssemblyInfo.cs b/MapProjections/UWP/Properties/AssemblyInfo.cs index 8f17d59b..a5cf22a2 100644 --- a/MapProjections/UWP/Properties/AssemblyInfo.cs +++ b/MapProjections/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapProjections/WPF/Properties/AssemblyInfo.cs b/MapProjections/WPF/Properties/AssemblyInfo.cs index 70921fba..e0efdc4a 100644 --- a/MapProjections/WPF/Properties/AssemblyInfo.cs +++ b/MapProjections/WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/SQLiteCache/Shared/SQLiteCache.cs b/SQLiteCache/Shared/SQLiteCache.cs index d062f7aa..b574c401 100644 --- a/SQLiteCache/Shared/SQLiteCache.cs +++ b/SQLiteCache/Shared/SQLiteCache.cs @@ -47,6 +47,23 @@ namespace MapControl.Caching command.Parameters.AddWithValue("@exp", DateTime.UtcNow.Ticks); command.ExecuteNonQuery(); } +#if DEBUG + using (var command = new SQLiteCommand("select changes()", connection)) + { + var deleted = (long)command.ExecuteScalar(); + if (deleted > 0) + { + Debug.WriteLine("SQLiteCache: Deleted {0} expired items.", deleted); + } + } +#endif + } + + private SQLiteCommand RemoveItemCommand(string key) + { + var command = new SQLiteCommand("delete from items where key = @key", connection); + command.Parameters.AddWithValue("@key", key); + return command; } private SQLiteCommand GetItemCommand(string key) @@ -61,14 +78,7 @@ namespace MapControl.Caching var command = new SQLiteCommand("insert or replace into items (key, expiration, buffer) values (@key, @exp, @buf)", connection); command.Parameters.AddWithValue("@key", key); command.Parameters.AddWithValue("@exp", expiration.Ticks); - command.Parameters.AddWithValue("@buf", buffer); - return command; - } - - private SQLiteCommand RemoveItemCommand(string key) - { - var command = new SQLiteCommand("delete from items where key = @key", connection); - command.Parameters.AddWithValue("@key", key); + command.Parameters.AddWithValue("@buf", buffer ?? new byte[0]); return command; } } diff --git a/SQLiteCache/UWP/Properties/AssemblyInfo.cs b/SQLiteCache/UWP/Properties/AssemblyInfo.cs index 209b1f56..0042342f 100644 --- a/SQLiteCache/UWP/Properties/AssemblyInfo.cs +++ b/SQLiteCache/UWP/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/SQLiteCache/UWP/SQLiteCache.UWP.cs b/SQLiteCache/UWP/SQLiteCache.UWP.cs index 8811b41d..81fd5caf 100644 --- a/SQLiteCache/UWP/SQLiteCache.UWP.cs +++ b/SQLiteCache/UWP/SQLiteCache.UWP.cs @@ -26,7 +26,7 @@ namespace MapControl.Caching if (string.IsNullOrEmpty(fileName)) { - throw new ArgumentNullException("The parameter fileName must not be null."); + throw new ArgumentException("The parameter fileName must not be null or empty."); } connection = Open(Path.Combine(folder.Path, fileName)); @@ -36,13 +36,6 @@ namespace MapControl.Caching public async Task GetAsync(string key) { - if (key == null) - { - throw new ArgumentNullException("The parameter key must not be null."); - } - - ImageCacheItem imageCacheItem = null; - try { using (var command = GetItemCommand(key)) @@ -51,7 +44,7 @@ namespace MapControl.Caching if (await reader.ReadAsync()) { - imageCacheItem = new ImageCacheItem + return new ImageCacheItem { Expiration = new DateTime((long)reader["expiration"]), Buffer = ((byte[])reader["buffer"]).AsBuffer() @@ -64,24 +57,14 @@ namespace MapControl.Caching Debug.WriteLine("SQLiteCache.GetAsync(\"{0}\"): {1}", key, ex.Message); } - return imageCacheItem; + return null; } public async Task SetAsync(string key, IBuffer buffer, DateTime expiration) { - if (key == null) - { - throw new ArgumentNullException("The parameter key must not be null."); - } - - if (buffer == null) - { - throw new ArgumentNullException("The parameter buffer must not be null."); - } - try { - using (var command = SetItemCommand(key, expiration, buffer.ToArray())) + using (var command = SetItemCommand(key, expiration, buffer?.ToArray())) { await command.ExecuteNonQueryAsync(); } diff --git a/SQLiteCache/WPF/Properties/AssemblyInfo.cs b/SQLiteCache/WPF/Properties/AssemblyInfo.cs index ccf61663..a8478042 100644 --- a/SQLiteCache/WPF/Properties/AssemblyInfo.cs +++ b/SQLiteCache/WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/SQLiteCache/WPF/SQLiteCache.WPF.cs b/SQLiteCache/WPF/SQLiteCache.WPF.cs index 431b03cc..f3241714 100644 --- a/SQLiteCache/WPF/SQLiteCache.WPF.cs +++ b/SQLiteCache/WPF/SQLiteCache.WPF.cs @@ -121,8 +121,6 @@ namespace MapControl.Caching throw new ArgumentNullException("The parameter key must not be null."); } - ImageCacheItem imageCacheItem = null; - try { using (var command = GetItemCommand(key)) @@ -131,7 +129,7 @@ namespace MapControl.Caching if (reader.Read()) { - imageCacheItem = new ImageCacheItem + return new ImageCacheItem { Expiration = new DateTime((long)reader["expiration"]), Buffer = (byte[])reader["buffer"] @@ -144,7 +142,7 @@ namespace MapControl.Caching Debug.WriteLine("SQLiteCache.Get(\"{0}\"): {1}", key, ex.Message); } - return imageCacheItem; + return null; } public override CacheItem GetCacheItem(string key, string regionName = null) @@ -173,9 +171,9 @@ namespace MapControl.Caching var imageCacheItem = value as ImageCacheItem; - if (imageCacheItem == null || imageCacheItem.Buffer == null || imageCacheItem.Buffer.Length == 0) + if (imageCacheItem == null) { - throw new ArgumentException("The parameter value must be an ImageCacheItem with a non-empty Buffer."); + throw new ArgumentException("The parameter value must be a MapControl.Caching.ImageCacheItem instance."); } try diff --git a/SampleApps/UniversalApp/Properties/AssemblyInfo.cs b/SampleApps/UniversalApp/Properties/AssemblyInfo.cs index 884332db..37bb602f 100644 --- a/SampleApps/UniversalApp/Properties/AssemblyInfo.cs +++ b/SampleApps/UniversalApp/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyCopyright("Copyright © 2019 Clemens Fischer")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("4.13.0")] -[assembly: AssemblyFileVersion("4.13.0")] +[assembly: AssemblyVersion("4.13.1")] +[assembly: AssemblyFileVersion("4.13.1")] [assembly: AssemblyConfiguration("")] [assembly: ComVisible(false)]