Version 4.3.0. Changed FileDbCache folder structure. New UWP project files.

This commit is contained in:
ClemensF 2017-10-22 22:34:44 +02:00
parent a7bb9e1ef4
commit 2f123886ff
31 changed files with 184 additions and 256 deletions

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl.Caching</RootNamespace>
<AssemblyName>FileDbCache.UWP</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.10240.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="FileDbCache.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\FileDbCache.UWP.rd.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.0.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="..\..\MapControl.snk">
<Link>MapControl.snk</Link>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MapControl\UWP\MapControl.UWP.csproj">
<Project>{9545f73c-9c35-4cf6-baae-19a0baebd344}</Project>
<Name>MapControl.UWP</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="FileDbPcl, Version=6.1.0.0, Culture=neutral, PublicKeyToken=ba3f58a0e60cd01d, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\FileDb\FileDbPcl.dll</HintPath>
</Reference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,260 @@
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using FileDbNs;
namespace MapControl.Caching
{
/// <summary>
/// IImageCache implementation based on FileDb, a free and simple No-SQL database by EzTools Software.
/// See http://www.eztools-software.com/tools/filedb/.
/// </summary>
public sealed class FileDbCache : IImageCache, IDisposable
{
private const string keyField = "Key";
private const string valueField = "Value";
private const string expiresField = "Expires";
private readonly FileDb fileDb = new FileDb();
private readonly StorageFolder folder;
private readonly string fileName;
public FileDbCache(StorageFolder folder, string fileName = "TileCache.fdb", bool autoFlush = true, int autoCleanThreshold = -1)
{
if (folder == null)
{
throw new ArgumentNullException("The parameter folder must not be null.");
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException("The parameter fileName must not be null.");
}
this.folder = folder;
this.fileName = fileName;
fileDb.AutoFlush = autoFlush;
fileDb.AutoCleanThreshold = autoCleanThreshold;
Application.Current.Resuming += async (s, e) => await Open();
Application.Current.Suspending += (s, e) => Close();
var task = Open();
}
public void Dispose()
{
Close();
}
public void Clean()
{
if (fileDb.IsOpen)
{
int deleted = fileDb.DeleteRecords(new FilterExpression(expiresField, DateTime.UtcNow, ComparisonOperatorEnum.LessThan));
if (deleted > 0)
{
Debug.WriteLine("FileDbCache: Deleted {0} expired items", deleted);
fileDb.Clean();
}
}
}
public Task<ImageCacheItem> GetAsync(string key)
{
if (key == null)
{
throw new ArgumentNullException("The parameter key must not be null.");
}
if (!fileDb.IsOpen)
{
return null;
}
return Task.Run(() => Get(key));
}
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(async () =>
{
if (fileDb.IsOpen)
{
var bytes = buffer.ToArray();
var ok = AddOrUpdateRecord(key, bytes, expiration);
if (!ok && (await RepairDatabase()))
{
AddOrUpdateRecord(key, bytes, expiration);
}
}
});
}
private async Task Open()
{
if (!fileDb.IsOpen)
{
try
{
var file = await folder.GetFileAsync(fileName);
var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
fileDb.Open(stream.AsStream());
Debug.WriteLine("FileDbCache: Opened database with {0} cached items in {1}", fileDb.NumRecords, file.Path);
Clean();
}
catch
{
await CreateDatabase();
}
}
}
private void Close()
{
if (fileDb.IsOpen)
{
fileDb.Close();
}
}
private async Task CreateDatabase()
{
Close();
var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
fileDb.Create(stream.AsStream(), 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 " + file.Path);
}
private async Task<bool> RepairDatabase()
{
try
{
fileDb.Reindex();
return true;
}
catch (Exception ex)
{
Debug.WriteLine("FileDbCache: FileDb.Reindex(): " + ex.Message);
}
try
{
await CreateDatabase();
return true;
}
catch (Exception ex)
{
Debug.WriteLine("FileDbCache: Creating database {0}: {1}", Path.Combine(folder.Path, fileName), ex.Message);
}
return false;
}
private ImageCacheItem Get(string key)
{
var fields = new string[] { valueField, expiresField };
try
{
var record = fileDb.GetRecordByKey(key, fields, false);
if (record != null)
{
return new ImageCacheItem
{
Buffer = ((byte[])record[0]).AsBuffer(),
Expiration = (DateTime)record[1]
};
}
}
catch (Exception ex)
{
Debug.WriteLine("FileDbCache: FileDb.GetRecordByKey(\"{0}\"): {1}", key, ex.Message);
}
return null;
}
private bool AddOrUpdateRecord(string key, byte[] value, DateTime expiration)
{
var fieldValues = new FieldValues(3);
fieldValues.Add(valueField, value);
fieldValues.Add(expiresField, expiration);
bool recordExists;
try
{
recordExists = fileDb.GetRecordByKey(key, new string[0], false) != null;
}
catch (Exception ex)
{
Debug.WriteLine("FileDbCache: FileDb.GetRecordByKey(\"{0}\"): {1}", key, ex.Message);
return false;
}
if (recordExists)
{
try
{
fileDb.UpdateRecordByKey(key, fieldValues);
}
catch (Exception ex)
{
Debug.WriteLine("FileDbCache: FileDb.UpdateRecordByKey(\"{0}\"): {1}", key, ex.Message);
return false;
}
}
else
{
try
{
fieldValues.Add(keyField, key);
fileDb.AddRecord(fieldValues);
}
catch (Exception ex)
{
Debug.WriteLine("FileDbCache: FileDb.AddRecord(\"{0}\"): {1}", key, ex.Message);
return false;
}
}
//Debug.WriteLine("FileDbCache: Writing \"{0}\", Expires {1}", key, expiration.ToLocalTime());
return true;
}
}
}

View file

@ -0,0 +1,14 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("XAML Map Control FileDbCache (UWP)")]
[assembly: AssemblyDescription("IImageCache implementation based on EzTools FileDb")]
[assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("4.3.0")]
[assembly: AssemblyFileVersion("4.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="FileDbCache.UWP">
</Library>
</Directives>