.NET MAUI Local Storage with Preferences, SecureStorage, and SQLite
Developing mobile applications often requires persisting user data across sessions. In .NET Multi-platform App UI (.NET MAUI), developers have access to various local storage options to manage this data efficiently. This article explores how to use Preferences, SecureStorage, and SQLite to handle different types of user data within .NET MAUI applications.
Preferences
.NET MAUI Preferences offer a simple mechanism for storing key-value pairs. These key-value pairs are typically used for lightweight settings, such as user preferences or small pieces of application state. Preferences are stored in a platform-specific storage system, such as app settings in Windows, UserDefaults in iOS, and SharedPreferences in Android.
Key Features:
- Synchronous API: Preferences provide a straightforward, synchronous API for setting and getting data, making it easy to integrate into application flow.
- Platform-Specific Storage: Each platform has its dedicated storage mechanism for Preferences, optimized for performance and security.
- Limited Data Types: Preferences can only store basic data types such as integers, strings, floats, booleans, and doubles.
Usage Example:
using Microsoft.Maui.Storage;
Preferences.Set("username", "JohnDoe");
string username = Preferences.Get("username", string.Empty);
Preferences.Set("isLoggedIn", true);
bool isLoggedIn = Preferences.Get("isLoggedIn", false);
Important Considerations:
- Use Cases: Preferences are best suited for simple data and settings, such as user preferences and small pieces of state.
- Security: Because Preferences is not secure, avoid storing sensitive data like passwords or private keys here.
SecureStorage
SecureStorage is designed for storing small pieces of secure data like passwords, API keys, and OAuth tokens. Unlike Preferences, SecureStorage uses encryption to protect the stored data, enhancing security.
Key Features:
- Encryption: Data is encrypted before being stored, providing an added layer of security compared to Preferences.
- Synchronous API: Similar to Preferences, SecureStorage uses a synchronous API, though it is advisable to use it sparingly due to potential UI thread blocking.
- Platform-Specific: Each platform implements SecureStorage differently, using hardware-based encryption where possible.
Usage Example:
using Microsoft.Maui.Storage;
await SecureStorage.SetAsync("api_key", "some_secure_api_key");
string apiKey = await SecureStorage.GetAsync("api_key");
Important Considerations:
- Size Limitations: SecureStorage is designed for small data sizes. Storing large amounts of data could slow down your application or fail.
- User Consent: Always obtain user consent before accessing or storing sensitive data.
SQLite
For more complex data storage needs, including relational data or extensive datasets, SQLite is a robust and efficient choice. SQLite is a compact, serverless, self-contained, fully transactional SQL database engine. .NET MAUI applications can leverage SQLite to persist structured data, allowing for complex queries and relationships.
Key Features:
- SQLite.NET: A popular ORM (Object-Relational Mapper) that simplifies working with SQLite databases in .NET MAUI applications.
- Cross-Platform: SQLite is supported across all platforms, ensuring consistent behavior and functionality.
- Relational Data: SQLite supports tables, indexes, and relationships, making it a great choice for structured data.
Usage Example: First, install the SQLite NuGet package:
dotnet add package sqlite-net-pcl
Then, use SQLite in your application:
using SQLite;
using System.Collections.Generic;
using System.IO;
// Define a data model
public class User
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
// Database operations
public class Database
{
private SQLiteAsyncConnection _database;
public Database(string dbPath)
{
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<User>().Wait();
}
public Task<List<User>> GetUsersAsync()
{
return _database.Table<User>().ToListAsync();
}
public Task<int> AddUserAsync(User user)
{
return _database.InsertAsync(user);
}
}
// Usage
var dbPath = Path.Combine(FileSystem.AppDataDirectory, "mauidb.db3");
Database database = new Database(dbPath);
User newUser = new User { Name = "Alice", Email = "alice@example.com" };
await database.AddUserAsync(newUser);
List<User> users = await database.GetUsersAsync();
Important Considerations:
- Performance: SQLite is generally efficient for mobile applications, but performance can degrade with very large datasets or poorly optimized queries.
- Data Integrity: Use transactions and proper schema design to ensure data integrity and consistency.
- Backup: Implement mechanisms for backing up SQLite databases to prevent data loss.
Conclusion
.NET MAUI provides a comprehensive suite of tools for managing local storage in mobile applications. Whether you're dealing with small application settings or extensive relational data, there's a storage solution for every use case. Preferences offer simplicity for lightweight data, SecureStorage ensures security for sensitive information, and SQLite provides robust capabilities for structured data management. By leveraging these tools effectively, developers can enhance the functionality and security of their .NET MAUI applications.
Examples, Set Route and Run the Application, and Data Flow Step by Step for Beginners: .NET MAUI Local Storage with Preferences, SecureStorage, and SQLite
If you're diving into .NET MAUI and want to understand how to handle data storage using Preferences, SecureStorage, and SQLite, then you've come to the right place. Here, we'll walk through setting up a simple .NET MAUI application to explore these storage mechanisms step by step. This guide will be beginner-friendly and broken down into easy-to-follow stages.
Step 1: Setting Up Your Project
Install Visual Studio: Ensure you have the latest version of Visual Studio installed, with the .NET MAUI workload added. You can find .NET MAUI templates in the latest releases.
Create a New Project:
- Open Visual Studio.
- Click on Create a New Project.
- Search for .NET MAUI App and select it.
- Choose your project's name and location.
- Click Create.
Step 2: Setting Navigation Routes
.NET MAUI uses Shell for routing and navigation. Before diving into local storage, we'll set up a basic navigation structure to understand data flow.
Open App.xaml.cs:
public partial class App : MauiApplication { public override MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); builder.Services.AddSingleton<MainPage>(); builder.Services.AddTransient<PreferencesPage>(); builder.Services.AddTransient<SecureStoragePage>(); builder.Services.AddTransient<SQLitePage>(); return builder.Build(); } }
Define Routes in AppShell.xaml:
<?xml version="1.0" encoding="UTF-8" ?> <Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiLocalStorage.AppShell"> <TabBar Route="MainPage"> <Tab Title="Preferences" Icon="preferences.png"> <ShellContent ContentTemplate="{DataTemplate local:PreferencesPage}" Route="PreferencesPage" /> </Tab> <Tab Title="SecureStorage" Icon="securestorage.png"> <ShellContent ContentTemplate="{DataTemplate local:SecureStoragePage}" Route="SecureStoragePage" /> </Tab> <Tab Title="SQLite" Icon="sqlite.png"> <ShellContent ContentTemplate="{DataTemplate local:SQLitePage}" Route="SQLitePage" /> </Shell> </TabBar> </Shell>
Step 3: Running the Application
- Build and Run:
- Select your target platform (e.g., Windows, Android, iOS).
- Click the Run button or press
F5
. - You should see your application launch with three tabs: Preferences, SecureStorage, and SQLite.
Step 4: Data Flow and Examples
Let's look at how to manage data using Preferences, SecureStorage, and SQLite.
a. Preferences
Preferences is used for storing simple, non-sensitive data.
Install Packages:
- Go to the NuGet Package Manager and ensure
Microsoft.Maui.Preferences
is installed.
- Go to the NuGet Package Manager and ensure
PreferencesPage.xaml:
<?xml version="1.0" encoding="UTF-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiLocalStorage.PreferencesPage" Title="Preferences"> <StackLayout> <Entry x:Name="EntryPreference" Placeholder="Enter preference value" /> <Button Text="Save Preference" Clicked="SavePreference_Clicked" /> <Button Text="Load Preference" Clicked="LoadPreference_Clicked" /> <Label x:Name="LabelPreference" Margin="5" /> </StackLayout> </ContentPage>
PreferencesPage.xaml.cs:
using Microsoft.Maui.Storage; namespace MauiLocalStorage; public partial class PreferencesPage : ContentPage { public PreferencesPage() { InitializeComponent(); } private void SavePreference_Clicked(object sender, EventArgs e) { Preferences.Set("my_key", EntryPreference.Text); LabelPreference.Text = "Preference saved!"; } private void LoadPreference_Clicked(object sender, EventArgs e) { EntryPreference.Text = Preferences.Get("my_key", "No preference found"); LabelPreference.Text = $"Preference loaded: {EntryPreference.Text}"; } }
b. SecureStorage
SecureStorage is ideal for sensitive data like API keys or authentication tokens.
Install Packages:
- Ensure
Microsoft.Maui.Storage
is installed.
- Ensure
SecureStoragePage.xaml:
<?xml version="1.0" encoding="UTF-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiLocalStorage.SecureStoragePage" Title="SecureStorage"> <StackLayout> <Entry x:Name="EntrySecure" Placeholder="Enter secure value" /> <Button Text="Save Secure Data" Clicked="SaveSecure_Clicked" /> <Button Text="Load Secure Data" Clicked="LoadSecure_Clicked" /> <Label x:Name="LabelSecure" Margin="5" /> </StackLayout> </ContentPage>
SecureStoragePage.xaml.cs:
using Microsoft.Maui.Storage; namespace MauiLocalStorage; public partial class SecureStoragePage : ContentPage { public SecureStoragePage() { InitializeComponent(); } private async void SaveSecure_Clicked(object sender, EventArgs e) { await SecureStorage.SetAsync("secure_key", EntrySecure.Text); LabelSecure.Text = "Secure data saved!"; } private async void LoadSecure_Clicked(object sender, EventArgs e) { EntrySecure.Text = await SecureStorage.GetAsync("secure_key"); LabelSecure.Text = $"Secure data loaded: {EntrySecure.Text}"; } }
c. SQLite
SQLite is used for complex data storage with relational database capabilities.
Install Packages:
- Go to the NuGet Package Manager and install
Microsoft.EntityFrameworkCore.Sqlite
andSQLitePCLRaw.bundle_e_sqlite3
.
- Go to the NuGet Package Manager and install
Define a Data Model:
public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } }
Create a Database Context:
using Microsoft.EntityFrameworkCore; public class AppDbContext : DbContext { public DbSet<User> Users { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite($"Filename={Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "test.db")}"); } }
SQLitePage.xaml:
<?xml version="1.0" encoding="UTF-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiLocalStorage.SQLitePage" Title="SQLite"> <StackLayout> <Entry x:Name="EntryName" Placeholder="Name" /> <Entry x:Name="EntryEmail" Placeholder="Email" /> <Button Text="Add User" Clicked="AddUser_Clicked" /> <Button Text="Load Users" Clicked="LoadUsers_Clicked" /> <ListView x:Name="ListViewUsers" /> </StackLayout> </ContentPage>
SQLitePage.xaml.cs:
using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Threading.Tasks; using System.Linq; namespace MauiLocalStorage; public partial class SQLitePage : ContentPage { public SQLitePage() { InitializeComponent(); using (var db = new AppDbContext()) { db.Database.EnsureCreated(); } } private async void AddUser_Clicked(object sender, EventArgs e) { var user = new User() { Name = EntryName.Text, Email = EntryEmail.Text }; EntryName.Text = ""; EntryEmail.Text = ""; using (var db = new AppDbContext()) { db.Users.Add(user); await db.SaveChangesAsync(); } } private async void LoadUsers_Clicked(object sender, EventArgs e) { using (var db = new AppDbContext()) { var users = await db.Users.ToListAsync(); ListViewUsers.ItemsSource = users.Select(u => $"{u.Name}, {u.Email}"); } } }
Step 5: Summary and Tips
- Preferences is great for simple settings like themes or UI preferences.
- SecureStorage should be used for sensitive information that needs to be secured.
- SQLite is perfect for applications requiring local database storage with more complex data structures.
By following the above steps, you'll have a basic .NET MAUI application demonstrating how to use different local storage options. This foundation will help you build more complex applications and confidently manage data storage. Happy coding!
Top 10 Questions and Answers on .NET MAUI Local Storage with Preferences, SecureStorage, and SQLite
When developing applications using .NET Multi-platform App UI (MAUI), managing local data storage efficiently becomes a crucial aspect of the application lifecycle. .NET MAUI provides several mechanisms for storing data locally: Preferences, SecureStorage, and SQLite. This guide answers the top 10 questions developers often encounter when working with these storage options.
1. What is Preferences in .NET MAUI, and when should you use it?
Preferences in .NET MAUI is a simple key-value storage system designed for storing small amounts of data. It is useful for settings and preferences like user interface preferences, app settings, and lightweight data that do not require complex data structures or security. For instance, you can use Preferences to remember the position of a toggle switch or store language settings.
Example:
// Saving data to preferences
Preferences.Set("FontSize", 12, "MyAppPreferences");
// Retrieving data from preferences
var fontSize = Preferences.Get("FontSize", 12, "MyAppPreferences");
2. How does SecureStorage differ from Preferences in .NET MAUI?
While Preferences is a general-purpose key-value store for small data, SecureStorage is specifically designed for storing sensitive information securely, such as passwords and API keys. SecureStorage encrypts the data stored and is accessible only by your application.
Example:
// Saving data to SecureStorage
await SecureStorage.SetAsync("ApiToken", "secure-api-token");
// Retrieving data from SecureStorage
var apiToken = await SecureStorage.GetAsync("ApiToken");
Note: SecureStorage is not available on all platforms by default. Ensure you have platform-specific implementations and dependencies set up.
3. What are the benefits of using SQLite in .NET MAUI over other storage options?
SQLite is a relational database engine that allows you to store structured data like tables, rows, and columns. It provides robust data querying capabilities, supports transactions, and is a standard way of handling complex data relationships and large datasets efficiently. Use SQLite when you need a robust, secure, and scalable local database solution.
Example:
// Creating a new SQLite database and table
var dbPath = Path.Combine(FileSystem.Current.AppDataDirectory, "database.db");
using var db = new SQLiteConnection(dbPath);
db.CreateTable<User>();
// Saving data to SQLite
var user = new User { Id = 1, Name = "John Doe", Email = "john.doe@example.com" };
db.Insert(user);
// Querying data from SQLite
var allUsers = db.Table<User>().ToList();
4. Can Preferences and SecureStorage be used together in the same application?
Yes, Preferences and SecureStorage can coexist in the same .NET MAUI application. Use Preferences for general settings and SecureStorage for sensitive data. For example, you might store a user's theme preference in Preferences but securely store their authentication token in SecureStorage.
Example:
// Using both Preferences and SecureStorage together
Preferences.Set("Theme", "Dark", "MyAppPreferences");
await SecureStorage.SetAsync("UserToken", "user-auth-token");
var theme = Preferences.Get("Theme", "Light", "MyAppPreferences");
var userToken = await SecureStorage.GetAsync("UserToken");
5. How can you handle data migrations when using SQLite in .NET MAUI?
When using SQLite in .NET MAUI, data schema changes during updates might require migrations. You can use libraries like Microsoft.EntityFrameworkCore (EF Core) or SQLite-net Extensions to manage schema migrations.
Example with SQLite-net Extensions:
// Handling schema migrations using SQLite-net Extensions
var dbPath = Path.Combine(FileSystem.Current.AppDataDirectory, "database.db");
using var db = new SQLiteConnection(dbPath);
db.CreateTable<User>(); // Create table if not exists
// Schema version check and migration
var currentVersion = 1;
var version = db.ExecuteScalar<int>("PRAGMA user_version");
if (version < currentVersion)
{
// Perform migration
db.Execute("ALTER TABLE User ADD COLUMN Phone TEXT");
db.Execute("PRAGMA user_version = 1");
}
6. What is the difference between SetAsync
and Set
methods in SecureStorage and Preferences?
The Set
method in Preferences is synchronous, meaning it blocks the calling thread until the operation is complete. In contrast, SecureStorage provides an SetAsync
method, which is asynchronous and does not block the calling thread. You should use SetAsync
to avoid blocking the UI thread, especially when dealing with sensitive data.
Example:
// Synchronous Preferences Set method
Preferences.Set("Username", "johndoe", "MyAppPreferences");
// Asynchronous SecureStorage SetAsync method
await SecureStorage.SetAsync("SessionId", "session-12345");
7. How can you clear all stored data from Preferences and SecureStorage?
To clear all stored data from Preferences and SecureStorage, you can use the Clear
method for Preferences and RemoveAsync
for SecureStorage.
Example:
// Clear all data from Preferences
Preferences.Clear("MyAppPreferences");
// Remove a specific key from SecureStorage
await SecureStorage.RemoveAllAsync(); // or SecureStorage.RemoveAsync("SessionId");
8. What are the security considerations when using SecureStorage in .NET MAUI?
When using SecureStorage, consider the following security best practices:
- Never store sensitive data like passwords or tokens directly in Preferences.
- Use SecureStorage for sensitive data.
- Ensure platform-specific implementations are correctly set up.
- Regularly update and secure your application.
Note: SecureStorage is not perfect and can be compromised under certain circumstances. Always follow the latest security practices and guidelines.
9. How can you implement a simple caching mechanism using Preferences in .NET MAUI?
You can implement a caching mechanism using Preferences by storing frequently accessed data, like API responses or configuration settings. This helps reduce network calls and improves application performance.
Example:
// Implementing a simple caching mechanism using Preferences
var cachedData = Preferences.Get("CachedData", null, "MyAppPreferences");
if (cachedData != null)
{
// Use cached data
var data = JsonConvert.DeserializeObject<List<User>>(cachedData);
}
else
{
// Fetch data from API and cache it
var data = FetchDataFromApiAsync().Result;
Preferences.Set("CachedData", JsonConvert.SerializeObject(data), "MyAppPreferences");
}
10. What are the best practices for using SQLite in .NET MAUI applications?
Here are some best practices for using SQLite in .NET MAUI applications:
- Use migrations for schema changes.
- Optimize queries for performance.
- Index columns for faster lookups.
- Use connections wisely to avoid memory leaks.
- Backup data if necessary.
Example:
// Best practices in using SQLite in .NET MAUI
var dbPath = Path.Combine(FileSystem.Current.AppDataDirectory, "database.db");
using var db = new SQLiteConnection(dbPath);
db.CreateTable<User>();
// Create an index on Name column for faster searches
db.Execute("CREATE INDEX IF NOT EXISTS user_name_index ON User(Name)");
Conclusion
Understanding how to use Preferences, SecureStorage, and SQLite in .NET MAUI is essential for building robust, secure, and efficient applications. By following the best practices and guidelines provided, you can effectively manage local data storage in your .NET MAUI projects.