![]() |
VOOZH | about |
dotnet add package Akavache --version 11.1.1
NuGet\Install-Package Akavache -Version 11.1.1
<PackageReference Include="Akavache" Version="11.1.1" />
<PackageVersion Include="Akavache" Version="11.1.1" />Directory.Packages.props
<PackageReference Include="Akavache" />Project file
paket add Akavache --version 11.1.1
#r "nuget: Akavache, 11.1.1"
#:package Akavache@11.1.1
#addin nuget:?package=Akavache&version=11.1.1Install as a Cake Addin
#tool nuget:?package=Akavache&version=11.1.1Install as a Cake Tool
๐ NuGet Stats
๐ Build
๐ Code Coverage
<br>
<a href="https://www.nuget.org/packages/akavache.sqlite3">
<img src="https://img.shields.io/nuget/dt/akavache.sqlite3.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 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.
Akavache V11.0 introduces a new Builder Pattern for initialization, improved serialization support, and enhanced cross-serializer compatibility:
Akavache V11.0 represents a significant evolution in the library's architecture, developed through extensive testing and community feedback in our incubator project. The new features and improvements in V11.0 were first prototyped and battle-tested in the ReactiveMarbles.CacheDatabase repository, which served as an experimental ground for exploring new caching concepts and architectural patterns.
Key Development Milestones:
This careful incubation process ensured that V11.0 delivers not just new features, but a more robust, flexible, and maintainable caching solution that builds upon years of community experience and testing. The ReactiveMarbles organization continues to serve as a proving ground for innovative reactive programming concepts that eventually make their way into the broader ReactiveUI ecosystem.
<PackageReference Include="Akavache.Sqlite3" Version="11.0.*" />
<PackageReference Include="Akavache.SystemTextJson" Version="11.0.*" />
Note:
WithAkavacheWithAkavacheCacheDatabaseandInitializealways requires anISerializerdefined as a generic type, such asWithAkavache<SystemJsonSerializer>. This ensures the cache instance is properly configured for serialization.
using Akavache.Core;
using Akavache.SystemTextJson;
using Akavache.Sqlite3;
using Splat.Builder;
// Initialize with the builder pattern
AppBuilder.CreateSplatBuilder()
.WithAkavacheCacheDatabase<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider() // Use SQLite backend - new in V11.0.2 + (Required for Sqlite, this is to avoid confusion between Sqlite and EncryptedSqlite which both have `Batteries_V2.Init();` calls)
.WithSqliteDefaults());
using Akavache.Core;
using Akavache.SystemTextJson;
using Akavache.Sqlite3;
using Splat.Builder;
// Example: Register Akavache with Splat DI
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(
"MyApp",
builder => builder.WithSqliteDefaults(),
(splat, instance) => splat.RegisterLazySingleton(() => instance));
// For in-memory cache (testing or lightweight scenarios):
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(
"Akavache",
builder => builder.WithInMemoryDefaults(),
(splat, instance) => splat.RegisterLazySingleton(() => instance));
using Akavache.Core;
using Akavache.SystemTextJson;
using Akavache.Sqlite3;
var akavacheInstance = CacheDatabase.CreateBuilder()
.WithSerializer<SystemJsonSerializer>()
.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSqliteDefaults()
.Build();
// Use akavacheInstance.UserAccount, akavacheInstance.LocalMachine, etc.
// Store an object
var user = new User { Name = "John", Email = "john@example.com" };
await CacheDatabase.UserAccount.InsertObject("current_user", user);
// Retrieve an object
var cachedUser = await CacheDatabase.UserAccount.GetObject<User>("current_user");
// Store with expiration
await CacheDatabase.LocalMachine.InsertObject("temp_data", someData, DateTimeOffset.Now.AddHours(1));
// Get or fetch pattern
var data = await CacheDatabase.LocalMachine.GetOrFetchObject("api_data",
async () => await httpClient.GetFromJsonAsync<ApiResponse>("https://api.example.com/data"));
Akavache V11.0 uses a modular package structure. Choose the packages that match your needs:
<PackageReference Include="Akavache" Version="11.0.**" />
<PackageReference Include="Akavache.Sqlite3" Version="11.0.**" />
<PackageReference Include="Akavache.EncryptedSqlite3" Version="11.0.**" />
<PackageReference Include="Akavache.SystemTextJson" Version="11.0.**" />
<PackageReference Include="Akavache.NewtonsoftJson" Version="11.0.**" />
<PackageReference Include="Akavache.Drawing" Version="11.0.**" />
<PackageReference Include="Akavache.Settings" Version="11.0.**" />
BlobCache.ApplicationName and Registrations.Start() methods are replaced with the builder pattern// V10.x initialization
BlobCache.ApplicationName = "MyApp";
// or
Akavache.Registrations.Start("MyApp");
// Usage
var data = await BlobCache.UserAccount.GetObject<MyData>("key");
await BlobCache.LocalMachine.InsertObject("key", myData);
// V11.0 initialization
AppBuilder.CreateSplatBuilder()
.WithAkavacheCacheDatabase<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSqliteDefaults());
// Usage (same API)
var data = await CacheDatabase.UserAccount.GetObject<MyData>("key");
await CacheDatabase.LocalMachine.InsertObject("key", myData);
Create this helper method to ease migration:
public static class AkavacheMigration
{
public static void InitializeV11(string appName)
{
// Initialize with SQLite (most common V10.x setup)
CacheDatabase
.Initialize<SystemJsonSerializer>(builder =>
builder
.WithSqliteProvider()
.WithSqliteDefaults(),
appName);
}
}
// Then in your app:
AkavacheMigration.InitializeV11("MyApp");
Akavache V11.0 uses a fluent builder pattern for configuration:
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp") // Required
.WithSqliteProvider() // Initialize SQLite backend
.WithSqliteDefaults()); // SQLite persistence
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("TestApp")
.WithInMemoryDefaults());
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSqliteDefaults());
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithEncryptedSqliteProvider()
.WithSqliteDefaults("mySecretPassword"));
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithEncryptedSqliteProvider()
.WithUserAccount(new SqliteBlobCache("custom-user.db"))
.WithLocalMachine(new SqliteBlobCache("custom-local.db"))
.WithSecure(new EncryptedSqliteBlobCache("secure.db", "password"))
.WithInMemory(new InMemoryBlobCache()));
// Set global DateTime behavior
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithForcedDateTimeKind(DateTimeKind.Utc)
.WithSqliteDefaults());
Akavache V11.0 supports multiple serialization formats with automatic cross-compatibility.
Best for: New applications, performance-critical scenarios, .NET native support
Features:
Configuration:
var serializer = new SystemJsonSerializer()
{
UseBsonFormat = false, // true for max compatibility with old data
Options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
}
};
Best for: Migrating from older Akavache versions, complex serialization needs
Features:
Configuration:
var serializer = new NewtonsoftSerializer()
{
UseBsonFormat = true, // Recommended for Akavache compatibility
Options = new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
NullValueHandling = NullValueHandling.Ignore
}
};
Once configured, pass the serializer type to the builder:
AppBuilder.CreateSplatBuilder()
.WithAkavache<NewtonsoftSerializer>(
() => serializer,
builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSqliteDefaults());
For maximum backward compatibility with existing Akavache data: use UseBsonFormat = true in either serializer.
Akavache provides four types of caches, each with different characteristics:
Purpose: User settings and preferences that should persist and potentially sync across devices.
// Store user preferences
var settings = new UserSettings { Theme = "Dark", Language = "en-US" };
await CacheDatabase.UserAccount.InsertObject("user_settings", settings);
// Retrieve preferences
var userSettings = await CacheDatabase.UserAccount.GetObject<UserSettings>("user_settings");
Platform Behavior:
Purpose: Cached data that can be safely deleted by the system.
// Cache API responses
var apiData = await httpClient.GetFromJsonAsync<ApiResponse>("https://api.example.com/data");
await CacheDatabase.LocalMachine.InsertObject("api_cache", apiData, DateTimeOffset.Now.AddHours(6));
// Retrieve with fallback
var cachedData = await CacheDatabase.LocalMachine.GetOrFetchObject("api_cache",
() => httpClient.GetFromJsonAsync<ApiResponse>("https://api.example.com/data"));
Platform Behavior:
Purpose: Encrypted storage for sensitive data like credentials and API keys.
// Store credentials
await CacheDatabase.Secure.SaveLogin("john.doe", "secretPassword", "myapp.com");
// Retrieve credentials
var loginInfo = await CacheDatabase.Secure.GetLogin("myapp.com");
Console.WriteLine($"User: {loginInfo.UserName}, Password: {loginInfo.Password}");
// Store API keys
await CacheDatabase.Secure.InsertObject("api_key", "sk-1234567890abcdef");
var apiKey = await CacheDatabase.Secure.GetObject<string>("api_key");
Purpose: Temporary storage that doesn't persist between app sessions.
// Cache session data
var sessionData = new SessionInfo { UserId = 123, SessionToken = "abc123" };
await CacheDatabase.InMemory.InsertObject("current_session", sessionData);
// Fast temporary storage
await CacheDatabase.InMemory.InsertObject("temp_calculation", expensiveResult);
// Store simple objects
await CacheDatabase.UserAccount.InsertObject("key", myObject);
// Store with expiration
await CacheDatabase.LocalMachine.InsertObject("temp_key", data, DateTimeOffset.Now.AddMinutes(30));
// Store multiple objects
var keyValuePairs = new Dictionary<string, MyData>
{
["key1"] = new MyData { Value = 1 },
["key2"] = new MyData { Value = 2 }
};
await CacheDatabase.UserAccount.InsertObjects(keyValuePairs);
// Store raw bytes
await CacheDatabase.LocalMachine.Insert("raw_key", Encoding.UTF8.GetBytes("Hello World"));
// Get single object
var data = await CacheDatabase.UserAccount.GetObject<MyData>("key");
// Get multiple objects
var keys = new[] { "key1", "key2", "key3" };
var results = await CacheDatabase.UserAccount.GetObjects<MyData>(keys).ToList();
// Get all objects of a type
var allData = await CacheDatabase.UserAccount.GetAllObjects<MyData>().ToList();
// Get raw bytes
var rawData = await CacheDatabase.LocalMachine.Get("raw_key");
// Handle missing keys
try
{
var data = await CacheDatabase.UserAccount.GetObject<MyData>("nonexistent_key");
}
catch (KeyNotFoundException)
{
// Key not found
var defaultData = new MyData();
}
// Use fallback pattern
var data = await CacheDatabase.UserAccount.GetObject<MyData>("key")
.Catch(Observable.Return(new MyData()));
// Remove single object
await CacheDatabase.UserAccount.InvalidateObject<MyData>("key");
// Remove multiple objects
await CacheDatabase.UserAccount.InvalidateObjects<MyData>(new[] { "key1", "key2" });
// Remove all objects of a type
await CacheDatabase.UserAccount.InvalidateAllObjects<MyData>();
// Remove all data
await CacheDatabase.UserAccount.InvalidateAll();
The most common pattern for caching remote data:
// Basic get-or-fetch
var userData = await CacheDatabase.LocalMachine.GetOrFetchObject("user_profile",
async () => await apiClient.GetUserProfile(userId));
// With expiration
var weatherData = await CacheDatabase.LocalMachine.GetOrFetchObject("weather",
async () => await weatherApi.GetCurrentWeather(),
DateTimeOffset.Now.AddMinutes(30));
// With custom fetch observable
var liveData = await CacheDatabase.LocalMachine.GetOrFetchObject("live_data",
() => Observable.Interval(TimeSpan.FromSeconds(5))
.Select(_ => DateTime.Now.ToString()));
Returns cached data immediately, then fetches fresh data:
// Subscribe to get both cached and fresh data
CacheDatabase.LocalMachine.GetAndFetchLatest("news_feed",
() => newsApi.GetLatestNews())
.Subscribe(news =>
{
// This will be called twice:
// 1. Immediately with cached data (if available)
// 2. When fresh data arrives from the API
UpdateUI(news);
});
// Download and cache URLs
var imageData = await CacheDatabase.LocalMachine.DownloadUrl("https://example.com/image.jpg");
// With custom headers
var headers = new Dictionary<string, string>
{
["Authorization"] = "Bearer " + token,
["User-Agent"] = "MyApp/1.0"
};
var apiResponse = await CacheDatabase.LocalMachine.DownloadUrl("https://api.example.com/data",
HttpMethod.Get, headers);
// Force fresh download
var freshData = await CacheDatabase.LocalMachine.DownloadUrl("https://api.example.com/live",
fetchAlways: true);
// Save login credentials (encrypted)
await CacheDatabase.Secure.SaveLogin("username", "password", "myapp.com");
// Retrieve credentials
var loginInfo = await CacheDatabase.Secure.GetLogin("myapp.com");
Console.WriteLine($"User: {loginInfo.UserName}");
// Multiple hosts
await CacheDatabase.Secure.SaveLogin("user1", "pass1", "api.service1.com");
await CacheDatabase.Secure.SaveLogin("user2", "pass2", "api.service2.com");
// Cache for relative time periods
await CacheDatabase.LocalMachine.InsertObject("data", myData, TimeSpan.FromMinutes(30).FromNow());
// Use in get-or-fetch
var cachedData = await CacheDatabase.LocalMachine.GetOrFetchObject("api_data",
() => FetchFromApi(),
1.Hours().FromNow());
// Use custom scheduler for background operations
CacheDatabase.TaskpoolScheduler = TaskPoolScheduler.Default;
// Or use a custom scheduler
CacheDatabase.TaskpoolScheduler = new EventLoopScheduler();
// Get all keys (for debugging)
var allKeys = await CacheDatabase.UserAccount.GetAllKeys().ToList();
// Check when item was created
var createdAt = await CacheDatabase.UserAccount.GetCreatedAt("my_key");
if (createdAt.HasValue)
{
Console.WriteLine($"Item created at: {createdAt.Value}");
}
// Get creation times for multiple keys
var creationTimes = await CacheDatabase.UserAccount.GetCreatedAt(new[] { "key1", "key2" })
.ToList();
// Force flush all pending operations
await CacheDatabase.UserAccount.Flush();
// Vacuum database (SQLite only - removes deleted data)
await CacheDatabase.UserAccount.Vacuum();
// Flush specific object type
await CacheDatabase.UserAccount.Flush(typeof(MyDataType));
// Store different types with one operation
var mixedData = new Dictionary<string, object>
{
["string_data"] = "Hello World",
["number_data"] = 42,
["object_data"] = new MyClass { Value = "test" },
["date_data"] = DateTime.Now
};
await CacheDatabase.UserAccount.InsertObjects(mixedData);
Akavache.Drawing provides comprehensive image caching and bitmap manipulation functionality for Akavache applications. Built on Splat, it offers cross-platform support for loading, caching, and manipulating images with enhanced features beyond basic blob storage.
<PackageReference Include="Akavache.Drawing" Version="11.0.*" />
Akavache.Drawing requires:
Akavache.Core - Core caching functionalitySplat.Drawing - Cross-platform bitmap abstractionsusing Akavache.Core;
using Akavache.Drawing;
using Akavache.SystemTextJson;
using Splat;
// Initialize Akavache with drawing support
CacheDatabase.Initialize<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyImageApp")
.WithSqliteProvider()
.WithSqliteDefaults());
// Register platform-specific bitmap loader using Splat (if needed (Net 8.0+))
AppLocator.CurrentMutable.RegisterPlatformBitmapLoader();
// Load image from cache
var image = await CacheDatabase.LocalMachine.LoadImage("user_avatar");
// Load with custom sizing
var thumbnail = await CacheDatabase.LocalMachine.LoadImage("user_avatar", 150, 150);
// Load with error handling
try
{
var profileImage = await CacheDatabase.UserAccount.LoadImage("profile_pic");
DisplayImage(profileImage);
}
catch (KeyNotFoundException)
{
// Image not found in cache
ShowDefaultImage();
}
// Download and cache image from URL
var imageFromUrl = await CacheDatabase.LocalMachine
.LoadImageFromUrl("https://example.com/images/photo.jpg");
// With custom expiration
var tempImage = await CacheDatabase.LocalMachine
.LoadImageFromUrl("https://api.example.com/temp-image.png",
absoluteExpiration: DateTimeOffset.Now.AddHours(1));
// Force fresh download (bypass cache)
var freshImage = await CacheDatabase.LocalMachine
.LoadImageFromUrl("https://api.example.com/live-feed.jpg", fetchAlways: true);
// With custom key
var namedImage = await CacheDatabase.LocalMachine
.LoadImageFromUrl("user_background", "https://example.com/bg.jpg");
// Save image to cache
await CacheDatabase.LocalMachine.SaveImage("user_photo", bitmap);
// Save with expiration
await CacheDatabase.LocalMachine.SaveImage("temp_image", bitmap,
DateTimeOffset.Now.AddDays(7));
// Convert bitmap to bytes for manual storage
var imageBytes = await bitmap.ImageToBytes().FirstAsync();
await CacheDatabase.LocalMachine.Insert("raw_image_data", imageBytes);
// Load multiple images at once
var imageKeys = new[] { "image1", "image2", "image3" };
var loadedImages = await CacheDatabase.LocalMachine
.LoadImages(imageKeys, desiredWidth: 200, desiredHeight: 200)
.ToList();
foreach (var kvp in loadedImages)
{
Console.WriteLine($"Loaded {kvp.Key}: {kvp.Value.Width}x{kvp.Value.Height}");
}
// Preload images from URLs (background caching)
var urls = new[]
{
"https://example.com/image1.jpg",
"https://example.com/image2.jpg",
"https://example.com/image3.jpg"
};
await CacheDatabase.LocalMachine.PreloadImagesFromUrls(urls,
DateTimeOffset.Now.AddDays(1));
// Load image with automatic fallback
var defaultImageBytes = File.ReadAllBytes("default-avatar.png");
var userAvatar = await CacheDatabase.UserAccount
.LoadImageWithFallback("user_avatar", defaultImageBytes, 100, 100);
// Load from URL with fallback
var profileImage = await CacheDatabase.LocalMachine
.LoadImageFromUrlWithFallback("https://example.com/profile.jpg",
defaultImageBytes,
desiredWidth: 200,
desiredHeight: 200);
// Create and cache thumbnail from existing image
await CacheDatabase.LocalMachine.CreateAndCacheThumbnail(
sourceKey: "original_photo",
thumbnailKey: "photo_thumb",
thumbnailWidth: 150,
thumbnailHeight: 150,
absoluteExpiration: DateTimeOffset.Now.AddDays(30));
// Load the cached thumbnail
var thumbnail = await CacheDatabase.LocalMachine.LoadImage("photo_thumb");
// Get image dimensions without fully loading
var imageSize = await CacheDatabase.LocalMachine.GetImageSize("large_image");
Console.WriteLine($"Image size: {imageSize.Width}x{imageSize.Height}");
Console.WriteLine($"Aspect ratio: {imageSize.AspectRatio:F2}");
// Use size info for layout decisions
if (imageSize.AspectRatio > 1.5)
{
// Wide image
SetWideImageLayout();
}
else
{
// Square or tall image
SetNormalImageLayout();
}
// Clear images matching a pattern
await CacheDatabase.LocalMachine.ClearImageCache(key => key.StartsWith("temp_"));
// Clear all user avatars
await CacheDatabase.UserAccount.ClearImageCache(key => key.Contains("avatar"));
// Clear expired images
await CacheDatabase.LocalMachine.ClearImageCache(key =>
key.StartsWith("cache_") && IsExpired(key));
public class PhotoGalleryService
{
private readonly IBlobCache _imageCache;
private readonly IBlobCache _thumbnailCache;
public PhotoGalleryService()
{
// Initialize Akavache with drawing support
AppBuilder.CreateSplatBuilder().WithAkavacheCacheDatabase<SystemJsonSerializer>(builder =>
builder.WithApplicationName("PhotoGallery")
.WithSqliteProvider()
.WithSqliteDefaults());
_imageCache = CacheDatabase.LocalMachine;
_thumbnailCache = CacheDatabase.UserAccount;
}
public async Task<IBitmap> LoadPhotoAsync(string photoId, bool generateThumbnail = false)
{
try
{
// Try to load from cache first
var photo = await _imageCache.LoadImage($"photo_{photoId}");
// Generate thumbnail if requested and not exists
if (generateThumbnail)
{
await _thumbnailCache.CreateAndCacheThumbnail(
$"photo_{photoId}",
$"thumb_{photoId}",
200, 200,
DateTimeOffset.Now.AddMonths(1));
}
return photo;
}
catch (KeyNotFoundException)
{
// Load from remote URL if not cached
var photoUrl = $"https://api.photos.com/images/{photoId}";
return await _imageCache.LoadImageFromUrl($"photo_{photoId}", photoUrl,
absoluteExpiration: DateTimeOffset.Now.AddDays(7));
}
}
public async Task<IBitmap> LoadThumbnailAsync(string photoId)
{
try
{
return await _thumbnailCache.LoadImage($"thumb_{photoId}", 200, 200);
}
catch (KeyNotFoundException)
{
// Generate thumbnail from full image
var fullImage = await LoadPhotoAsync(photoId);
await _thumbnailCache.SaveImage($"thumb_{photoId}", fullImage,
DateTimeOffset.Now.AddMonths(1));
return await _thumbnailCache.LoadImage($"thumb_{photoId}", 200, 200);
}
}
public async Task PreloadGalleryAsync(IEnumerable<string> photoIds)
{
var photoUrls = photoIds.Select(id => $"https://api.photos.com/images/{id}");
await _imageCache.PreloadImagesFromUrls(photoUrls,
DateTimeOffset.Now.AddDays(7));
}
public async Task ClearOldCacheAsync()
{
// Clear images older than 30 days
await _imageCache.ClearImageCache(key =>
key.StartsWith("photo_") && IsOlderThan30Days(key));
// Clear thumbnails older than 60 days
await _thumbnailCache.ClearImageCache(key =>
key.StartsWith("thumb_") && IsOlderThan60Days(key));
}
private static bool IsOlderThan30Days(string key) =>
/* Implementation to check cache age */ false;
private static bool IsOlderThan60Days(string key) =>
/* Implementation to check cache age */ false;
}
Akavache.Settings provides a specialized settings database for installable applications. It creates persistent settings that are stored one level down from the application folder, making application updates less painful as the settings survive reinstalls.
<PackageReference Include="Akavache.Settings" Version="11.0.*" />
using Akavache.Settings;
public class AppSettings : SettingsBase
{
public AppSettings() : base(nameof(AppSettings))
{
}
// Boolean setting with default value
public bool EnableNotifications
{
get => GetOrCreate(true);
set => SetOrCreate(value);
}
// String setting with default value
public string UserName
{
get => GetOrCreate("DefaultUser");
set => SetOrCreate(value);
}
// Numeric settings
public int MaxRetries
{
get => GetOrCreate(3);
set => SetOrCreate(value);
}
public double CacheTimeout
{
get => GetOrCreate(30.0);
set => SetOrCreate(value);
}
// Enum setting
public LogLevel LoggingLevel
{
get => GetOrCreate(LogLevel.Information);
set => SetOrCreate(value);
}
}
public enum LogLevel
{
Debug,
Information,
Warning,
Error
}
using Akavache.Core;
using Akavache.SystemTextJson;
using Akavache.Settings;
// Initialize Akavache with settings support
var appSettings = default(AppSettings);
AppBuilder.CreateSplatBuilder().WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSerializer(new SystemJsonSerializer())
.WithSqliteProvider()
.WithSettingsStore<AppSettings>(settings => appSettings = settings));
// Now use the settings
appSettings.EnableNotifications = false;
appSettings.UserName = "John Doe";
appSettings.MaxRetries = 5;
Console.WriteLine($"User: {appSettings.UserName}");
Console.WriteLine($"Notifications: {appSettings.EnableNotifications}");
By default, settings are stored in a subfolder of your application directory. You can customize this path:
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSettingsCachePath(@"C:\MyApp\Settings") // Custom path
.WithSettingsStore<AppSettings>(settings => appSettings = settings));
You can create multiple settings classes for different categories:
public class UserSettings : SettingsBase
{
public UserSettings() : base(nameof(UserSettings)) { }
public string Theme
{
get => GetOrCreate("Light");
set => SetOrCreate(value);
}
}
public class NetworkSettings : SettingsBase
{
public NetworkSettings() : base(nameof(NetworkSettings)) { }
public int TimeoutSeconds
{
get => GetOrCreate(30);
set => SetOrCreate(value);
}
}
// Initialize multiple settings
var userSettings = default(UserSettings);
var networkSettings = default(NetworkSettings);
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSettingsStore<UserSettings>(settings => userSettings = settings)
.WithSettingsStore<NetworkSettings>(settings => networkSettings = settings));
For sensitive settings, use encrypted storage:
public class SecureSettings : SettingsBase
{
public SecureSettings() : base(nameof(SecureSettings)) { }
public string ApiKey
{
get => GetOrCreate(string.Empty);
set => SetOrCreate(value);
}
public string DatabasePassword
{
get => GetOrCreate(string.Empty);
set => SetOrCreate(value);
}
}
// Initialize with encryption
var secureSettings = default(SecureSettings);
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithEncryptedSqliteProvider()
.WithSecureSettingsStore<SecureSettings>("mySecurePassword",
settings => secureSettings = settings));
// Use encrypted settings
secureSettings.ApiKey = "sk-1234567890abcdef";
secureSettings.DatabasePassword = "super-secret-password";
You can specify custom database names for settings:
var appSettings = default(AppSettings);
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSettingsStore<AppSettings>(
settings => appSettings = settings,
"CustomAppConfig")); // Custom database name
Here's a comprehensive example showing all data types and features:
public class ComprehensiveSettings : SettingsBase
{
public ComprehensiveSettings() : base(nameof(ComprehensiveSettings))
{
}
// Basic types with defaults
public bool BoolSetting
{
get => GetOrCreate(true);
set => SetOrCreate(value);
}
public byte ByteSetting
{
get => GetOrCreate((byte)123);
set => SetOrCreate(value);
}
public short ShortSetting
{
get => GetOrCreate((short)16);
set => SetOrCreate(value);
}
public int IntSetting
{
get => GetOrCreate(42);
set => SetOrCreate(value);
}
public long LongSetting
{
get => GetOrCreate(123456L);
set => SetOrCreate(value);
}
public float FloatSetting
{
get => GetOrCreate(2.5f);
set => SetOrCreate(value);
}
public double DoubleSetting
{
get => GetOrCreate(3.14159);
set => SetOrCreate(value);
}
public string StringSetting
{
get => GetOrCreate("Default Value");
set => SetOrCreate(value);
}
// Nullable types
public string? NullableStringSetting
{
get => GetOrCreate<string?>(null);
set => SetOrCreate(value);
}
// Complex types (automatically serialized)
public List<string> StringListSetting
{
get => GetOrCreate(new List<string> { "Item1", "Item2" });
set => SetOrCreate(value);
}
public Dictionary<string, int> DictionarySetting
{
get => GetOrCreate(new Dictionary<string, int> { ["Key1"] = 1, ["Key2"] = 2 });
set => SetOrCreate(value);
}
// Custom objects
public WindowPosition WindowPosition
{
get => GetOrCreate(new WindowPosition { X = 100, Y = 100, Width = 800, Height = 600 });
set => SetOrCreate(value);
}
}
public class WindowPosition
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
// Usage
var settings = default(ComprehensiveSettings);
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSettingsStore<ComprehensiveSettings>(s => settings = s));
// Use the settings
settings.StringListSetting.Add("Item3");
settings.WindowPosition = new WindowPosition { X = 200, Y = 150, Width = 1024, Height = 768 };
settings.DictionarySetting["NewKey"] = 999;
// In your application shutdown code
public async Task OnApplicationExit()
{
var builder = CacheDatabase.Builder;
// Dispose settings stores to ensure data is flushed
await builder.DisposeSettingsStore<AppSettings>();
await builder.DisposeSettingsStore<UserSettings>();
// Regular Akavache shutdown
await CacheDatabase.Shutdown();
}
// Delete a specific settings store
var builder = CacheDatabase.Builder;
await builder.DeleteSettingsStore<AppSettings>();
// Settings will be recreated with default values on next access
var builder = CacheDatabase.Builder;
var existingSettings = builder.GetSettingsStore<AppSettings>();
if (existingSettings != null)
{
Console.WriteLine("Settings already exist");
}
else
{
Console.WriteLine("First run - settings will be created with defaults");
}
// In MauiProgram.cs
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
// Initialize Akavache early
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(cacheBuilder =>
cacheBuilder.WithApplicationName("MyMauiApp")
.WithSqliteProvider()
.WithForceDateTimeKind(DateTimeKind.Utc)
.WithSqliteDefaults());
return builder.Build();
}
}
// In App.xaml.cs
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
ConfigureAkavache();
base.OnStartup(e);
}
protected override void OnExit(ExitEventArgs e)
{
// Important: Shutdown Akavache properly
CacheDatabase.Shutdown().Wait();
base.OnExit(e);
}
private static void ConfigureAkavache()
{
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyWpfApp")
.WithSqliteProvider()
.WithForceDateTimeKind(DateTimeKind.Utc)
.WithSqliteDefaults());
}
}
// In AppDelegate.cs or SceneDelegate.cs
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyiOSApp")
.WithSqliteProvider()
.WithSqliteDefaults());
return base.FinishedLaunching(application, launchOptions);
}
// In MainActivity.cs or Application class
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyAndroidApp")
.WithSqliteProvider()
.WithSqliteDefaults());
}
// In App.xaml.cs
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyUwpApp")
.WithSqliteProvider()
.WithSqliteDefaults());
// Rest of initialization...
}
Important for UWP: Mark your application as x86 or ARM, not Any CPU.
Performance comparison of different serializers (operations per second):
| Operation | System.Text.Json | Newtonsoft.Json | BSON |
|---|---|---|---|
| Serialize small object | 50,000 | 25,000 | 20,000 |
| Deserialize small object | 45,000 | 22,000 | 18,000 |
| Serialize large object | 5,000 | 2,500 | 2,000 |
| Deserialize large object | 4,500 | 2,200 | 1,800 |
For comprehensive performance analysis and V10 vs V11 comparison:
// 1. Use System.Text.Json for best performance
.WithSerializer<SystemJsonSerializer>();
// 2. Use batch operations for multiple items
await CacheDatabase.UserAccount.InsertObjects(manyItems);
// 3. Set appropriate expiration times
await CacheDatabase.LocalMachine.InsertObject("temp", data, 30.Minutes().FromNow());
// 4. Use InMemory cache for frequently accessed data
await CacheDatabase.InMemory.InsertObject("hot_data", frequentData);
// 5. Avoid storing very large objects
// Instead, break them into smaller chunks or use compression
// 6. Use specific types instead of object when possible
await CacheDatabase.UserAccount.GetObject<SpecificType>("key"); // Good
await CacheDatabase.UserAccount.Get("key", typeof(SpecificType)); // Slower
// โ
Do: Initialize once at app startup
public class App
{
static App()
{
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(builder =>
builder.WithApplicationName("MyApp")
.WithSqliteProvider()
.WithSqliteDefaults());
}
}
// โ Don't: Initialize multiple times
// โ
Do: Use consistent, descriptive key naming
await CacheDatabase.UserAccount.InsertObject("user_profile_123", userProfile);
await CacheDatabase.LocalMachine.InsertObject("api_cache_weather_seattle", weatherData);
// โ
Do: Use constants for keys
public static class CacheKeys
{
public const string UserProfile = "user_profile";
public const string WeatherData = "weather_data";
}
// โ Don't: Use random or inconsistent keys
await CacheDatabase.UserAccount.InsertObject("xyz123", someData);
// โ
Do: Handle KeyNotFoundException appropriately
try
{
var data = await CacheDatabase.UserAccount.GetObject<MyData>("key");
}
catch (KeyNotFoundException)
{
// Provide fallback or default behavior
var defaultData = new MyData();
}
// โ
Do: Use GetOrFetchObject for remote data
var data = await CacheDatabase.LocalMachine.GetOrFetchObject("api_data",
() => httpClient.GetFromJsonAsync<ApiData>("https://api.example.com/data"));
// โ
Do: Use appropriate cache types
await CacheDatabase.UserAccount.InsertObject("user_settings", settings); // Persistent user data
await CacheDatabase.LocalMachine.InsertObject("api_cache", apiData); // Cacheable data
await CacheDatabase.Secure.InsertObject("api_key", apiKey); // Sensitive data
await CacheDatabase.InMemory.InsertObject("session_data", sessionData); // Temporary data
// โ
Do: Set appropriate expiration times
await CacheDatabase.LocalMachine.InsertObject("api_data", data, 1.Hours().FromNow());
await CacheDatabase.LocalMachine.InsertObject("image_cache", imageBytes, 1.Days().FromNow());
// โ
Do: Don't expire user settings (unless necessary)
await CacheDatabase.UserAccount.InsertObject("user_preferences", prefs); // No expiration
// โ
Do: Always shutdown Akavache properly
public override void OnExit(ExitEventArgs e)
{
CacheDatabase.Shutdown().Wait();
base.OnExit(e);
}
// For MAUI/Xamarin apps
protected override void OnSleep()
{
CacheDatabase.Shutdown().Wait();
base.OnSleep();
}
// โ
Do: Use in-memory cache for unit tests
[SetUp]
public void Setup()
{
CacheDatabase.Initialize<SystemJsonSerializer>(builder =>
builder.WithApplicationName("TestApp")
.WithInMemoryDefaults());
}
[TearDown]
public void TearDown()
{
CacheDatabase.Shutdown().Wait();
}
// Fix: Register a suitable serializer during initialization
CacheDatabase.Initialize<SystemJsonSerializer>(/* ... */);
AppBuilder.CreateSplatBuilder()
.WithAkavache<SystemJsonSerializer>(/* ... */);
AppBuilder.CreateSplatBuilder()
.WithAkavacheCacheDatabase<SystemJsonSerializer>(/* ... */);
// Fix: Call Initialize before using cache
CacheDatabase.Initialize<SystemJsonSerializer>(builder => builder.WithApplicationName("MyApp").WithInMemoryDefaults());
var data = await CacheDatabase.UserAccount.GetObject<MyData>("key");
// Fix: Use cross-compatible serializer or migration
CacheDatabase.Initialize<NewtonsoftBsonSerializer>(/* ... */); // Most compatible
// Fix: Ensure SQLitePCL.raw bundle is installed
// Add to your project:
<ItemGroup>
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.11" />
// If using Encrypted SQLite, also add:
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlcipher" Version="2.1.11" />
</ItemGroup>
You will need to preserve certain types to prevent the linker from stripping them out in release builds.
// Add to your .csproj file:
<ItemGroup>
<TrimmerRootAssembly Include="SQLitePCLRaw.lib.e_sqlite3.## YOUR-PLATFORM ##" RootMode="All" />
</ItemGroup>
### Platform-Specific Issues
#### iOS Linker Issues
```csharp
// Add LinkerPreserve.cs to your iOS project:
public static class LinkerPreserve
{
static LinkerPreserve()
{
var sqliteBlobCachetName = typeof(SqliteBlobCache).FullName;
var encryptedSqliteBlobCacheName = typeof(EncryptedSqliteBlobCache).FullName;
}
}
Ensure your UWP project targets a specific platform (x86, x64, ARM) rather than "Any CPU".
Akavache is licensed under the .
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 5 NuGet packages that depend on Akavache:
| Package | Downloads |
|---|---|
|
Akavache.Sqlite3
Package Description |
|
|
SheshaMobile.Core
Common application functionality and features to be shared across the framework |
|
|
SheshaMobile.Modules
The modules module contains common functionality shared across multiple modules |
|
|
SheshaMobile.Modules.UserProfile
A module for building apps with user functionality |
|
|
SheshaMobile.Modules.Facilities
The facilities module contains common functionality for browsing and viewing facilities |
Showing the top 15 popular GitHub repositories that depend on Akavache:
| Repository | Stars |
|---|---|
|
CodeHubApp/CodeHub
CodeHub is an iOS application written using Xamarin
|
|
|
MoocDownloader/MoocDownloader
An MOOC downloader implemented by .NET. ไธๆ็ฑ .NET ๅฎ็ฐ็ MOOC ไธ่ฝฝๅจ.
|
|
|
reactiveui/Camelotia
Cross-platform sample .NET GUI for cloud file management.
|
|
|
reactiveui/ReactiveUI.Samples
This repository contains ReactiveUI samples.
|
|
|
mmbot/mmbot
A C# port of Hubot
|
|
|
flagbug/Espera
Espera is a media player that plays your music, YouTube videos, SoundCloud songs and has a special "party mode".
|
|
|
Ombrelin/plex-rich-presence
A desktop app to enable discord rich presence for your Plex Media Server Activity
|
|
|
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!
|
|
|
Titlehhhh/Minecraft-Holy-Client
A high-performance platform for running Minecraft stress-test bots written in C#.
|
|
|
Respawnsive/Apizr
Refit based web api client management, but resilient (retry, connectivity, cache, auth, log, priority, etc...)
|
|
|
kentcb/WorkoutWotch
Repository for my video series on building an iOS app in .NET.
|
|
|
BlossomiShymae/Needlework.Net
๐ชก A .NET helper development tool for the LCU and Game Client!
|
|
|
thedillonb/RepoStumble
A mobile application for viewing GitHub repositories in a fashion similar to StumbleUpon
|
|
|
sthewissen/MVP
Unofficial app to help MVPs manage their community activities
|
| Version | Downloads | Last Updated |
|---|---|---|
| 12.1.1 | 4,673 | 6/3/2026 |
| 11.5.1 | 52,606 | 11/30/2025 |
| 11.4.1 | 24,760 | 9/9/2025 |
| 11.3.3 | 993 | 9/6/2025 |
| 11.1.1 | 1,676 | 9/2/2025 |
| 11.0.1 | 1,309 | 8/24/2025 |
| 10.2.41 | 27,056 | 3/16/2025 |
| 10.1.6 | 175,344 | 9/16/2024 |
| 10.0.1 | 103,272 | 5/1/2024 |
| 9.1.20 | 324,241 | 6/29/2023 |
| 9.1.7 | 70,212 | 2/1/2023 |
| 9.0.1 | 262,359 | 6/25/2022 |
| 8.1.1 | 218,919 | 12/12/2021 |
| 7.3.47 | 15,980 | 11/26/2021 |