Cariño, he perdido el foco

El orden de tabulación en una aplicación es uno de esos pequeños detalles que, no siendo a veces ni un requerimiento funcional, hace perder calidad y buena presencia a tu aplicación. Es por tanto importante decidir a qué elementos vamos a dejar navegar pulsando el tabulador y en qué orden lo vamos a hacer. Esto en Silverlight lo hacemos mediante las propiedades IsTabStop y TabIndex.

Pero a veces hacer esto no es tan fácil. Podemos tener controles que no sepamos que pueden recoger el foco y a los que no estemos estableciendo correctamente las propiedades, o que el estilo de los controles no contemple el foco y no sepamos por donde anda.

Si nos pasa esto, necesitamos de un mecanismo que nos ayude a saber qué elemento tiene actualmente el foco. Con esta clase de ayuda podremos conseguir este objetivo:

 

public static class FocusHelper
{
    private static System.Threading.Timer focusTimer;
    private static Control lastFocus = null;

    public static void Start()
    {
        focusTimer = new Timer(new TimerCallback((o) =>
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                object temp = null;

                temp = FocusManager.GetFocusedElement();

                if (temp != lastFocus)
                {
                    if (temp is Control)
                    {
                        Control conTemp = temp as Control;
                        var conTempParent = conTemp.Parent;

                        lastFocus = temp as Control;

                        Debug.WriteLine(«Current Focus: Control » + conTemp.Name + » of Type » + conTemp + » in » + conTempParent);

                    }
                }
            });
        }), null, 0, 100);
    }

   public static void Stop()
    {
        focusTimer.Change(0, System.Threading.Timeout.Infinite);
    }
}

 

Y con esto, llamamos a FocusHelper.Start() donde nos interese debugar el orden de tabulación y en la pantalla de Output del Visual Studio iremos viendo por donde está el foco.

 

Espero que os sirva de ayuda!

 

Nota: código basado en este post: http://codeblog.larsholm.net/2009/12/focushelper/

Problema de rendimiento en Silverlight

Es común que en nuestras vistas de una aplicación Silverlight queramos añadir un borde con un bonito DropShadowEffect que agrupe todo nuestro control o un conjunto de controles. Un posible XAML de ejemplo podría ser el siguiente (aunque de bonito no tenga mucho):

<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Border Background="AntiqueWhite" >
            <Border.Effect>
                <DropShadowEffect BlurRadius="0.2" Direction="55" Color="Red"></DropShadowEffect>
            </Border.Effect>
            <StackPanel>
                <TextBlock>TextBlock 1</TextBlock>
                <TextBlock>TextBlock 2</TextBlock>
                <TextBlock>TextBlock 1</TextBlock>
                <TextBox></TextBox>
                <TextBox></TextBox>
                <TextBox></TextBox>
                <TextBox></TextBox>
                <ProgressBar Grid.Row="1" IsIndeterminate="True" Height="8" Margin="5"/>
            </StackPanel>
        </Border>
    </Grid>

Si nuestra pantalla no fuera tan sencilla sino un poco más compleja (un DataGrid y unos cuantos UserControls por ejemplo) podríamos observar una considerable caída en el rendimiento.

Para intentar mejorar el comportamiento de nuestra aplicación, vamos a analizar que componentes se están redibujando. La lógica nos diría que simplemente se tendría que redibujar el control del ProgressBar o, como mucho, el TextBox que tenga el foco (por el cursor). Para ver que es lo que realmente se está redibujando tenemos que pasar el siguiente parámetro a a nuestra aplicación Silverlight:

<param name="enableRedrawRegions" value="true"/>

Ejecutamos la aplicación y vemos que se redibuja toda la pantalla!!

RedrawAll

Esto sucede porque cuando añadimos un DropShadowEffect a un borde, siempre que se redibuja un elemento que está dentro de este borde, se redibujan todos los elementos que están dentro del borde.

Por suerte la solución es muy sencilla: tenemos que “partir” nuestro borde en dos bordes: en el primero ponemos tan solo el DropShadowEffect y en el segundo agrupamos todo los elementos que nos interesen. Por lo tanto nuestro código original quedaría así:

