AlmacenamientoUna firma sobre el almacén nativo propio de cada plataforma. Una aplicación escribe el mismo C# en todas partes, y el valor aterriza donde esa plataforma ya guarda este tipo de cosas, así que su copia de seguridad, su migración y su desinstalación se comportan como quien la usa espera, sin que el framework invente ni empaquete nada.
Desde 0.2.0-preview.10
Hay dos interfaces, y cuál tomas es una decisión, no un parámetro.
Web
localStorage
ninguno, se resuelve a null
macOS / iOS
NSUserDefaults
Keychain
Android
SharedPreferences
AES/GCM respaldado por KeyStore
Las dos se toman por constructor, como cualquier otra capacidad:
public sealed class SettingsShell(IAppStorage storage) : StatefulComponent
private void Remember(string language) => storage.Set("language", language);
TODOS LOS DESTINOS De forma nativa lo resuelve el contenedor de .NET; en el navegador el constructor transpilado lo resuelve por el nombre de la interfaz; durante el SSR se resuelve a un almacén que no guarda nada y lo dice: las lecturas responden null, las escrituras no van a ninguna parte, porque el almacenamiento que esto representa vive en la máquina de quien visita. Así que una página lee su valor guardado en el primer render del cliente, y el marcado renderizado en el servidor muestra lo mismo que muestra una primera visita. Vea Capacidades para el cuadro completo. Léelo en OnMount, no en el constructor: el reconciliador construye instancias nuevas en cada pasada y conserva la retenida, así que un constructor que lee almacenamiento lo lee otra vez para una instancia que luego se tira. (Componentes write-once) Por qué los secretos son un tipo distinto
Poner un token en localStorage es el error de seguridad más cometido en la web, y una API donde la seguridad es un argumento secure: true es una API donde la seguridad está a un argumento olvidado de distancia. Aquí la elección no se puede hacer por omisión: un secreto necesita un servicio distinto, y pedirlo es algo que alguien hizo a propósito.
El navegador no tiene bóveda, así que en la web ISecretStore se resuelve a null, igual que el framework reporta cada capacidad que un host no tiene, en lugar de fingir con un almacén que cualquier script del origen puede leer. Una aplicación que lo busca en la web tiene que responder la pregunta que estaba evitando: guardar el secreto en el servidor y entregar al navegador una sesión que solo puede gastar, o aceptar que lo que guardaba nunca fue de verdad un secreto.
En nativo es la bóveda real de la plataforma. Apple: un elemento kSecClassGenericPassword por clave bajo el identificador de bundle de la aplicación, AfterFirstUnlockThisDeviceOnly para que un refresco en segundo plano pueda leerlo mientras un dispositivo no desbloqueado desde el arranque no puede, y nunca sincronizado a iCloud. Android: una clave AES respaldada por hardware en AndroidKeyStore (el material de la clave es ilegible incluso para este proceso) con texto cifrado AES/GCM en un archivo de preferencias. Eso es lo que hace EncryptedSharedPreferences de AndroidX, escrito directamente porque la plataforma entrega cada pieza y el framework no toma una dependencia para algo que el sistema operativo ya provee.
Cada almacén de aquí es por debajo un mapa de cadenas. Una superficie tipada serían tres serializadores que mantener idénticos, y su primer desacuerdo es un valor que se escribe en una plataforma y no se puede leer en otra. Serializa en tu aplicación, donde el formato es tuyo.
El almacenamiento es una capacidad de CLIENTE
No hay realización de servidor. Durante el SSR el servicio se resuelve a null y las lecturas no responden nada.
Esto importa más de lo que suena. Una página que ramifica su árbol según el estado guardado renderiza una cosa en el servidor y otra en el navegador, y el reconciliador reconciliará fielmente la diferencia delante de quien lee. Lee el almacenamiento en un manejador de eventos o después del mount, nunca mientras construyes.
Es también por eso que el almacenamiento solo no puede recordar un tema sin un parpadeo: el servidor pinta primero y localStorage no es algo que pueda ver. Ese problema concreto quiere una cookie, porque el requisito no es "recordar" sino "decirle al servidor", y el framework ya se encarga, así que una aplicación no tiene que hacerlo. Vea ServerIntegration. Los fallos responden, nunca lanzan
•
localStorage es la API del DOM con más probabilidad de lanzar en lugar de fallar en silencio. El modo privado de Safari ha lanzado al escribir, un navegador en su cuota lanza, y leerlo siquiera lanza cuando el origen tiene el almacenamiento bloqueado. Una preferencia que no se guarda no debe tirar una página, así que una escritura que no puede ocurrir simplemente no ocurre, y una lectura que no puede ocurrir responde null.
•
Un elemento de Keychain no sobrevive a toda restauración, y una clave de KeyStore queda invalidada por una nueva pantalla de bloqueo. Las dos cosas hacen que cada valor bajo ellas sea permanentemente ilegible.
Así que trata una lectura null como "vuelve a preguntar" (inicia sesión otra vez, cae al valor por defecto) y nunca como un error que reportar. Es la misma respuesta que da una clave que nunca se escribió, y quien llama ya maneja esa.
Cada capacidad se registra con TryAdd, así que registrar el tuyo gana:
builder.Services.AddSingleton<IAppStorage, MyOwnStorage>();
Esa es la vía de escape para un almacén con otra durabilidad, un archivo cifrado o un doble de pruebas.