¿Porqué el App.config lo tengo duplicado?

Voy a seguir la serie de UniversalSync abordando el “coñazo” de tener que duplicar las entradas del app.config del proyecto en el app.config del proyecto de test y en el cliente de consola, etc.

Esta duplicidad es motivada por el funcionamiento natural de la clase ConfigurationManager y su versión CloudConfigurationManager, que leen el app.config del raíz de la solución desde donde es invocado.

Repetir es malo. Repetirlo mil veces.

Por ejemplo, fíjate en la solución que se ve en la imagen. Si lanzara el test desde el Proyecto de Test “StorageAzureTest” que prueba métodos de la clase “BlobContainer”, el test utilizaría su propio app.config en vez de el del proyecto CloudStorage, que es en donde está la clase que se ejecuta.

app.config

Es más, realmente el proyecto de Test ni tan siquiera necesita un app.config, por lo cual recibiría una preciosa Excepción por no haber encontrado la clave que tengo que recuperar y pasar a la clase que está siendo probada.

¿Y si tengo más proyectos? ¿Tengo que andar copiando y pegando el app.config? Las primeras dos veces, bueno… pero a la tercera (cuando he montado un cliente de consola para probar las cargas en la realidad) ya olía que tenía que cambiar la forma de funcionar.

Una solución, que no la única

Veamos, si he empezado a utilizar Interfaces en el cliente de Consola para desacoplar clases, ¿porqué no utilizar interfaces para pasarle al constructor del Contenedor de Blob los datos que debe utilizar?

    public interface IAzureBlobContainer
    {
        string StorageConnectionString { get; set; }
        string ContainerReference { get; set; }
        CloudBlobContainer container { get; set; }
    }

Voy a empezar por el Test, para que se vea claro el camino que he seguido.

    [TestClass()]
    public class BlobContanierTests
    {
        [TestMethod()]
        public void CreateContainer()
        {
            var blobContainer = new GetBlobContainer();

            Assert.IsNotNull(blobContainer.container);
        }
    }

¿A que parece muy poquito? ¿Qué hace esa clase GetBlobContainer que me devuelve un container que no debe ser null?


    public class GetBlobContainer : IAzureBlobContainer
    {
        public string StorageConnectionString { get; set; }
        public string ContainerReference { get; set; }
        public CloudBlobContainer container { get; set; }

        public GetBlobContainer()
        {
            StorageConnectionString = CloudConfigurationManager.GetSetting("StorageConnectionString");
            ContainerReference = CloudConfigurationManager.GetSetting("ContainerReference");
            Create();
        }

        private void Create()
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(StorageConnectionString);
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            container = blobClient.GetContainerReference(ContainerReference);
            container.CreateIfNotExists();
        }
    }

Lo que hace es recuperar los datos que voy a utilizar para Crear u Obtener una referencia de un BlobContainer. Y lo carga dentro de la propiedad container de la clase que implementa el interfaz.

Por eso el test solamente tiene que instanciar la clase y leer esta propiedad para comprobar que se instancia corréctamente. Es más, puedo desacoplar más y cumplir más con la segregación de responsabilidades, si saco el Create de la clase. Pero por ahora me va bien y le doy más peso a KISS.

¿Qué ocurre en el cliente?

Aquí voy a empezar a tirar del hilo desde el cliente, el cual se queda de esta forma:


        [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();
        }

Como ya describí en el artículo anterior, primero me traigo los ficheros que quiero subir. Y a continuación vienen los cambios (los he separado para hacer más legible el código):

  • Recupero el blobContainer desde la clase que está en la capa del Cloud. Es decir, como va a cambiar la configuración para todos los clientes, pues la sitúo en el sitio central en donde todos lo pueden ir a buscar. Y aquí está la ventaja ya que puedo cambiar los valores de configuración de forma a la implementación del Interfaz que se realiza en GetBlobContainer para, por ejemplo, en los Test utilizar una configuración diferente.
  • Recupero una implementación Azure del interfaz que realiza las operaciones de CRUD, pasandole el blobContainer que he recuperado en el paso anterior.
  • Por último llamo a la clase que envía los fichero al cloud, inyectandole el repositorio que debe utilizar en sus operaciones.

En  los comentarios por twiter me señalaron que puede no ser la solución óptima ya que con situar un config en un sitio en donde lea toda la aplicación debería ser más que suficiente… pero es que me apetecía hacerlo con interfaces 🙂

Espero que sea de utilidad, y nos vemos en el próximo capítulo.

Anuncios

2 comentarios en “¿Porqué el App.config lo tengo duplicado?

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