<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Border Background="AntiqueWhite" >
            <Border.Effect>
                <DropShadowEffect BlurRadius="0.2" Direction="55" Color="Red"></DropShadowEffect>
            </Border.Effect>
        </Border>
        <Border>
            <StackPanel>
                <TextBlock>TextBlock 1</TextBlock>
                <TextBlock>TextBlock 2</TextBlock>
                <TextBlock>TextBlock 1</TextBlock>
                <TextBox></TextBox>
                <TextBox></TextBox>
                <TextBox></TextBox>
                <TextBox></TextBox>
                <ProgressBar Grid.Row="1" IsIndeterminate="True" Height="8" Margin="5"/>
            </StackPanel>
        </Border>
    </Grid>

Si ahora ejecutamos la aplicación veremos que solo se redibuja la ProgressBar:

RedrawProgress

 

Así que ya sabéis, vigilad con los bordes!

Nuestro primer spy con Jasmine

Esta mañana el amigo Marc Rubiño ha escrito un interesantísimo post sobre como empezar con TDD y JavaScript, utilizando qUnit y ReSharper. Esto ha iniciado una pequeña charla en twitter.  Con todo esto me he lanzado a hacer una pequeñísima introducción a los spy con Jasmine.

Mi primera tentación, como ha comentado Marc en su post, ha sido utilizar Chutzpah. Ya había hecho pruebas con el con Visual Studio 2012 y había quedado encantado, pero la verdad es que para Visual Studio 2010 no lo tienen tan bien resuelto. En lugar de correr junto con los otros tests de la solución, hay un dos menús contextuales para ejecutar los tests. Uno para ejecutarlos en el propio Visual Studio e informando de los errores en la ventana de Output y de Error List (pero no en la de test) y otro para ejecutarlos en un browser. Si escogemos esta segunda opción, veremos que la versión de Jasmine con la que está pasando los tests es la 1.1.0 y no he encontrado manera de actualizarlo a la 1.2.0. En VS2012 es bastante sencillo, pero en VS2010 no. Así que al final he desestimado esta opción y he tirado por la de toda la vida de tener un html que pase los tests (podéis ver uno de ejemplo en el mismo zip en el que se distribuye Jasmine).

Empecemos pues con el proyecto. La estructura del mismo es algo como esto

Solucion

 

Vamos a empezar nuestro primer test para comprobar que tenemos bien configurado el SpecRunner.html.

FirstTest

Alucinados con el test, ¿eh? Es sencillo pero ya podemos ver muchas cosas. Primero como definir un Suite con describe y un spec con it. Y después como hacer un aserción muy sencilla. Con esto, ejecutamos SpecRunner.html desde nuestro navegador favorito y vemos que todo ha ido bien.

FirstTestExecution

Perfecto, ya nos podemos poner con el test que nos interesa. Echémosle un ojo a la clase que queremos testear.

SimpleClass

Como veis es una clase muy sencilla que hace una llamada por ajax a un controlador y guarda el resultado en un atributo de la clase. Imaginaros que todavía no tengo el controlador hecho, o que yo no lo voy a hacer y que, a parte, quiero que mis tests sean unitarios, rápidos y que no dependan de elementos externos. ¿Qué tendría que hacer? Pues claramente, mockear la llamada al controlador. Si lo hacemos con nuestras clases en .Net con Moq, Rhino, Moles o el framework que utilicemos, por qué no lo tenemos que hacer en JavaScript?

Y aquí tenemos una de las ventajas de Jasmine sobre otros frameworks de testeo unitario de JavaScript: ella misma ya lleva el framework de mockeo incorporado, lo que ella le llama los spy.

Crear un spy es muy sencillo: tenemos que indicar cual es el objeto y la función que queremos espiar y después ya podemos simular callbacks, mirar si se ha llamado con los parámetros adecuados, si se ha llamado las veces esperadas, simular los valores de retorno, etc.

Vamos a quedarnos con la primera de las opciones y vamos a simular la llamada al controlador via la función ajax de jquery.

