127.0.0.1: Hogar dulce hogar

martes, 24 de agosto de 2010

[WCF] Desplegando en IIS, error 404.2

Personalmente considero a la rama IT como algo sencillo desde el punto de vista idealista, puesto que muy, muy en el fondo son tareas que se pueden considerar mecánicas una vez conoces el funcionamiento de todo. El problema es cuando estás en proceso de aprender y tardas a veces más tiempo en configurar el despliegue que en otras tareas. Eso es lo que me ha pasado al desplegar un servicio WCF en IIS.

Al desplegar mi servicio WCF obtenía el error 404.2 indicando que no podía acceder al servicio correspondiente, por lo que si no es visible para el propio servidor menos aún lo será para cualquier aplicación que desee consumirlo.

El problema de acceso puede consistir en dos pasos fundamentales:

  • Algún problema en el webconfig (o no están bien definidos los endpoints del servicio o bien directamente no puede acceder al fichero). Para el primer punto basta con editarlo y arreglar la parte que está mal especificada y para la segunda basta verificar si el fichero es accesible por los permisos para el servidor y si está contemplado en las directivas de Filtrado de Solicitudes:image
  • No puede acceder al servicio debido a alguna restricción ISAPI o CGI, en cuyo caso deberemos comprobar el tipo de aplicación que permite ejecutar el servidor. En este caso, al emplear WCF deberemos asegurarnos que IIS se está ejecutando con la versión 4.x como mínimo de .NET Framework y que además, los filtros de las solicitudes ISAPI y CGI permiten la ejecución de estas características:image

Una vez teniendo esto correctamente configurado, IIS ya podrá ejecutar nuestro servicio correctamente.

miércoles, 18 de agosto de 2010

[SilverLight] NotFound Exception

Una de las mayores desventajas que nos podemos encontrar en SilverLight es la depuración de errores, en especial si estamos usando servicio WCF con RIA. Siempre podemos depurar la aplicación SilverLight cuando usemos Visual Studio, pero el problema es cuando disponemos de un servicio correctamente desplegado en IIS y nuestra aplicación falla al conectarse al servicio. El error más común al lanzar nuestra aplicación que se conecta a un servicio es una excepción de WCF indicando lo siguiente:

   1: {System.Net.WebException: El servidor remoto devolvió un error: NotFound. ---> System.Net.WebException: El servidor remoto devolvió un error: NotFound.
   2:    en System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
   3:    en System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
   4:    en System.Net.Browser.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)
   5:    --- Fin del seguimiento de la pila de excepciones internas ---
   6:    en System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
   7:    en System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   8:    en System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)}

Para ver qué esta ocurriendo realmente debemos realizar los siguientes pasos:

1 – Debemos asegurarnos que nuestro servicio está creado perfectamente dentro del servidor (accediendo al servicio a través del mismo para comprobar que se ha creado correctamente).

2 – Verificar si el ámbito del servicio y nuestra aplicación es el mismo. En el caso de que no lo sea, debemos especificar las políticas de acceso de dos modos: uno para las aplicaciones SilverLight y otro para el estándar de Adobe (como bien se indica en este artículo para SilverLight y este otro para dominios cruzados )

3 – Por último nos queda establecer una directiva para poder imprimir la traza. La excepción de NotFound es un tanto ambigua, ya que aparentemente indica que no ha encontrado el servicio pero no indica por qué. Antes de dedicarse mucho tiempo a analizar la configuración del cliente y el servidor conviene primero imprimir la traza del error para conocer de primera mano qué es lo que impide al cliente conectarse con el servicio. Para ello debemos indicarlo expresamente mediante las siguientes líneas en el web.config (fichero de configuración del lado servidor):

 

<system.serviceModel>

    <diagnostics>
      <messageLogging logEntireMessage="true"
        maxMessagesToLog="300"
        logMessagesAtServiceLevel="false"
        logMalformedMessages="true"
        logMessagesAtTransportLevel="true" />
    </diagnostics>

</system.serviceModel>

