RunSafe Tasks / Commands wrapper en Xamarin

Contenido

Cuando trabajamos con Task la mayor parte del tiempo hacemos implementaciones comunes de escenarios donde usamos código repetitivo. Por ejemplo usar IsBusy, try-catch, Loggin, etc.

Bueno, la idea es hacer un wrapper que nos permita almacenar toda esta lógica para nosotros reutilizarla. Así que, vamos a ello.

Task Wrapper (Tarea Contenedora)

Empecemos por el principio. ¿Qué es un Task Wrapper? En general, una Task Wrapper es una tarea, metodo o proceso que «envuelve» o «encapsula» cierta funcionalidad.

Estas son útiles al proporcionar un nivel de abstracción de implementación; por ejemplo, las tareas contenedoras que envuelven lógica administrativa de proceso de invocación sin molestar al código que se llama con él.

También pueden simplificar el uso del objeto subyacente al reducir el número de puntos de interfaz involucrados; con frecuencia, esto permite un uso más seguro de los componentes subyacentes. Sin mencionar que facilita bastante el soporte o adaptación para todas sus implementaciones.

Para poder entender todo el contexto, veamos un escenario común:

...
        private async Task DoSomething()
        {
            try
            {
                if (IsBusy) return;

                IsBusy = true;

                // Your code goes here
            }
            catch (Exception e)
            {
                // Your code goes here
            }
            finally
            {
                IsBusy = false;
            }
        }
...

El ejemplo mostrado anteriormente es un escenario común donde muy probablemente estemos repitiendo el mismo código (try-catch y IsBussy) en todas las acciones que ejecutas.

Para evitar esto, utilizaremos un RunSafe Task Wrapper. Veamos a continuación.

RunSafe Task Wrapper

Para evadir el código repetitivo lo que vamos a hacer es crear un método que podamos usar globalmente en todas nuestras ViewModel. Es decir, debemos crear un método parecido al siguiente en nuestra BaseViewModel. Veamos:

...
        protected virtual async Task RunSafe(Task task, Action<Exception> onError = null)
        {
            try
            {
                if (IsBusy) return;

                IsBusy = true;

                await task;
            }
            catch (Exception e)
            {
                onError?.Invoke(e);
            }
            finally
            {
                IsBusy = false;
            }
        }
...

Aquí hay que tener en cuenta varias cosas:

  • Podemos ejecutar una acción (Action<Exception>) que reciba una excepción para nosotros poder manejar el contexto en caso de que pase algo. Por ejemplo: actualizar el estado de tu aplicación.
  • Podemos agregar otras propiedades como Loggin o Crashes.TrackError(exception, properties) de App Center para rastrear nuestras excepciones y mas.
  • Tambien podemos almacenar lógica mas global como mostrar estados en la aplicación, o simplemente manejar un TimeOut para nuestras tareas.
  • Etc.

Con este wrapper eliminamos toda ese código repetitivo, y lo utilizaríamos de la siguiente manera.

...
        // Normal Implementation
        await RunSafe(MyMethod(parameter));

       // Command Implementation
       MyCommand = new Command(async () => await RunSafe(MyMethod(parameter)));
...

RunSafe Command Wrapper

Con lo anterior deberíamos podemos trabajar sin ningún problema, pero para aquellos que están utilizando ReactiveUI pueden hacer esto con los comandos.

...
        protected virtual void RegisterSafeCommand<T, U>(ReactiveCommand<T, U> command, Action<Exception> onError = null)
        {
            command.IsExecuting.Subscribe(x =>
            {
                this.IsBusy = x;
            }, _ => this.IsBusy = false); 

            command.ThrownExceptions.Subscribe(exception =>
            {
                onError?.Invoke(exception);
            });
        }
...

OR

...
        protected virtual void RegisterBusyCommand<T, U>(ReactiveCommand<T, U> command) =>
           command.IsExecuting.Subscribe(
               x => this.IsBusy = x,
               _ => this.IsBusy = false,
               () => this.IsBusy = false
           );
...

Luego podemos tener una implementación similar a esta:

...
        MyCommand = ReactiveCommand.CreateFromTask(MyMethod);
        RegisterSafeCommand(MyCommand , _ => Console.WriteLine("Something Happens"));
...

Como ves, estas son algunas aplicaciones que puedes hacer con los comandos, pero estas pueden variar dependiendo de las necesidades.

Conclusión

Como les prometí, este articulo que les puede ayudar a manejar los errores en su lógica de negocio a nivel global. Y si eres nuevo, no dejes de leer el articulo anterior para manejar errores globales en Xamarin.

Espero que este articulo les sea de mucha utilidad, y cualquier comentario me lo dejan en la caja de abajo. Si quieres que escriba sobre un contenido especifico déjamelo saber en las redes y si tu solicitud gusta mucho es muy probable que lo veamos por aquí.

Nada, recordarles que estoy compartiendo muchísimo contenido en Twitter y LinkedIn para los que quieran darse una vueltica por allá.

Sin nada mas que agregar, ¡Nos vemos en la próxima!

¿Qué opinas de este contenido?
 
Luis Matos

Luis Matos

I help professionals and companies to create value solutions. I am a Systems Engineer, blockchain executive, and international mobile application speaker. Founder of the Malla Consulting Agency and several international technology communities.
Suscribirte
Notificar de
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x

Buscar en el sitio