MockingJquery

Como veis, estamos indicando a Jasmine que queremos espiar la función ajax de jquery y que queremos que al llamarla, llame a un fake que simule el success. Con esto, ya podemos hacer después el expect que más nos interese, en nuestro caso que se está igualando el resultado al objeto asset. Podríamos haber espiado otras cosas, como que solo se ha llamado una vez, o que se haya llamado con el id 1 como parámetro.

Y hasta aquí esta pequeñísima demo. Espero que entre el artículo de Marc y este, ya no tengáis excusas para testear vuestro código JavaScript!

Hasta la próxima!

Storyboarding con PowerPoint en TFS11

«Un storyboard o guion gráfico es un conjunto de ilustraciones mostradas en secuencia con el objetivo de servir de guía para entender una historia, previsualizar una animación o seguir la estructura de una película antes de realizarse o filmarse.» (Fuente: Wikipedia)

Según esta definición de la Wikipedia parece lógico que un storyboard sea algo que podamos linkar a, por ejemplo, un work item de historia de usuario en nuestro TFS. A los desarrolladores de la nueva versión de TFS también les ha parecido lógico y por eso nos proporcionan de serie una nueva pestaña en el work ítem de historia de usuario para gestionar este tipo de artefactos y, a parte, han desarrollado una extensión para Power Point para poder crearlos con facilidad.

Si abrimos Power Point después de haber instalado el nuevo Team Explorer veremos que si abrimos Power Point tenemos una nueva pestaña llamada Storyboarding

Si clicamos sobre Storyboard Shapes se nos abrirá una pantalla con todas las formas predefinidas que tenemos para crear nuestro storyboard

Ahora solo nos queda crear la pantalla que necesitemos para el dispositivo requerido. Por ejemplo, vamos a intentar (con las limitaciones que mis capacidades de diseño me permitan) crear una pantalla de settings para una aplicación móvil.

Como veis, como diseñador no doy para mucho, pero como Product Owner estoy razonablemente contento. La pantalla tiene todo aquello que yo quiero que tenga. Esta pantalla se puede enriquecer tanto como queramos, ya sea con imágenes, shapes hechas con PowerPoint, capturas de pantalla.

Ahora solo nos queda guardar el archivo (en una carpeta compartida o en un site de Sharepoint) y mediante el botón de Storyboard links ( o desde el work item de la historia, claro) relacionarlo con nuestra historia de usuario.

Un saludo!

Tests unitarios con NUnit (u otros) con VS11 y en TFSService

Con Visual Studio 2010 para poder correr tests unitarios con NUnit teníamos que hacer un poco de trabajo extra, desde instalar una extensión que nos creaba un tipo de proyecto especial, utilizar plugins como TestDriven o simplemente correr los tests desde el runner de NUnit. Ahora con VS11 tenemos esta integración mucho más sencilla, tanto con NUnit como con otros frameworks de test.

Lo que tenemos que hacer es irnos al extension manager de VS11 (Tools ->  Extension Manager ) y bajar por el árbol hasta Online Extensions -> Visual Studio Gallery -> Tools -> Testing. En nuestro caso, seleccionaremos NUnit Test Adapter.

Como veis, ya hay otros adaptadores disponibles y seguro que irán apareciendo más. Los adaptadores lo que son es un puente entre los comandos a los que llama Visual Studio ( como podrían ser «descubre tests», «corre tests», etc ) y las propias llamadas del framework con el que se trabaje. Esto permite que se puedan integrar todos los diferentes tests unitarios en el IDE y tener una mejor experiencia. Podéis leer más información en este artículo de Peter Provost.

Al añadir la extensión de Visual Studio este nos pide reiniciar y al hacerlo, voilà!! Ya tenemos nuestros tests con NUnit pasándose y mostrando el resultado en la ventana de Test Explorer. Obviamente, tendremos que haber incluido, preferiblemente por NuGet, la librería de NUnit para poder compilar los tests.

Es curioso ver como el primer tests de NUnit tarda un poquitín más que el primer test de MSTest.

