127.0.0.1: Hogar dulce hogar
Mostrando entradas con la etiqueta asp. Mostrar todas las entradas
Mostrando entradas con la etiqueta asp. Mostrar todas las entradas

jueves, 9 de septiembre de 2010

[SilverLight] Integración con HTML

Uno de los temas más complicados o que por el momento no parece que tenga una solución clara es integrar HTML normal con una aplicación de SilverLight. Me explico con un sencillo ejemplo: supongamos el escenario de una aplicación en la que tenemos dentro un mininavegador donde podemos acceder a otras páginas. ¿Es posible? Evidentemente. ¿Es una solución bonita? En mi modesta opinión, no. ¿Y por qué voy a hablar de ello? Porque no he encontrado otras soluciones…

Como primera medida encuentro la solución que se propone a través de este tutorial, empleando un control WebBrowser al que mediante su propiedad Source le podemos indicar el código html a carga. Podemos indicarlo mediante un típico enlace a página, creando un URI o bien añadiendo en el string el código html “a pelo”. El problema de todo esto es que para que el objeto WebBrowser funcione debe ejecutarse fuera del navegador (es un requerimiento del propio objeto). Si queremos que a través del propio navegador usemos html, tenemos la siguiente opción.

Esta opción consiste en un tipo de fuerza bruta. Como principio básico conocemos que SilverLight no puede procesar el código HTML desde dentro del navegador, por lo que nuestra solución pasa por añadir un iframe desde el cual carguemos el código HTML y separarlo de la propia aplicación SilverLight (pero dentro de la misma aplicación ASP). El método es simple: creamos un tag div en la página principal, introducimos el iframe (podemos acceder a él a través del DOM) y le asignamos coordenadas absolutas, de forma que aparezca encima de la aplicación SilverLight:

   1: <iframe id="iframeReport" style="position:absolute;top:120px;left:0px;width:200px;height:200px;visibility:hidden;margin-left:15px;" src="http://www.google.com/"></iframe>
   1: System.Windows.Browser.HtmlElement myFrame = System.Windows.Browser.HtmlPage.Document.GetElementById("iframeReport"); 
   2: myFrame.SetStyleAttribute("visibility",

Evidentemente hay varios componentes que intentan simular el comportamiento del HTML (como por ejemplo este), pero sin soporte oficial por parte del equipo de desarrollo de SilverLight.

[Web] WebMatrix

WebMatrix es un producto destinado al desarrollo web orientado a estudiantes y gente que aún no tiene un conocimiento muy amplio de la materia. Incluye todo lo necesario para comenzar:

  • IIS Developer Express: Un servidor web de desarrollo sobre el que podremos comprobar cómo funciona nuestra web.
  • ASP.NET: Nuestro querido framework para desarrollar web.
  • SQL Server Compact: Una base de datos embedida.

En cuanto a la aplicación, dispone de la interfaz Ribbon (famosa por ser la interfaz de Office 2007 y usada en la mayoría de software incluido Windows 7) y acceso directo a Visual Studio para poder desarrollar mejor la web.

Es un producto en fase beta, por lo que es muy posible que tenga algún fallo o cosilla que sea necesaria depurar. Por todo lo demás, pienso que es una buena idea el despojar de la complejidad el desarrollo web para pequeños sitios y en especial para todos aquellos que quieran aprender poco a poco y paso a paso antes de pasar por otro tipo de soluciones bastante más complejas.

Aquí os dejo el enlace:

http://www.microsoft.com/web/webmatrix

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 ( 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.