GetObject <T> de Akavache se bloquea cuando se espera. Alguna idea de lo que está mal aquí?

Tengo una aplicación Xamarin.Forms, con este código en mi clase App (sí, esto es sólo un ejemplo para demostrar el problema):

public App() { BlobCache.ApplicationName = "MyApp"; BlobCache.EnsureInitialized(); // The root page of your application MainPage = GetMainPage(); } public object BlockingGetExternalUser() { return GetExternalUser().Result; } private async Task<object> GetExternalUser() { try { return await BlobCache.LocalMachine.GetObject<object>("user"); } catch (KeyNotFoundException) { return null; } } 

La clave "usuario" no existe, por lo que esperaría obtener una KeyNotFoundException. Sin embargo nunca veo esta excepción ser lanzada. En su lugar simplemente "se bloquea" y nunca vuelve de la llamada GetObject esperar.

Estoy ejecutando esto en mi teléfono con Android 5.0.

Alguna idea de cómo solucionar este problema? ¿Estoy haciendo algo fundamentalmente equivocado?

Actualización: En una nota lateral: En lugar de intentar inmediatamente GetObject, se podría intentar comprobar si la clave realmente existe en la caché y sólo entonces recuperarla de la caché. Sin embargo, si no me equivoco, no hay otra forma de hacer un cheque que no sea llamar a GetObject y capturar la excepción como en la muestra anterior. Para un escenario en el que uno sólo desearía saber si existe un artículo, eso no parece ser el ideal. Tal vez un "Exists ()" método sería un buen tener en Akavache? O tal vez me falta algo?

Actualización2: Cambiar el ejemplo para no utilizar un método asíncrono en el constructor. Sólo para demostrar un punto de que ese no es el problema.

Actualización3: Eliminar la llamada del constructor. Cuando llamo a BlockingGetExternalUser desde cualquier parte de mi código, el await seguirá colgando.

Lo más seguro es que tienes un bloqueo. Citar Esperando sincrónicamente una operación asíncrona y por qué Wait () congela el programa aquí :

La espera dentro de su método asíncrono está tratando de volver al hilo de interfaz de usuario.

Dado que el hilo de la interfaz de usuario está ocupado esperando que se complete toda la tarea, tiene un bloqueo.

Tenga en cuenta que su llamada a .Result implica un Task.Wait() alguna parte.

Hay dos soluciones: Evite completamente los métodos async o envuelva el código en una Task.Run siguiente manera:

 public object BlockingGetExternalUser() { return Task.Run<object>(() => GetExternalUser().Result); } 

(Espero que esté compilando no verifiqué en VS 🙂

Por experiencia tiendo a evitar los métodos async en combinación con SQLite en estos días. La razón es que la mayoría de las bibliotecas de wrapper de SQLite utilizan el Task.Run Anti-patrón de Task.Run para proporcionar wrappers async alrededor de sus métodos mientras que SQLite no tiene ninguna anotación intrínseca de ser asíncrono. Tenga en cuenta que está perfectamente bien para que envuelva las cosas en Task.Run para hacerlas asíncronas y que es sólo un anti-patrón para los diseñadores de la biblioteca, lo que sugiere a sus usuarios que los métodos son asíncronos cuando en realidad no lo son. Puedes leer más sobre esto aquí: Task.Run como un anti-patrón?

El uso de métodos asíncronos en un constructor ( var externalUser = GetExternalUser().Result; ) se considera como un código incorrecto. No debe utilizar métodos asíncronos en los constructores de una clase. Lea esto: ¿Pueden los constructores ser asíncronos?

Puede intentar cambiarlo para evitar bloqueos:

 Func<Task> task = async () => { await GetExternalUser().ConfigureAwait(false); }; task().Wait(); 

… pero no lo recomiendo.

  • Cómo personalizar el icono de flecha, el icono de la página y el título de la página en MasterDetailPage - Xamarin.Forms
  • Convertir Xamarin.Forms.Color a color específico de la plataforma
  • Xamarin Forms - Media Plugin - Vaciar las miniaturas en el teléfono
  • Superposición blanca en WebView después de la actualización a AppCompat con Xamarin Forms
  • ¿Puedo diseñar la interfaz de usuario en Xamarin.Forms mediante XAML
  • Xamarin.Forms MasterDetailPage con TabbedView - Tab Título que aparece al navegar a través del menú de hamburguesas
  • Xamarin.Forms untappable ListView (eliminar el efecto de rizo de selección)
  • Xamarin.Forms acceder a los controles escritos en el código de marcado
  • Resource.Designer.cs: "Recurso ... no contiene una definición para ..."
  • Proguard en gris en ciertas configuraciones de construcción
  • Reenvío de fuerza de Xamarin.Forms View con procesador personalizado
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.