Si tuviéramos una build de integración continua configurada en el nuevo servicio de builds de TFSService ( como vimos en el artículo de ayer ) y subiéramos nuestros cambios a TFSService, podríamos ver que los tests de NUnit no se están pasando, ya que las máquinas de TFSService, no lo traen configurado por defecto. Por suerte, arreglar esto es algo muy sencillo.

Primero de todo nos vamos a bajar la misma extensión de Visual Studio a nuestro ordenador (a no ser que ya lo hubiéramos hecho antes en lugar de instalarla por NuGet). Esto lo podemos hacer accediendo a la siguiente página http://aka.ms/nunit-vs11. Cuando tengamos el vsix en nuestro disco duro, le cambiamos la extensión a .zip y lo descomprimimos a una carpeta.

Copiamos todas las dlls y las metemos en una carpeta de nuestro control de código fuente.

 Ahora solo hace falta indicarle a nuestro controlador de builds que los custom assemblies los busque en esta carpeta. Así que nos vamos a la sección de builds del Team Explorer, clicamos sobre Actions y seleccionamos la acción Manage Build Controllers

En la ventana de configuración que nos sale, seleccionamos el Hosted Build Controller

Y accedemos a sus propiedades y modificamos el valor de Versión Control Path to Custom Assemblies al valor adecuado en nuestro caso.

 

Ya podemos volver a correr la build y podremos ver como se pasan tanto los tests de MSTest como los de NUnit.

Un saludo!!

Fuente: http://blogs.msdn.com/b/visualstudioalm/archive/2012/03/27/build-on-the-team-foundation-service.aspx

Creación de una build con el nuevo servicio de builds para TFS Service

Hace un par de días, Brian Harry anunció que ya estaba disponible el nuevo servicio en la nube para poder crear builds de un proyecto alojado en TFS Service. Como ya sabéis, TFS Service es un TFS11 alojado en Azure y, por ahora, con acceso gratuito mediante invitación.

Hasta hace un par de días, una de las limitaciones que tenía este servicio es que no proveía de la posibilidad de crear builds también alojadas en la nube, con lo que nos teníamos que crear nosotros la infraestructura necesaria para ello, ya sea instalando en una máquina local un agente de build de TFS11 o alojándolo nosotros mismos en Azure. Ahora esto ya no es así, y Microsoft ya nos provee de un servicio donde poder alojar nuestras builds y, a parte, facilísimo de configurar.

Para crear una build, haremos lo que estamos acostumbrados a hacer con nuestro TFS de toda la vida, es decir, ir al apartado de builds de nuestro Team Explorer y clicar sobre New Build Definition.

 Se nos abrirá la pantalla de definición de builds donde configuraremos los parámetros de la build que nos interesen. En este caso, hay dos parámetros críticos: el controlador de la build y el drop folder.

Como veis, nos ha aparecido un controlador nuevo, llamado Hosted Build Controller, que es el que tenemos que seleccionar. Por otra parte, por una limitación de azure, no podemos copiar el output de la build a un path UNC, así que tendremos que escoger la opción de copiarlo en una carpeta del Source Control. Vigilad en no poner una carpeta que tengáis mapeada en un proyecto, para no bajaros información innecesaria.

Y ya está, ya tenemos todo lo necesario para correr nuestra build. Ya podemos poner una build en la cola y esperar que esta finalice, a poder ser de manera satisfactoria claro 🙂

Mañana veremos como podemos configurar el adaptador de nUnit para pasar los tests con este framework desde Visual Studio y como configurar la build para que también lo haga.

Un saludo!

Mi participación en el Codemotion.es

El pasado 24 de marzo tuve el placer de participar en la primera edición española del Codemotion. Mi charla fue una introducción a Kinect y tuve el gusto de compartirla con el gran @elbruno. Podéis ver en la entrada de su blog una descripción de la charla así como la descarga de los materiales y slides.