Poca explicación se puede añadir a esas líneas. Únicamente le estamos indicando que queremos activar el sistema de log, las características de los que admitimos y la capacidad del log.

Por otra parte tenemos que añadir el siguiente nodo al XML:

<system.diagnostics>
    <sources>
      <source name="System.ServiceModel.MessageLogging" switchValue="Verbose">
        <listeners>
         <add name="xml" type="System.Diagnostics.XmlWriterTraceListener"
           initializeData="c:\Temp\WcfMessage.log" />
        </listeners>
      </source>
    </sources>
    <trace autoflush="true" />
</system.diagnostics>

Donde evidentemente estamos indicando dónde se almacenará el log que podremos ir consultando. Por último, sólo falta indicarle a las clases de los servicios que queremos incluirlos en el sistema de logging especificándole el comportamiento IncludeExpcetionDetailInFaults en la cabecera de la clase:

   1: [ServiceBehavior(IncludeExceptionDetailInFaults= true)]
   2: public class Service
   3: {
   4: ...
   5: }

Ahora, cada vez que se produzca un fallo podemos verlo en el fichero WcfMessage que hemos especificado para ver exactamente que es lo que está ocurriendo por debajo y así poder facilitar las tareas de depuración.

viernes, 13 de agosto de 2010

[WCF] Implementando objeto serializable ( II )

Con este artículo concluyo la miniserie sobre SilverLight y WPF, ya que simplemente queda explicar cómo se puede serializar y deserializar un objeto en WCF. Recordemos que todo esto ha venido por una aplicación SL que estoy montando y que a través de un servicio web en WCF ejerzo dicho proceso de serialización sobre los objetos.

Para ello, tenemos que tener en cuenta las siguientes partes:

  • DataContractSerializer: Es la clase encargada de serializar el tipo. Nosotros podemos espeficiar y crear nuevos tipos de serializadores para nuestros objetos de datos según nuestras necesidades.
  • Stream: Un flujo de datos, sea de memoria o ficheros que permita abrir o cerrarlos para acceder a los datos.

Ya está. Sencillo, ¿no? Pues veamos un par de ejemplos:

   1: public bool SaveToXML(Foo foo)
   2: {
   3:     bool retValue = false;
   4:     FileStream file = null;
   5:     try
   6:     {
   7:         DataContractSerializer dcs = new DataContractSerializer(foo.GetType());
   8:         file = new FileStream(@"fooPath", FileMode.Create);
   9:         dcs.WriteObject(file, galleryManager);
  10:         retValue = true;
  11:     }
  12:     catch ( Exception ex )
  13:     {
  14:         //...
  15:     }
  16:     finally
  17:     {
  18:         if ( file != null )
  19:         {
  20:             file.Close();
  21:         }
  22:     }
  23:     return retValue;
  24: }

Y ahora otro ejemplo para abrir un fichero y deserializarlo:

   1: public Foo LoadFromXML()
   2: {
   3:     FileStream file = null;
   4:     Foo foo = null;
   5:     try
   6:     {
   7:         DataContractSerializer dcs = new DataContractSerializer(Foo.GetType());
   8:         file = new FileStream(@"FooPath", FileMode.OpenOrCreate);
   9:         foo = (Foo)dcs.ReadObject(file);
  10:     }
  11:     catch (Exception ex)
  12:     { }
  13:     finally
  14:     {
  15:         if (file != null)
  16:         {
  17:             file.Close();
  18:         }
  19:     }
  20:     return foo;
  21: }

Con estas dos funciones ya podemos escribir y cargar datos del XML de nuestra clase serializada Foo.

[WCF] Implementando objeto serializable ( I )

Siguiendo con la serie de artículos sobre SilverLight, ahora toca explicar cómo se puede serializar un objeto. Recordemos que en el primer artículo mencioné dos problemas que me encontré a la hora de desarrollar la aplicación en SilverLight:

  • - Problemas derivados del baile de versiones entre ASP4, .NET4 y SilverLight (resuelto en el artículo anterior)
  • - Imposibilidad de usar Xml.Serialize para emplear la serialización de objetos. (que es a lo que vamos ahora)

