akavache.core 10.1.6

Prefix Reserved
dotnet add package akavache.core --version 10.1.6                
NuGet\Install-Package akavache.core -Version 10.1.6                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="akavache.core" Version="10.1.6" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add akavache.core --version 10.1.6                
#r "nuget: akavache.core, 10.1.6"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install akavache.core as a Cake Addin
#addin nuget:?package=akavache.core&version=10.1.6

// Install akavache.core as a Cake Tool
#tool nuget:?package=akavache.core&version=10.1.6                

NuGet Stats Build Code Coverage <br> <a href="https://www.nuget.org/packages/akavache"> <img src="https://img.shields.io/nuget/dt/akavache.svg"> </a> <a href="#backers"> <img src="https://opencollective.com/reactiveui/backers/badge.svg"> </a> <a href="#sponsors"> <img src="https://opencollective.com/reactiveui/sponsors/badge.svg"> </a> <a href="https://reactiveui.net/slack"> <img src="https://img.shields.io/badge/chat-slack-blue.svg"> </a>

<img alt="Akavache" src="https://raw.githubusercontent.com/reactiveui/styleguide/master/logo_akavache/main.png" width="150" />

Akavache: An Asynchronous Key-Value Store for Native Applications

Akavache is an asynchronous, persistent (i.e. writes to disk) key-value store created for writing desktop and mobile applications in C#, based on SQLite3. Akavache is great for both storing important data (i.e. user settings) as well as cached local data that expires.

Where can I use it?

Akavache is currently compatible with:

  • Xamarin.iOS / Xamarin.Mac / Xamarin.Android / Xamarin.TVOS / Xamarin.WatchOS
  • Maui iOS / Mac / Mac Catalyst / Android / TVOS
  • .NET 4.6.2 (and above) and .NET 6 Desktop (WPF and WinForms)
  • .NET 6.0
  • Windows 10 (Universal Windows Platform)
  • Tizen 4.0

What does that mean?

Downloading and storing remote data from the internet while still keeping the UI responsive is a task that nearly every modern application needs to do. However, many applications that don't take the consideration of caching into the design from the start often end up with inconsistent, duplicated code for caching different types of objects.

Akavache is a library that makes common app patterns easy, and unifies caching of different object types (i.e. HTTP responses vs. JSON objects vs. images).

It's built on a core key-value byte array store (conceptually similar to a Dictionary<string, byte[]>), and on top of that store, extensions are added to support:

  • Arbitrary objects via JSON.NET
  • Fetching and loading Images and URLs from the Internet
  • Storing and automatically encrypting User Credentials

Contents

Getting Started

Interacting with Akavache is primarily done through an object called BlobCache. At App startup, you must first set your app's name via BlobCache.ApplicationName or Akavache.Registrations.Start("ApplicationName") . After setting your app's name, you're ready to save some data.

For example with Xamarin Forms or WPF applications you'll place this in the constructor of your App.xaml.cs file.

Choose a location

There are four built-in locations that have some magic applied on some systems:

  • BlobCache.LocalMachine - Cached data. This data may get deleted without notification.
  • BlobCache.UserAccount - User settings. Some systems backup this data to the cloud.
  • BlobCache.Secure - For saving sensitive data - like credentials.
  • BlobCache.InMemory - A database, kept in memory. The data is stored for the lifetime of the app.

The magic

  • Xamarin.iOS may remove data, stored in BlobCache.LocalMachine, to free up disk space (only if your app is not running). The locations BlobCache.UserAccount and BlobCache.Secure will be backed up to iCloud and iTunes. Apple Documentation
  • Xamarin.Android may also start deleting data, stored in BlobCache.LocalMachine, if the system runs out of disk space. It isn't clearly specified if your app could be running while the system is cleaning this up. Android Documentation
  • Windows 10 (UWP) will replicate BlobCache.UserAccount and BlobCache.Secure to the cloud and synchronize it to all user devices on which the app is installed UWP Documentation

Platform-specific notes

  • Windows 10 (Universal Windows Platform) - You must mark your application as x86 or ARM, or else you will get a strange runtime error about SQLitePCL_Raw not loading correctly. You must also ensure that the Microsoft Visual C++ runtime is added to your project.
