eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
DocsWrite-once
Speicher
Edit this page
4 min read
Eine Signatur über dem jeweils eigenen nativen Speicher jeder Plattform. Eine Anwendung schreibt überall dasselbe C#, und der Wert landet dort, wo diese Plattform diese Art von Dingen schon aufhebt, sodass ihr Backup, ihre Migration und ihre Deinstallation sich so verhalten, wie ein Nutzer es erwartet, ohne dass das Framework etwas erfindet oder mitliefert.
Seit 0.2.0-preview.10
Es gibt zwei Schnittstellen, und welche Sie nehmen, ist eine Entscheidung, kein Parameter.
IAppStorage
ISecretStore
Web
localStorage
keiner, löst zu null auf
macOS / iOS
NSUserDefaults
Keychain
Android
SharedPreferences
AES/GCM, vom KeyStore gestützt
Beide werden per Konstruktor genommen, wie jede andere Fähigkeit:
1
2
3
4
public sealed class SettingsShell(IAppStorage storage) : StatefulComponent
{
private void Remember(string language) => storage.Set("language", language);
}
JEDES ZIEL Nativ löst der .NET-Container ihn auf; im Browser löst der transpilierte Konstruktor ihn über den Namen der Schnittstelle auf; beim SSR löst er zu einem Speicher auf, der nichts hält und das sagt: Lesevorgänge antworten null, Schreibvorgänge gehen nirgendwohin, denn der Speicher, für den dies steht, liegt auf der Maschine der Besucherin. Eine Seite liest ihren gespeicherten Wert also beim ersten Rendern des Clients, und das serverseitig gerenderte Markup zeigt dasselbe, was ein allererster Besuch zeigt. Siehe Fähigkeiten für das ganze Bild.
Lesen Sie ihn in OnMount, nicht im Konstruktor: Der Reconciler baut in jedem Durchgang frische Instanzen und behält die aufbewahrte, ein Konstruktor, der Speicher liest, liest ihn also erneut für eine Instanz, die dann weggeworfen wird. (Write-once-Komponenten)
Warum Geheimnisse ein anderer Typ sind
Ein Token in localStorage zu legen ist der am häufigsten gemachte Sicherheitsfehler im Web, und eine API, in der Sicherheit ein Argument secure: true ist, ist eine API, in der Sicherheit ein vergessenes Argument weit entfernt ist. Hier kann die Wahl nicht durch Auslassen getroffen werden: Ein Geheimnis braucht einen anderen Dienst, und danach zu fragen ist etwas, das jemand mit Absicht getan hat.
Der Browser hat kein Schließfach, im Web löst ISecretStore also zu null auf, so wie das Framework jede Fähigkeit meldet, die ein Host nicht hat, statt mit einem Speicher zu tun, den jedes Skript auf der Origin lesen kann. Eine Anwendung, die im Web danach greift, muss die Frage beantworten, der sie auswich: das Geheimnis auf dem Server behalten und dem Browser eine Sitzung geben, die er nur ausgeben kann, oder akzeptieren, dass das, was sie speicherte, nie wirklich ein Geheimnis war.
Auf Native ist es das echte Schließfach der Plattform. Apple: ein kSecClassGenericPassword-Element je Schlüssel unter dem Bundle-Identifier der Anwendung, AfterFirstUnlockThisDeviceOnly, sodass eine Hintergrundaktualisierung es lesen kann, während ein seit dem Start nicht entsperrtes Gerät es nicht kann, und nie zu iCloud synchronisiert. Android: ein hardwaregestützter AES-Schlüssel im AndroidKeyStore (das Schlüsselmaterial ist selbst für diesen Prozess unlesbar) mit AES/GCM-Chiffrat in einer Präferenzdatei. Das ist, was EncryptedSharedPreferences von AndroidX tut, direkt geschrieben, weil die Plattform jedes Stück mitliefert und das Framework für etwas, das das Betriebssystem schon bereitstellt, keine Abhängigkeit aufnimmt.
Nur Strings
Jeder Speicher hier ist darunter eine String-Karte. Eine typisierte Oberfläche wären drei Serialisierer, die identisch zu halten sind, und ihre erste Uneinigkeit ist ein Wert, der auf einer Plattform schreibt und auf einer anderen nicht gelesen werden kann. Serialisieren Sie in Ihrer Anwendung, wo das Format Ihres ist.
Speicher ist eine CLIENT-Fähigkeit
Es gibt keine Server-Realisierung. Beim SSR löst der Dienst zu null auf, und Lesevorgänge antworten nichts.
Das zählt mehr, als es klingt. Eine Seite, die ihren Baum nach gespeichertem Zustand verzweigt, rendert auf dem Server das eine und im Browser das andere, und der Reconciler wird den Unterschied getreulich vor der Leserin ausgleichen. Lesen Sie den Speicher in einem Event-Handler oder nach dem Mount, nie während des Bauens.
Darum kann der Speicher allein auch kein Theme ohne Aufblitzen erinnern: Der Server malt zuerst, und localStorage ist nichts, was er sehen kann. Dieses bestimmte Problem will einen Cookie, denn die Anforderung ist nicht "erinnern", sondern "dem Server sagen", und das Framework kümmert sich schon darum, eine Anwendung muss es also nicht. Siehe ServerIntegration.
Fehler antworten, sie werfen nie
•
localStorage ist die DOM-API, die am ehesten wirft statt leise zu scheitern. Safaris privater Modus hat beim Schreiben geworfen, ein Browser am Kontingent wirft, und es überhaupt zu lesen wirft, wenn die Origin Speicher gesperrt hat. Eine Einstellung, die nicht gespeichert wird, darf keine Seite umreißen, ein Schreibvorgang, der nicht stattfinden kann, findet also einfach nicht statt, und ein Lesevorgang, der nicht stattfinden kann, antwortet null.
•
Ein Keychain-Element übersteht nicht jede Wiederherstellung, und ein KeyStore-Schlüssel wird durch einen neuen Sperrbildschirm entwertet. Beides macht jeden Wert darunter dauerhaft unlesbar.
Behandeln Sie ein null beim Lesen also als "frag nochmal" (erneut anmelden, auf die Voreinstellung zurückfallen) und nie als zu meldenden Fehler. Es ist dieselbe Antwort, die ein nie geschriebener Schlüssel gibt, und der Aufrufer behandelt diese schon.
Den eigenen mitbringen
Jede Fähigkeit wird mit TryAdd registriert, Ihren eigenen zu registrieren gewinnt also:
1
builder.Services.AddSingleton<IAppStorage, MyOwnStorage>();
Das ist die Notluke für einen Speicher mit anderer Haltbarkeit, eine verschlüsselte Datei oder ein Test-Double.