Como solución al primer apartado empleé Windows Communication Foundation para levantar un servicio web que sea consumido por la aplicación web SilverLight sin que haya ningún problema. Ahora toca explicar cómo podemos serializar nuestros elementos de lógica mediante WCF.

En primer lugar debemos colocar en la clase a serializar la etiqueta de DataContract, que permite agregarle tres tipos de atributos:

  • IsReference: Por defecto está a False, pero si se ajusta a True se garantiza el tipo del objeto mediante una referencia. Para ver un ejemplo, ver este artículo
  • Name: El nombre de la clase.
  • Namespace: El espacio de nombres al que pertence.

Y después en cada propiedad o atributo público que queramos marcar, lo etiquetaremos como DataMember que incluye los siguientes atributos:

  • EmitDefaultValue: Esta propiedad está activa por defecto. Su función es que cuando el miembro al que está asociado tenga el valor por defecto (0, null, etc.) NO se escriba en XML si está con valor FALSE.
  • IsRequired: Indica si este campo debe existir o no. Es conveniente añadirlo para asegurar la compatibilidad de un tipo en futuras versiones.
  • Name: El nombre del miembro en el XML.
  • Order: Indica el orden de serialización que aparecerán en el XML.
  • TypeId: Indica el tipo de objeto que se emplea durante el proceso de serialización. Es conveniente indicarlo cuando trabajamos con jerarquías de herencia.

Ahora veamos un ejemplo. Tenemos una clase Foo que vamos a serializar y sus miembros:

   1: [DataContract()]
   2: public class Foo
   3: {
   4:     [DataMember()]
   5:     public int x;
   6:  
   7:     [DataMember()]
   8:     public int y;
   9:  
  10:     //...
  11: }