En este artículo me gustaría centrarme más en dar mi opinión sobre las cosas que me gustaron y las que considero que son mejorables del evento en sí, tanto desde el punto de vista de ponente como desde el punto de vista de asistente. Vaya por delante mi respeto enorme por la organización, que fue capaz de convocar y gestionar la participación de unas 1000 personas.

Empecemos por lo mejorable. Como ponente me parece que la selección de las charlas fue un poco caótica. Nosotros mismos no nos enteramos de que nos habían seleccionado la charla hasta 15 días antes, que es un tiempo un poco justo para organizar una buena charla, sobretodo teniendo en cuenta de que había gente que hacía un mes que lo sabía. También fue un poco justo el aviso de la cena de ponentes, con solo un par de días de antelación, que nos cogió con los billetes ya comprados con lo que nos fue imposible asistir.

En cuanto al punto de vista de asistente, me sumo a la petición de aulas más grandes. Hubo charlas en que el aula estaba a reventar (tuvimos la «suerte» de ser una de estas, síntoma de que la charla interesaba) y la gente no pudo entrar a escuchar temas que le interesaban. A parte, el sonido en algunas de ellas era bastante mejorable, siendo difícil de escuchar nítidamente al ponente.

Por otra parte, aunque esto es un problema de los eventos en general, sigo sin ver claro el valor que aporta a los patrocinadores tener un pequeño stand en medio de un pasillo. No tengo claro que el retorno de inversión del patrocinio sea elevado con esta forma de promoción. Es algo en que las organizaciones de los eventos y los patrocinadores en sí deberían mejorar para poder ofrecer algo diferente y de más valor.

Y vamos ahora a por lo bueno. Me parece increíble juntar a unas 1000 personas en un evento de desarrollo en nuestro país. Creo que la gestión del registro y de los 15 minutos entre charlas estuvo muy bien resuelto, no habiendo demasiado follón ni colas. La comida, un punto crítico en toda organización de eventos, estuvo muy bien resuelta con la bolsa con el bocadillo y la bebida, permitiendo a la gente que se sentara donde le apeteciera, evitando colas interminables y saturación de la cafetería y facilitando un buen tiempo de networking.

En definitiva, me pareció un muy buen evento con un amplio rango de mejora.

Un saludo!

Work Item de retrospectiva

Hola a todos,

como muchos sabréis, la plantilla MSF for Agile es una plantilla genérica de TFS 2010 que se adapta bien a cualquier metodología ágil, sin centrarse en las particularidades de una u otra como, por ejemplo, sí que hace Visual Studio Scrum.

En MSF for Agile, las iteraciones las definimos en la pantalla de áreas e iteraciones de la plantilla, pero en ningún caso le ponemos límites temporales a las mismas. Esto en la plantilla Visual Studio Scrum lo hacemos gracias al elemento de trabajo Sprint, en el que definimos una fecha de inicio y una fecha de fin del sprint.  Otra información que podemos introducir en este elemento de trabajo es la información resultante de la retrospectiva. Si queréis saber un poco más de retrospectivas podéis echarle un vistazo a la charla que dio el amigo Jose Ramón Díaz en la CAS2011.

En cambio, en la plantilla MSF for Agile no tenemos ninguna manera clara de introducir esta información (aunque siempre hay maneras alternativas de hacerlo, como un documento en el Sharepoint, por ejemplo). Es por esto que en Plain Concepts hemos hecho un nuevo elemento de trabajo para poder guardar mejor esta información en nuestro TFS. Aquí tenéis un pantallazo de como es el nuevo elemento de trabajo.

wiretrospective

Y aquí tenéis la definición del elemento de trabajo por si lo queréis utilizar en vuestro TFS. [View:/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.20.23.37/Retrospective.rar]

Un saludo!

Mockeo de servicios WCF con Moq

Muy buenas a todos. Después de un tiempo de inactividad bloguera, volvemos a la carga con uno de nuestros temas favoritos: el testeo unitario. Esta vez vamos a ver como podemos mockear (o hacer un doble de prueba, como prefiráis) un servicio WCF con la ayuda de Moq. Recordad que tenéis dos tutoriales introductorios a Moq en este mismo blog (parte 1, parte 2).