Handling Xamarin/Maui Linker

There are two options to ensure the Akavache.Sqlite3 dll will not be removed by Xamarin and Maui build tools

1) Add a file to reference the types

public static class LinkerPreserve
{
  static LinkerPreserve()
  {
    var persistentName = typeof(SQLitePersistentBlobCache).FullName;
    var encryptedName = typeof(SQLiteEncryptedBlobCache).FullName;
  }
}
2) Use the following initializer in your cross platform library or in your head project

Akavache.Registrations.Start("ApplicationName")

Using Akavache

The most straightforward way to use Akavache is via the object extensions:

using System.Reactive.Linq;   // IMPORTANT - this makes await work!

// Make sure you set the application name before doing any inserts or gets
Akavache.Registrations.Start("AkavacheExperiment")

var myToaster = new Toaster();
await BlobCache.UserAccount.InsertObject("toaster", myToaster);

//
// ...later, in another part of town...
//

// Using async/await
var toaster = await BlobCache.UserAccount.GetObject<Toaster>("toaster");

// or without async/await
Toaster toaster;

BlobCache.UserAccount.GetObject<Toaster>("toaster")
    .Subscribe(x => toaster = x, ex => Console.WriteLine("No Key!"));

Handling Errors

When a key is not present in the cache, GetObject throws a KeyNotFoundException (or more correctly, OnError's the IObservable). Often, you would want to return a default value instead of failing:

Toaster toaster;

try {
    toaster = await BlobCache.UserAccount.GetObject("toaster");
} catch (KeyNotFoundException ex) {
    toaster = new Toaster();
}

// Or without async/await:
toaster = await BlobCache.UserAccount.GetObject<Toaster>("toaster")
    .Catch(Observable.Return(new Toaster()));

Shutting Down

Critical to the integrity of your Akavache cache is the BlobCache.Shutdown() method. You must call this when your application shuts down. Moreover, be sure to wait for the result:

BlobCache.Shutdown().Wait();

Failure to do this may mean that queued items are not flushed to the cache.

Using a different SQLitePCL.raw bundle

To use a different SQLitePCL.raw bundle, e.g. Microsoft.AppCenter:

  • Install the akavache.sqlite3 nuget instead of akavache
  • Install the SQLitePCLRaw bundle you want to use, e.g., SQLitePCLRaw.bundle_green
  • Use Akavache.Sqlite3.Registrations.Start("ApplicationName", () => SQLitePCL.Batteries_V2.Init()); in your platform projects or in your cross platform project.
<PackageReference Include="akavache.sqlite3" Version="6.0.40-g7e90c572c6" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="1.1.11" />
Akavache.Sqlite3.Registrations.Start("ApplicationName", () => SQLitePCL.Batteries_V2.Init());

For more info about using your own versions of SqlitePCL.raw

Examining Akavache caches

Using Akavache Explorer, you can dig into Akavache repos for debugging purposes to see what has been stored.

alternate text is missing from this package README image

What's this Global Variable nonsense?

Why can't I use $FAVORITE_IOC_LIBRARY?

You totally can. Just instantiate SQLitePersistentBlobCache or SQLiteEncryptedBlobCache instead - the static variables are there just to make it easier to get started.

DateTime/DateTimeOffset Considerations

Our default implementation overrides BSON to read and write DateTime's as UTC. To override the reader's behavior you can set BlobCache.ForcedDateTimeKind as in the following example:

// Sets the reader to return DateTime/DateTimeOffset in Local.
BlobCache.ForcedDateTimeKind = DateTimeKind.Local;

DateTime are stored as ticks for high precision. DateTimeOffset are stored as ticks for both the Date/Time aspect and the offset.

Basic Method Documentation

Every blob cache supports the basic raw operations given below (some of them are not implemented directly, but are added on via extension methods):

/*
 * Get items from the store
 */

// Get a single item
IObservable<byte[]> Get(string key);

// Get a list of items
IObservable<IDictionary<string, byte[]>> Get(IEnumerable<string> keys);

// Get an object serialized via InsertObject
IObservable<T> GetObject<T>(string key);

// Get all objects of type T
IObservable<IEnumerable<T>> GetAllObjects<T>();

// Get a list of objects given a list of keys
IObservable<IDictionary<string, T>> GetObjects<T>(IEnumerable<string> keys);

/*
 * Save items to the store
 */

// Insert a single item
IObservable<Unit> Insert(string key, byte[] data, DateTimeOffset? absoluteExpiration = null);

// Insert a set of items
IObservable<Unit> Insert(IDictionary<string, byte[]> keyValuePairs, DateTimeOffset? absoluteExpiration = null);

// Insert a single object
IObservable<Unit> InsertObject<T>(string key, T value, DateTimeOffset? absoluteExpiration = null);

// Insert a group of objects
IObservable<Unit> InsertObjects<T>(IDictionary<string, T> keyValuePairs, DateTimeOffset? absoluteExpiration = null);

/*
 * Remove items from the store
 */

// Delete a single item
IObservable<Unit> Invalidate(string key);

// Delete a list of items
IObservable<Unit> Invalidate(IEnumerable<string> keys);

// Delete a single object (do *not* use Invalidate for items inserted with InsertObject!)
IObservable<Unit> InvalidateObject<T>(string key);

// Deletes a list of objects
IObservable<Unit> InvalidateObjects<T>(IEnumerable<string> keys);

// Deletes all items (regardless if they are objects or not)
IObservable<Unit> InvalidateAll();

// Deletes all objects of type T
IObservable<Unit> InvalidateAllObjects<T>();

/*
 * Get Metadata about items
 */

// Return a list of all keys. Use for debugging purposes only.
IObservable<IEnumerable<string>> GetAllKeys();

// Return the time which an item was created
IObservable<DateTimeOffset?> GetCreatedAt(string key);

// Return the time which an object of type T was created
IObservable<DateTimeOffset?> GetObjectCreatedAt<T>(string key);

// Return the time which a list of keys were created
IObservable<IDictionary<string, DateTimeOffset?>> GetCreatedAt(IEnumerable<string> keys);

/*
 * Utility methods
 */

// Attempt to ensure all outstanding operations are written to disk
IObservable<Unit> Flush();

// Preemptively drop all expired keys and run SQLite's VACUUM method on the
// underlying database
IObservable<Unit> Vacuum();

Extension Method Documentation

On top of every IBlobCache object, there are extension methods that help with common application scenarios:

/*
 * Username / Login Methods (only available on ISecureBlobCache)
 */

// Save login information for the given host
IObservable<Unit> SaveLogin(string user, string password, string host = "default", DateTimeOffset? absoluteExpiration = null);

// Load information for the given host
IObservable<LoginInfo> GetLoginAsync(string host = "default");

// Erase information for the given host
IObservable<Unit> EraseLogin(string host = "default");

/*
 * Downloading and caching URLs and Images
 */

// Download a file as a byte array
IObservable<byte[]> DownloadUrl(string url,
    IDictionary<string, string> headers = null,
    bool fetchAlways = false,
    DateTimeOffset? absoluteExpiration = null);

// Load a given key as an image
IObservable<IBitmap> LoadImage(string key, float? desiredWidth = null, float? desiredHeight = null);

// Download an image from the network and load it
IObservable<IBitmap> LoadImageFromUrl(string url,
    bool fetchAlways = false,
    float? desiredWidth = null,
    float? desiredHeight = null,
    DateTimeOffset? absoluteExpiration = null);

/*
 * Composite operations
 */

// Attempt to return an object from the cache. If the item doesn't
// exist or returns an error, call a Func to return the latest
// version of an object and insert the result in the cache.
IObservable<T> GetOrFetchObject<T>(string key, Func<Task<T>> fetchFunc, DateTimeOffset? absoluteExpiration = null);

// Like GetOrFetchObject, but isn't async
IObservable<T> GetOrCreateObject<T>(string key, Func<T> fetchFunc, DateTimeOffset? absoluteExpiration = null);

// Immediately return a cached version of an object if available, but *always*
// also execute fetchFunc to retrieve the latest version of an object.
IObservable<T> GetAndFetchLatest<T>(this IBlobCache This,
    string key,
    Func<IObservable<T>> fetchFunc,
    Func<DateTimeOffset, bool> fetchPredicate = null,
    DateTimeOffset? absoluteExpiration = null,
    bool shouldInvalidateOnError = false,
    Func<T, bool> cacheValidationPredicate = null)
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-android34.0 is compatible.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-ios17.5 is compatible.  net8.0-maccatalyst was computed.  net8.0-maccatalyst17.5 is compatible.  net8.0-macos was computed.  net8.0-macos14.5 is compatible.  net8.0-tvos was computed.  net8.0-tvos17.5 is compatible.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (12)

Showing the top 5 NuGet packages that depend on akavache.core:

Package Downloads
akavache.sqlite3

Akavache Sqlite3

akavache.mobile

An asynchronous, persistent key-value store for desktop and mobile applications on .NET

Akavache.Drawing

An asynchronous, persistent key-value store for desktop and mobile applications on .NET

Optimizely.Commerce.API

Package Description

Lager

A cross-platform settings storage for .NET

GitHub repositories (7)

Showing the top 5 popular GitHub repositories that depend on akavache.core:

Repository Stars
CodeHubApp/CodeHub
CodeHub is an iOS application written using Xamarin
flagbug/Espera
Espera is a media player that plays your music, YouTube videos, SoundCloud songs and has a special "party mode".
Clancey/gMusic
This is a multi platform music player.
thedillonb/CodeBucket
CodeBucket is the best way to browse and maintain your Bitbucket repositories on any iPhone, iPod Touch, and iPad device!
kentcb/WorkoutWotch
Repository for my video series on building an iOS app in .NET.
Version Downloads Last updated
10.1.6 3,859 9/16/2024
10.0.1 46,016 5/1/2024
9.1.20 238,972 6/29/2023
9.1.7 67,782 2/1/2023
9.0.1 218,149 6/25/2022
8.1.1 234,341 12/12/2021
7.3.47 16,178 11/26/2021
7.3.1 142,231 6/6/2021
7.2.1 256,548 1/22/2021
7.1.1 189,481 10/23/2020
6.10.20 4,198,442 6/12/2020
6.10.17 54,693 5/7/2020
6.10.11 17,324 4/23/2020
6.10.6 16,423 4/1/2020
6.10.4 123,000 2/5/2020
6.10.3 11,146 1/29/2020
6.10.2 8,025 1/27/2020
6.10.1 2,576 1/27/2020
6.9.10 50,293 11/4/2019
6.9.1 42,590 10/5/2019
6.8.1 19,865 9/6/2019
6.7.1 16,596 8/6/2019
6.6.1 2,664 8/6/2019
6.5.20 18,732 7/28/2019
6.5.9 35,566 6/7/2019
6.5.1 93,468 3/27/2019
6.4.1 7,225,870 3/3/2019
6.3.6 9,911 2/19/2019
6.3.2 14,800 2/1/2019
6.3.1 4,709 1/25/2019
6.2.3 21,665 12/27/2018
6.2.1 2,949 12/27/2018
6.1.3 4,449 12/24/2018
6.1.2 3,776 12/24/2018
6.1.1 4,103 12/23/2018
6.0.31 43,582 11/11/2018
6.0.30 44,303 10/17/2018
6.0.27 16,996 10/5/2018
6.0.20 66,147 9/5/2018
6.0.19-beta 2,443 9/3/2018
6.0.17-beta 4,338 8/24/2018
6.0.0-alpha0038 92,463 9/3/2017
5.0.0 523,596 11/4/2016
4.1.2 105,391 10/27/2015
4.1.1 25,301 3/26/2015
4.1.0 7,172 1/3/2015
4.0.4 5,181 11/6/2014
4.0.3.2 9,592 8/28/2014
4.0.3.1 3,279 8/28/2014
4.0.3 3,255 8/28/2014
4.0.2.1 3,096 8/26/2014
4.0.2 3,154 8/25/2014
4.0.1 3,461 8/8/2014
4.0.0 8,654 8/3/2014
3.99.3-beta 2,473 7/25/2014
3.99.2-beta 2,416 7/17/2014
3.99.1-beta 2,552 2/8/2014