Por defecto se serializará tal cual está indicado (primero la clase Foo, los valores X e Y por este orden con los valores por defecto, etc). Pero podemos introducir atributos en el miembro para especificar lo contrario, como por ejemplo:

   1: [DataContract()]
   2: public class Foo
   3: {
   4:     [DataMember("Name=XMember, Order = 1"]
   5:     public int x;
   6:     
   7:     [DataMember("Name=YMember, Order = 0"]
   8:     public int y;
   9: }

Lo cual implicaría un XML parecido al siguiente:

<xml def…/>

<Foo>

<YMember>0</YMember>

<XMember>0</XMember>

</Foo>

Los nombres de los atributos públicos han sido etiquetados de forma distinta y además, en el orden inverso a la aparición de código ya que hemos especificado un orden distinto a través del atributo correspondiente.

martes, 10 de agosto de 2010

[SilverLight] Implementando Servicios ( II )

Siguiendo con el artículo anterior, ahora mostraré un ejemplo de cómo se pueden implementar servicios empleando WCF para que sean consumidos por una aplicación de SilverLight.

Implementar un servicio en WCF es muy similar a un servicio web “de toda la vida”, pero tiene unas diferencias de funcionamiento leves. En primer lugar, en mi proyecto web voy a agregar el servicio:

image

Una vez que ya está agregado nuestro servicio, que será el encargado de obtener los datos de una clase serializados mediante WCF con xml situados en el lado servidor podremos apreciar indicar qué operaciones queremos que aparezcan en la especificación del servicio como funciones mediante la siguiente etiqueta:

   1: [OperationContract]
   2: public void DoWork()
   3: {
   4:     // Add your operation implementation here
   5:     return;
   6: }

OperationContract permitirá que esa función sea consumida externamente. A la operación le podemos especificar una serie de parámetros de WCF para cambiar el nivel de seguridad, el nombre, etc. En otro artículo hablaré de estos parámetros, ya que ahora no nos ocupa.

Volviendo a nuestro servicio, ahora simplemente tenemos que implementar los métodos marcándolos siempre con OperationContract. Una vez los tengamos, compilamos el servicio para asegurarnos que no haya ningún problema en la ejecución por parte del servidor:

image

Y procedemos a agregarlo como referencia de servicio a nuestra aplicación para que lo pueda consumir:

image

Prácticamente el paso anterior es el mismo para un servicio web. Ahora, vamos a la aplicación de SL para trabajar con el servicio:

   1: GalleryService.GalleryServiceClient cliente = new GalleryService.GalleryServiceClient();

Si despleguamos con IntelliSense los métodos que proporciona el cliente del servicio web, veremos que por cada método que hemos incluido se ha creado un par de métodos (aquí es donde tal vez radica la mayor diferencia respecto a un servicio web convencional):

  • MétodoAsync: Este método se emplea para consumir el respectivo método del servicio web. El problema, es que pese a que nosotros habremos indicado en algún método que devuelva algo (por ejemplo un string, int, arrays, etc) el Async siempre devuelve void. ¿Como obtenemos por lo tanto el valor devuelto?
  • MétodoCompleted: Este es un evento que ocurre cuando la llamada al método respectivo Async ha finalizado y por lo tanto ya tenemos la totalidad el valor devuelto. A través de los parámetros de este evento obtendremos el resultado. El código sería como sigue:
   1: //GalleryCliente es nuestro cliente de servicio WCF
   2: //asignamos el delegado del evento a un metodo privado nuestro
   3: this.galleryClient.GetGalleryNamesCompleted += new EventHandler<GetGalleryNamesCompletedEventArgs>(galleryClient_GetGalleryNamesCompleted);
   4: //invocamos al metodo en si
   5: this.galleryClient.GetGalleryNamesAsync();

El método GetGalleryNames devuelve un array de string. Esos datos irán a un comboBox, por lo tanto en el evento tendremos lo siguiente:

   1: void galleryClient_GetGalleryNamesCompleted(object sender, GetGalleryNamesCompletedEventArgs e)
   2: {
   3:     comboGalleries.Items.Clear();
   4:     for (int i = 0; i < e.Result.Count; i++)
   5:     {
   6:         comboGalleries.Items.Add(e.Result[i]);
   7:     }
   8: }

A través del parámetro del evento disponemos de las siguientes propiedades:

  • Cancelled: Indica si la ejecución del método se ha cancelado.
  • Error: La excepción que ha ocurrido durante la ejecución del método.
  • Result: El valor devuelto (puede ser único o colecciones, según lo que hayamos especificado).
  • UserState: Obtiene un identificador único de la ejecución del método.

En el ejemplo, únicamente emplearé la propiedad Result para añadir los elementos del array al comboBox.

Con todo esto ya tenemos nuestro servicio WCF disponible y una aplicación SL que lo consuma correctamente.

[SilverLight] Implementando Servicios (I)

Actualmente ando liado haciendo mi primera aplicación web y mi primera aplicación SilverLight; ya que hago algo que sea a lo grande y a lo bestia para empezar en lugar de ir poco a poco…

En el caso que me ocupa ya publicaré la aplicación cuando esté terminada, pero dedicaré este artículo a hablar un poco sobre SilverLight y el modo en que se trabaja, que es ligeramente distinto si nunca has trabajado más allá de una aplicación de escritorio e incluso más allá de una aplicación ASP.NET.

En primer lugar, partimos de la base que SilverLight (en adelante SL) posee sus propias versiones de librerías y que los proyectos de SL son incompatibles con proyectos no-SL. Es decir, si deseas usar una librería para tu aplicación SL deberá ser una librería de SL, será imposible usar una librería de clases estándar. Como parte positiva de esta característica tan peculiar tenemos el bajo acoplamiento de la aplicación SL respecto a otros objetos, pero por contra obtenemos un modo de trabajo un tanto peculiar. En la aplicación que estoy desarrollando, además de la propia lógica que incluye empleo la serialización de entidades. El problema principal con el que he topado han sido los conflictos de DLL entre ASP y SL y que por motivos de seguridad, SL impide realizar cualquier acceso a disco.

Pero vayamos por partes: ¿podemos usar System.Xml.Serialize para serializar nuestras entidades como si de una aplicación de .NET normal se tratase? Evidentemente que sí, pero con el problema de que no podremos usar XmlSerializer para el proceso de seralización y no podemos usar los streams para acceder a disco. Para solucionar el tema del acceso a disco usaremos servicios web, pero para la serialización algunas de las soluciones que he visto por los foros se basan en:

  • No podemos usar XmlSerializer: No pasa nada, implementamos una función que lea el fichero y en función de los nodos y etiquetas asigne los valores correspondientes. Incoveniente: no es genérico; para cada tipo de entidad hay que readaptar la función para obtener los nodos correspondientes. O bien se implementa un propio XmlSerialize para SL que sea genérico.
  • Problemas de DLL’s: El hecho de usar XmlSerialize implicará conflictos de DLL’s entre las entidades a serializar de lógica de SL y la DLL del servicio web. Algunas de las soluciones se basan en copiar la DLL que falta a mano e incluso en añadir una clave al GAC (Global Assembly Cache) con la referencia de la DLL solicitada. Esta última solución me parece un absoluto hecatombe para la sensibilidad humana, por le siguiente escenario: Supongamos que cojo mi aplicación y la subo a un hosting. Es evidente que en el hosting tendré los permisos de administrador supremo para realizar esas tareas, y si así fuera, no hay nada mejor que una aplicación mantenible que requiere de la pericia de copiar y pegar DLL’s no soportadas por el Framework estándar para que nuestra aplicación pueda ejecutarse correctamente.

Entonces, si no podemos usar XmlSerializer pero queremos serializar para comunicarnos con nuestra lógica y acceder a disco, ¿qué podemos usar? Pues el maravilloso Windows Communication Foundation, que es una API orientada a proporcionar comunicación entre todos los servicios y aplicaciones desarrolladas con .NET. En el próximo artículo expondré un artículo práctico sobre cómo WCF con SL.

viernes, 6 de agosto de 2010

[XNA] Acelerómetro en Windows Phone 7

Desde el día 4 de agosto disponemos en XNA Creators Club de un par de tutoriales que explican cómo usar el acelerómetro con XNA en Windows Phone 7.

El primer tutorial implementa una clase que gestiona el acelerómetro y actualiza la posición de un sprite en pantalla en función de los datos capturados por este sensor.

El segundo tutorial consiste en el tratamiento de colisiones para simular un sistema de físicas donde las esferas se modelan con algo de elasticidad y se implementa la fricción entre ellas para calcular los vectores de fuerza. En este caso el acelerómetro actúa de generador de vector de gravedad.

martes, 3 de agosto de 2010

[VS2010] IntelliTrace ( II )

IntellITrace también ofrece un soporte avanzado para aquellas situaciones en las que todo desarrollador sufre alguna vez en la vida. Supongamos el siguiente escenario, donde nuestra aplicación produce un fallo que no ha sido detectado y procedemos a debuggear el código…pero no logramos localizar el fallo. En ese caso podemos emplear la característica de IntelliTrace de guardar una captura de debug. Para ello lo primero que debemos hacer es indicarle que deseamos guardar la traza:

image

Una vez hecho esto, prestemos especial atención a la casilla de Team Foundation Server. Esto permitirá que Team Foundation Server (TFS) recoja mediante el TestManager las capturas de debug y las envíe a los tester mientras el desarrollo continúa. En estas capturas no es sólo un volcado común de pila, sino es un conjunto de estados en los que la aplicación ha ido alterando a lo largo del tiempo. De este modo podremos ver los eventos y llamadas en cualquier momento anterior al presente, como se expuso en el primer artículo.

El siguiente paso es abrir el fichero .itrace. Al abrirlo, podemos apreciar una captura como la que sigue a continuación del siguiente párrafo:

image

Podemos expandir los campos para ver la información de hilos, excepciones, módulos y datos de testing. Al hacer clic sobre un hilo se cargan todos los eventos ocurridos y si por ejemplo, hacemos clic en cualquier elemento (como una excepción) automáticamente nos llevará al estado en el que se produjo, y ya podremos navegar por IntelliTrace al igual que se mostró en el primer artículo.

Por último resalto la posibilidad de aplicar extensiones a IntelliTrace. A través de MSDN obtenemos toda la información necesaria del API para analizar la recolección de datos y aquí podemos obtener algunos ejemplos prácticos.

[VS2010] IntelliTrace ( I )

Mientras voy trabajando con Visual Studio 2010 voy usando algunas de las nuevas mejoras, entre ellas IntelliTrace. Esta herramienta sólo está disponible con Visual Studio 2010 Ultimate, es decir que ni la versión Express ni la Professional la incluyen.

Generalmente al desarrollar cualquier software se emplea cientos de veces el debugger del IDE para averiguar qué ha ocurrido para que el software tenga un comportamiento anómalo o distinto de lo diseñado. En este caso el sistema es simple: introducimos breakpoints en el código y a través del análisis de las variables locales y de la pila de llamadas vamos analizando la secuencia del flujo de programa e investigando a través de los valores locales qué es lo que ha podido ocurrir. Sin embargo, muchas veces hemos perdido el tiempo colocando el breakpoint en el lugar adecuado. En determinadas ocasiones queremos ver por qué hemos llegado a determinado punto, y eso obliga  a que si ese punto en concreto no lo hemos marcado como breakpoint no podemos retornar a él salvo que cancelemos la ejecución actual, marquemos ese punto como breakpoint y volvamos a ejecutar para ver qué ha podido ocurrir. En una aplicación pequeña no supone mucho esfuerzo salvo por la incomodidad de tener que terminar la depuración y volver a compilar/ejecutar, pero si la aplicación es grande y consume bastantes recursos, nos conviene optimizar dicho tiempo para evitar perderlo. Resumiendo, podemos debuggear sólo en el punto donde tenemos puesto el breakpoint y seguir la secuencia de eventos.

Es a partir del punto anterior donde nace la principal ventaja de IntelliTrace: podemos retroceder al “pasado” y ver todos los eventos que ocurren únicamente dentro de ese contexto para poder observar realmente lo que pasa dentro de él. De este modo, podemos evitar los incómodos rearranques con nuevo ajuste de breakpoint para averiguar lo que ocurre dentro de ese contexto.

 

image

La imagen superior es la ventana de IntelliTrace. Aparece en cuanto comenzamos a depurar la aplicación, mediante un breakpoint y está junto al explorador de soluciones. En un primer vistazo a la ventana apreciamos dos estados: el inicio de la aplicación y el estado actual, donde reside el breakpoint. Podemos configurarlo de modo que sólo trabaje con determinadas categorías (ADO,ASP, Registro, Ficheros, etc) y también especificar en qué hilos queremos que IntelliTrace analice la depuración.

Si hacemos clic en cualquiera de los pasos de la imagen anterior, podemos analizar el estado de las variables en ese paso y el estado de la pila de llamadas:

image

Además podemos personalizar cómo queremos que realice la exploración. Por ejemplo, podemos indicarle que además de analizar todo lo que hemos visto hasta ahora, que analice también la secuencia de llamadas, que es el modo “avanzado” de analizar que dispone. Para ello bien podemos ir al icono de configuración de IntelliTrace o a través de opciones de Visual Studio 2010:

image

Dándole un vistazo por las opciones de configuración de IntelliTrace, podemos seleccionar qué módulos queremos que sean analizados, el tamaño del fichero donde se almacena el análisis y qué eventos queremos incluir en el análisis. En la sección General de la configuración de IntelliTrace, seleccionando eventos e informaciones de llamada, podemos obtener más datos de depuración. Como ventaja es que se almacena cada llamada, salida y valor de parámetros. En el caso de que un parámetro sea un array, sólo almacena las 256 primeras posiciones. Y en el caso de que sea un objeto, sólo almacena la información más relevante.

image