Para nuestro ejemplo vamos a utilizar uno de los servicios web que proporciona Sharepoint. Imaginaos que tenemos una clase que utiliza dicho servicio. Los pasos para hacerlo podrían ser:

  1. Agregar la referencia al servicio
    ConfigurarServicioSinAsync
  2. Crear una instancia de la clase cliente en nuestro código
    private DwsSoapClient sharepointClient = new DwsSoapClient();
  3. Hacer la llamada a la función deseada
    sharepointClient.CreateFolder(«http://share:81/sites/TestSite«);

Hasta aquí nada nuevo. ¿Pero qué pasa si queremos testear unitariamente nuestra clase? Pues para empezar lo que pasará es que si no hacemos ningún cambio, lo que nos salga no será un test unitario, pues necesitará de un elemento externo como puede ser un Sharepoint para poder funcionar. Lo que tendremos que hacer será mockear la clase proxy. Esto con Moq directamente no lo podemos hacer, pues esta clase no es abstracta ni tiene métodos virtuales. Si le echamos un ojo al fichero reference.cs que tiene la implementación del cliente (haciendo un Go to reference en una función) veremos que la clase implementa una interfaz del servicio. ¡Magnífico! Pues no, ya que los métodos que normalmente utilizaremos desde el cliente no se pueden acceder desde esta interfaz, ya que están directamente codificados en la clase. Lo mismo nos pasará con los métodos asíncronos si creamos el proxy del servicio con el check activado:

ConfigurarServicioConAsync

 

En este caso, Visual Studio pone estos métodos, y sus correspondientes eventos, directamente en el código de la clase cliente, y tampoco los añade a la interfaz. ¿Que opción tenemos? Pues crearnos nosotros una interfaz que incorpore los métodos asíncronos y los eventos para así ser capaz de mockearlos. También, apoyándonos en que la clase cliente es una clase parcial, haremos que la clase cliente implemente esta interfaz sin tener que tocar el fichero reference.cs, que es un fichero generado automáticamente por Visual Studio y no es nada recomendable modificarlo. Así pues, generaremos un fichero con el siguiente código, recordando de especificar el mismo namespace que la clase cliente.

public interface ISharepointDWSAsyncService : DwsSoap 
{
    void CreateFolderAsync(string url); 
    event System.EventHandler<CreateFolderCompletedEventArgs>
        CreateFolderCompleted; 
}

public partial class DwsSoapClient : ISharepointDWSAsyncService
{ }

En este caso sólo hemos añadido un método que será el que utilizaremos para el ejemplo, pero aquí tendríais que añadir todos los métodos y eventos que necesitéis.

Ahora que tenemos la interfaz, tenemos que modificar el código de nuestro SUT para que utilice la interfaz y no directamente la clase. Después utilizaremos inyección de dependencias para inyectar la implementación que nos interese. La inyección la podemos hacer de múltiples maneras, por ejemplo por constructor o por propiedad. Roy Osherove recomienda en su libro The Art of Unit Testing, with examples in .Net (que os recomiendo) que las dependencias obligatorias se inyecten por constructor y las opcionales por propiedad. Podéis utilizar esta regla como referencia. En nuestro caso, la inyectamos por propiedad:

private ISharepointDWSAsyncService sharepointClient;

public ISharepointDWSAsyncService SharepointClient
{
    set 
    { 
        sharepointClient = value;
    } 
}

El resto del código del SUT debería quedar igual.

Ahora ya podemos pasar a escribir nuestro test. Gracias a las bondades de Moq, nos queda un código bastante compacto y elegante:

[TestMethod] 
public void TestAsynCall() 

    Mock<IDAO> mockDao = new Mock<IDAO>();           

    Mock<ISharepointDWSAsyncService> sharepointMock = new
        Mock<ISharepointDWSAsyncService>();
    AssetManager assetManager =
        new AssetManager(mockDao.Object); 
    assetManager.SharepointClient = sharepointMock.Object; 
    
    assetManager.CallWSAsync(); 
    sharepointMock.Raise(sp => sp.CreateFolderCompleted += null,
        new CreateFolderCompletedEventArgs(
            new string[] { «CreateFolderCompleted» }, null, false, null));

    Assert.AreEqual(«CreateFolderCompleted»,
        assetManager.resultCall); 
}

