Interfaseando que es gerundio

La siguiente tarea que he decidido continuar en UniversalSync, es subir múltiples ficheros para ir tanteando si realmente funciona las soluciones que voy picando.

En el capítulo anterior he razonado porqué escogí utilizar Blob cool para persistir los ficheros multimedia en Azure y, una vez hechas las clases básicas de conexión, referencia y operaciones, el siguiente paso lógico es hacer un cliente simple.

Un cliente MVP

Quiero hacer un cliente de consola que me permita elegir una carpeta, y que me suba al Cloud todas las imágenes y vídeos que almacene este directorio y todos los subdirectorios.

La forma más sencilla y funcional de elegir un directorio y sus subdirectorios es utilizando el componente FolderBrowserDialog. Pero, ojo, para ello debo entrar en las referencias del programa (y del proyecto de Test) e incluir la clase System.Windows.Forms.

 class SelectFolder
    {
        public static List<string> RecursiveAndFiles()
        {
            var filesPaths = new List<string>();
            var numFiles = 0;
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            if (fbd.ShowDialog() == DialogResult.OK)
            {
                Console.WriteLine("Directorio principal: " + fbd.SelectedPath);
                foreach (var path in Directory.GetFiles(fbd.SelectedPath))
                {
                    Console.WriteLine(Path.GetFileName(path));
                    filesPaths.Add(path);
                    numFiles++;
                }
                foreach (var directorio in Directory.GetDirectories(fbd.SelectedPath))
                {
                    Console.WriteLine(directorio);
                    foreach (var path in Directory.GetFiles(directorio))
                    {
                        filesPaths.Add(path);
                    }
                    numFiles++;
                }
                Console.WriteLine("Numero de ficheros totáles: " + numFiles);
            }

            return filesPaths;
        }
    }

Realmente poco hay que contar de aquí, a excepción que tuve que añadir que buscara en el fbd.SelectedPath, porque el foreach arranca en los subdirectorios.

Ok, ya tengo cómo seleccionar los directorios y subdirectorios. Devolviendo una lista de paths por cada uno de los ficheros. Ahora tengo que hacer la clase que itere sobre esta lista, que los lea del disco duro y que los mande al Cloud.

Y como quiero que pueda utilizar cualquiera de los Cloud sin tener que cambiar el código, me veo abocado a utilizar Interfaces.

    public interface ICloudRepository
    {
        bool Put(FileStream file);
        Stream Get(string fileName);
        bool Delete(string fileName);
    }

Así cuando construya la clase que envía los ficheros, le puedo inyectar una implementación del interface de acuerdo al repositorio Cloud que quiero que utilice.

 public class SendFilesToCloud
    {
        private ICloudRepository CloudRepository;

        public SendFilesToCloud (ICloudRepository cloudRepository)
        {
            CloudRepository = cloudRepository;
        }
        public bool PutAllFiles(List<string> filePaths)
        {
            var resultado = false;
            foreach (var filePath in filePaths)
            {
                resultado = false;
                var file = File.OpenRead(filePath);
                resultado = CloudRepository.Put(file);
            }
            return resultado;
        }
    }

Fíjate que como estoy utilizando un interface, le puedo inyectar cualquier implementación; no solamente la de Azure. Y así el método Put podrá subir ficheros a Azure, Amazone, Flirck o cualquier sitio que tenga una implementación del interface. Sin tocar ni una línea de la clase.

Por ejemplo en el test utilizo un Mock de una implementación vacía:

    [TestClass()]
    public class SendFilesToCloudTests
    {
        [TestMethod()]
        public void PutAllFilesTest()
        {
            var sendFilesToClouds = new SendFilesToCloud(new BlobMock());
            var listadoFicheros = new List<string> { @"..\..\20160514_195832.jpg", @"..\..\20160512_194750.mp4" };

            var resultado = sendFilesToClouds.PutAllFiles(listadoFicheros);

            Assert.IsTrue(resultado);
        }
    }

    public class BlobMock : ICloudRepository
    {
        public bool Delete(string fileName)
        {
            try
            { return true; }
            catch (Exception)
            { return false; }
        }
        public Stream Get(string fileName)
        {
            try
            { return new MemoryStream(); }
            catch (Exception)
            { return null; }
        }
        public bool Put(FileStream file)
        {
            try
            { return true; }
            catch (Exception)
            { return false; }
        }
    }

Lo siguiente es irme a la clase Program,  al método Main y añado el código necesario para conectarme a la referencia del contenedor de Azure sobre las que voy a realizar las operaciones.

    public class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {
            var filesPaths = SelectFolder.RecursiveAndFiles();
            var blobContainer = new GetBlobContainer();
            var repository = new Blob(blobContainer);
            var resultado = new SendFilesToCloud(repository).PutAllFiles(filesPaths);

            Console.WriteLine("Pulsa una tecla");
            Console.ReadKey();
        }
    }

Dos cosas tengo que señalar:
* El decorador [STAThread] del método Main, que es obligatorio para poder utilizar el picker de Form, ya que debe forzar a utilizar un solo hilo de ejecución.
* La creación del blobContainer y repository, para inyectarlo en el método de SendFilesToCloud, lo explicaré con más detalle en el siguiente artículo.

Como bien me dicen en los comentarios de twiter, este código ya está pidiendo a gritos en uso de un inyector de dependencias… que ya lo he metido en el Backlog.

Espero que sea de utilidad.

Anuncios

Un comentario en “Interfaseando que es gerundio

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s