.NET MAUI のデータストア
.NET MAUIのデータストアはどうなってるのかな?
とういうことで、勉強していきます。
開発環境
- Win11
- VS2022 Preview Version 17.3.0 Preview 2.0
環境構築&プロジェクト作成の流れはこちらの記事でどうぞ。
サンプルソース
.NET MAUIの新規プロジェクト作成時のサンプルソースです。
画面上のボタンをクリックするとその回数をお知らせします。
悲しいことに、クリック回数を永続化しません。
2,147,483,647回クリックしても、アプリケーション閉じたら1からやり直しです。しないけど。
MainPage.cs
namespace MauiDatabaseDemo;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
}
}
データを保存する方法
クリック回数を是が非でも永続したいんじゃっ!てことで、.NET MAUI でデータを永続する方法調べました。
- Preferences
- FileSystem
- Database
- Remote (この記事ではあつかいません。)
- SecureStorage 2022/07/19追加
1. Preferences
key=value形式で値を永続することができます。
値としてサポートされるのは
- Boolean
- Double
- Int32
- Single
- Int64
- String
- DateTime
です。
複雑なデータには向きません。Jsonにシリアライズして・・・とか考えないように。
ソース
では、クリック回数を永続してみましょう!
namespace MauiDatabaseDemo;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
// ADD START
count = Preferences.Get("count", 0); // 第二引数はデフォルト値
// ADD END
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
// ADD START
Preferences.Default.Set("count", count);
// ADD END
}
}
どこに保存されるか?
- iOS : NSUserDefaults
- Android : SharedPreferences
- Windows : ApplicationDataContainer
C:/Users/UserId/AppData/Local/Packages/ApplicationIdGuid_xxxxxxxxxxxxx/Settings/settings.dat ぽい。
2. FileSystem
アプリケーション専用のディレクトリであれば、権限を気にせずアクセス可能です。
※iOSな人は、うんたらかんたら書いてあったので、参考資料を見れ。
// アプリケーションデータはこっち
string mainDir = FileSystem.Current.AppDataDirectory;
// キャッシュデータはこっち
string cacheDir = FileSystem.Current.CacheDirectory;
ソース
では、クリック回数を永続してみましょう!
よい子は、Serializerとか使いましょう()
namespace MauiDatabaseDemo;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
// ADD START
string path = Path.Combine(FileSystem.Current.AppDataDirectory, "count.txt");
if (File.Exists(path))
{
using (var s = new StreamReader(File.OpenRead(path)))
{
count = int.Parse(s.ReadLine());
}
}
else
{
count = 0;
}
// ADD END
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
// ADD START
using (var s = new StreamWriter(File.OpenWrite(path)))
{
s.Write(count.ToString());
}
// ADD END
}
}
どこに保存されるか?
- Windows :
C:/Users/UserId/AppData/Local/Packages/ApplicationIdGuid_xxxxxxxxxxxxx/LocalState/count.txt
3. Database
「この要件で、DBなしの設計なんてムリポぉ!」な時がくるかもしれないし。
参考資料 が sqlite-net-pcl 押しなので、使ってみましょう。
EF.Coreダメなん? (未調査)
SQLite専用だけど、EF.Coreと操作感は似てました。
個人的にtransactionをusingできないのが違和感。
ソース
では、クリック回数を永続してみましょう!
無駄にクリックした日時も記録しちゃいますよ!無駄に!
using SQLite;
namespace MauiDatabaseDemo;
public partial class MainPage : ContentPage
{
int count = 0;
private SQLiteConnection conn;
public MainPage()
{
InitializeComponent();
// ADD START
string path = Path.Combine(FileSystem.Current.AppDataDirectory, "count.db3");
conn = new SQLiteConnection(path);
// conn = new SQLiteAsyncConnection(path) 非同期版
conn.CreateTable(typeof(ClickTime));
// ADD END
}
private void OnCounterClicked(object sender, EventArgs e)
{
// ADD START
count = conn.Table<ClickTime>().Count();
// ADD END
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
// ADD START
try
{
conn.BeginTransaction();
conn.Insert(new ClickTime() { Time = DateTime.Now });
conn.Commit();
}
catch
{
conn.Rollback();
}
// ADD END
}
}
[Table(nameof(ClickTime))]
public class ClickTime
{
[PrimaryKey]
[Column(nameof(Time))]
public DateTime Time { get; set; }
}
どこに保存されるか?
当然ながらFileSystemと同じ。
4. SecureStorage 2022/07/19追加
セキュリティで保護されたストレージだそうです。
認証キーとか、抜かれて困るものがあれば。
string型しか対応していません。
ソース
// 設定
await SecureStorage.Default.SetAsync(string key, string value);
// 取得
await SecureStorage.Default.GetAsync(string key);
// 削除
await SecureStorage.Default.Remove(string key);
// すべて消す
SecureStorage.Default.RemoveAll();
参考資料
MS様に感謝☆