Como veis, primero creamos los dos mocks que utilizará nuestro SUT, uno lo inyectamos por constructor y otro por propiedad. Después hacemos la llamada a la función que hará la llamada asíncrona al servicio y después utilizamos la capacidad de Moq para lanzar eventos en un mock para lanzar el evento de completed de nuestra interfaz. Finalmente haremos el Assert que toque, en nuestro caso simplemente miraremos que se ha establecido el valor de una propiedad al valor correspondiente.

Y ya tenemos nuestro servicio WCF mockeado! Obviamente, esto último explicado sirve para cualquier clase asíncrona, no solo para servicios WCF. De echo, otra cosa que podemos hacer y que también os recomiendo es poner un nivel de indirección [1] entre vuestra clase y el servicio WCF, es decir, una clase intermedia con las llamadas y eventos que necesitéis. Esto os permitirá una mayor abstracción del servicio WCF (y poder cambiar su implementación sin sufrir demasiado) y el código seguramente os quedará más legible y usable.

Nos leemos!!

[1] –> «There is no object-oriented problem that cannot be solved by adding a layer of indirection, except, of course, too many layers of indirection.»

No hagas un deploy de lo que no tengas que hacer un deploy

Hoy nos hemos encontrado con uno de esos poltergeist que tan locos nos vuelven de tanto en cuanto.

Resulta que estábamos haciendo un despliegue de una aplicación MVC en un entorno de pruebas. Es una aplicación sencillita con autenticación windows y una autorización personalizada como explicábamos en el anterior artículo. Lo primero que nos hemos encontrado es que al acceder a la aplicación nos daba un error 403. Esto es debido a que el AppPool con el que estaba configurada la aplicación en el IIS tenia el Pipeline Mode a Classic. Este modo evita que podamos acceder a direcciones sin extensión, aunque hay workarounds que solventan el problema.

Pero todavía no sabíamos que teníamos este problema, así que una de las (erróneas) creencias que hemos tenido ha sido pensar que nuestro IIS tenia algún problema con el MVC. Pensando esto, hemos querido desplegar las dlls necesarias con nuestra aplicación, así que nos hemos ido a nuestro querido Visual Studio, hemos hecho clic con el botón derecho sobre la solución y hemos seleccionado la opción “add deployable dependencies”

adddeploymentdependencies2

Esto, después de pedirnos que dependencias queríamos añadir…

adddeploymentdependenciesStep2

…nos ha creado un directorio en la solución con las dependencias necesarias

bin_deployableAssemblies

Esto no nos ha solucionado nada ya que todavía teníamos el AppPool mal configurado. Finalmente nos hemos dado cuenta de nuestro error, hemos cambiado el AppPool y hemos vuelto a ejecutar la aplicación… y todavía nos ha dado un error más sorprendente!!

404

Un 404!! Y un 404 sobre un controlador y una acción que no tenemos definido. Repasamos el web.config para ver si tenemos alguna redirección mal configurada y vemos que no es así. Finalmente, después de mucho buscar nos hemos encontrado con este salvador blog. En él, su autor explica que si teniendo una aplicación con autenticación forms y cambiándole en el web.config el controlador de autenticación, la aplicación se le redirige hacia el mismo controlador que a nosotros. El autor explica que esto es un bug conocido que pasa cuando estamos desplegando las librerías WebMatrix.Data.dll y WebMatrix.DataWeb.dll junto con nuestra aplicación. Aquí podéis ver el error en el Windows Connect. Esto que a él le pasa con autenticación forms, parece que también pasa con autenticación windows.

Finalmente hemos borrado estas dos librerías del bin de nuestra aplicación y voilà!

appok

Así que ya sabéis, id con cuidado con lo que desplegáis, no vayáis a tener resultados inesperados!!

Un saludo!