Además - Tecnología, Tips y Programación por Sergio Gonzalez
Transcripción
Además - Tecnología, Tips y Programación por Sergio Gonzalez
nº31 Noviembre 2006 • 6,50 € (España) Visual Basic • C# • ASP.NET • ADO.NET • .NET Framework • Windows Server System dotNetManía www.dotnetmania.com Dedicada a los profesionales de la plataforma .NET TodotNet QA Más allá del mito Discusión sobre AJAX y ATLAS Eventos EuroDevCon 06 y EKON 10 Frankfurt, Alemania Laboratorio TestRunner for Visual Studio 2005 Fundamentos de AJAX. Cómo utilizarlo sin ayudas externas• AJAX con ASP.NET 2.0. Script callbacks• AJAX, redefiniendo la forma de ver la Web • Microsoft AJAX Library (Atlas). Cómo extender ASP.NET con lo más “cool” de la Web 2.0 Además Relación entre delegados y eventos El avisador que te avise, buen avisador será Presentación de SharePoint opinión Orientación al producto versus orientación al procedimiento dnm.editorial dotNetManía Dedicada a los profesionales de la plataforma .NET Vol. III •Número 31 • Noviembre 2006 Precio: 6,50€ Eventos, eventos, eventos... Editor Paco Marín ([email protected]) Editor técnico Octavio Hernández ([email protected]) Consejo de Redacción Dino Esposito, Guillermo 'guille' Som, José Manuel Alarcón, Lorenzo Ponte, Luis Miguel Blanco y Miguel Katrib (Grupo Weboo). Colaboradores habituales Antonio Quirós, Braulio Díez, Carlos Quintero, Eladio Rincón, Javier Aragonés, Jorge Serrano, José Miguel Torres, Iván González, Pepe Hevia, Salvador Ramos y Sergio Vázquez Además colaboran en este número Gustavo Vélez, Hadi Hariri, Miguel Jiménez y Román Fresneda Atención al suscriptor Pilar Pérez ([email protected]) Ilustraciones Yamil Hernández Edición, suscripciones y publicidad .netalia c/ Robledal, 135 28529 Rivas-Vaciamadrid (Madrid) www.dotnetmania.com Tf. (34) 91 666 74 77 Fax (34) 91 499 13 64 Imprime GRUPO MARTE ISSN 1698-5451 Depósito Legal M-3.075-2004 >> << Eventos, eventos, eventos... Para cuando tenga este ejemplar en sus manos ya se habrá celebrado el CodeCamp en El Escorial –les contaremos todo el mes que viene–; a principios de noviembre tenemos el Tech–Ed Europe en Barcelona, que este año se celebra conjuntamente con el IT Forum; coincidiendo con éstos se celebra en Madrid el SIMO, donde se presentará Windows Vista y 2007 Microsoft Office System en su versión empresarial; inmediatamente después, el 13 de noviembre nos visita David Chappell, que participará en la conferencia sobre SOA y Business Process que ofrece gratuitamente Microsoft Ibérica; terminando noviembre, se celebra expoQA, un evento para profesionales de la ingeniería, la calidad y las pruebas de software; y también la sexta edición de la feria MovilForum, donde los desarrolladores pueden entrar en contacto con los clientes de Movistar. ¡Qué hartazón de eventos, amigo! Bienvenido al número 31, de noviembre de 2006, de dotNetManía. Creo (aunque esté mal que yo lo diga) que nos ha quedado un estupendo especial sobre AJAX, tecnología imprescindible para el desarrollo de las aplicaciones Web de hoy y de mañana. Claro que en realidad el mérito es de los autores. José Manuel Alarcón nos explica los fundamentos de AJAX y los script callbacks, sin hacer referencia a implementación alguna; Miguel Katrib y Román Fresneda usan la implementación conocida como Ajax.NET (The Free Library for .NET), de Michael Schwarz; Miguel Jiménez presenta la implementación de Microsoft, Microsoft AJAX Library (antes conocida como Atlas), ahora ya en beta 1; y, por último, Dino Esposito, con el espléndido título “Más allá del mito. Discusión sobre AJAX y ATLAS”, ha agrupado preguntas relacionadas con el tema que nos ocupa. ¡Gracias a los cinco! Si aún no sabe para qué sirve Sharepoint, le recomiendo que se lea el artículo de Gustavo Vélez, al que doy la bienvenida por su primera colaboración, “Presentación de Sharepoint”. Ajeno a la AJAXManía de este número, El Guille continúa apuntalando los fundamentos de .NET, esta vez con las relaciones entre delegados y eventos, con su “Relación entre delegados y eventos. El avisador que te avise, buen avisador será”. Hadi Hariri, fundador del grupo de usuarios .NET de Málaga, se nos marchó a Frankfurt al EuroDevCon 06 y EKON 10 –eventos para desarrolladores de Borland– como ponente y también como reportero de esta revista. Desde allí nos mandó sus impresiones. Por último, no quiero terminar sin antes agradecer el esfuerzo extra realizado por Yamil Hernández, quien ha ilustrado la portada y algunos artículos interiores de este especial con su versión de Ajax, el héroe griego. Y esto es prácticamente todo por este mes. Espero que le resulte útil. Paco Marín <<dotNetManía Redactor Jefe Marino Posadas ([email protected]) 3 31 dnm.sumario EuroDevCon 06 y EKON 10 08 Coincidiendo con el reciente lanzamiento de la línea de productos Turbo de Developer Tools Group (una división de Borland), tuvo lugar en Frankfurt, Alemania, del 25 al 29 de septiembre, la décima edición de la Entwickler Konferenz (EKON), combinada con la sexta Euro Developer Conference (antigua European BorCon). Métricas para la evaluación de procesos de construcción de software 10-11 En la anterior entrega cogimos el metro para estimar la carga de trabajo necesaria a fin de realizar un proyecto de construcción de software. Medimos, diseñamos, construimos y ahora vuelve a tocar sacar el metro del bolsillo para comprobar si lo que hemos realizado se corresponde con lo que planificamos, así como para verificar si el proceso de construcción ha seguido las normas adecuadas y/o si tenemos evidencias de que no habrán demasiados defectos que compliquen el mantenimiento futuro del mismo. Fundamentos de AJAX. Cómo utilizarlo sin ayudas externas 13-19 Si hay una palabra de moda últimamente en el mundo del desarrollo Web, ésta es sin duda AJAX. En este artículo vamos a aprender sus fundamentos, independientes de la tecnología de servidor utilizada. Ello nos será útil para comprender mejor las nuevas bibliotecas especializadas (como Atlas) y evitar posibles errores. AJAX con ASP.NET 2.0. Script callbacks 20-24 dnm.sumario La reciente versión 2.0 de ASP.NET ofrece una nueva técnica para implementar páginas AJAX pero usando métodos nativos de servidor. Nos abstrae de la mayor parte de las complejidades asociadas al código de script de cliente, limitándose nuestra aportación en este sentido a procesar los resultados devueltos. En este artículo veremos cómo funcionan los script callbacks. AJAX, redefiniendo la forma de ver la Web 26-34 AJAX es el nombre con que se ha "popularizado" a un grupo de tecnologías que juntas han cambiado la forma en que vemos la Web. AJAX abre la posibilidad de invocar asíncronamente desde Javascript a código del lado del servidor en una aplicación Web, usando XML como transporte (aunque se verá que esto último no es necesariamente así). Microsoft AJAX Library (Atlas). Cómo extender ASP.NET con lo más "cool" de la Web 2.0 35-40 La combinación tecnológica de XHTML, CSS, Javascript y XMLHttpRequest, acuñada bajo el término AJAX desde 2005, representa la fórmula mágica de la poción que está revolucionando el concepto de la Web. Los desarrolladores de ASP.NET pueden unirse a la cruzada tecnológica gracias a Microsoft AJAX Library, una extensión de ASP.NET que proporciona la funcionalidad deseada desde la comodidad del .NET Framework 2.0 y Visual Studio 2005. Presentación de SharePoint 41-44 SharePoint es el servidor con el crecimiento más acelerado de todos los productos de Microsoft. Éste es un artículo introductorio sobre el producto, su arquitectura, programabilidad y la nueva versión que aparecerá en corto plazo. Relación entre delegados y eventos. El avisador que te avise, buen avisador será 45-50 En el número anterior vimos con detalle casi todo lo concerniente a los delegados, y aunque solo lo viésemos de pasada, comprobamos la relación entre los delegados y los eventos. En este número nos centraremos en los eventos, pero antes comprobaremos que hay ciertas características de los delegados que los hacen imprescindibles para usarlos con los eventos. dnm.todotnet.qa Más allá del mito. Discusión sobre AJAX y ATLAS 51-53 Las extensiones AJAX constituyen la siguiente gran novedad en el desarrollo de ASP.NET, como puede ver el lector en este número de la revista. En esta columna responderé algunas cuestiones que he recogido en las pasadas semanas, tratando de hacer una introducción al mundo AJAX de forma suave y gradual. dnm.laboratorio TestRunner for Visual Studio 2005 dnm.biblioteca.net 54 55 Programación con ASP.NET 2.0. Jesse Liberty y Dan Hurwitz Fundamentos de Bases de datos con Visual Basic 2005. Thearon Willis dnm.desvan 58 6 noticias.noticias.noticias.noticias.noticias.noticias << dotNetManía << dnm.noticias Feria movilforum 2006 Al día con versiones beta La Feria movilforum es el gran evento movistar dedicado a presentar los últimos desarrollos ligados con la movilidad y enfocado a generar negocio poniendo en contacto a los desarrolladores con los clientes de movistar. Beta 1 del Developer Kit para .NET Micro Framework Más de 50 empresas, entre expositores, colaboradores y patrocinadores estarán presentes en esta edición, una edición que contará con numerosas novedades y una fuerte presencia internacional. Presentará un área de exposición sectorizada en cinco grupos de actividad: Construcción, Industria y Telecomunicaciones, Distribución, Logística y Transporte; Medios de Comunicación, Ocio y Turismo; Sanidad y Administraciones Públicas; y Seguridad y Banca. Una oferta que se ampliará con los productos y promociones de las empresas patrocinadoras y colaboradoras. Otro aspecto destacable es el hecho de que movilforum se extiende por América Latina como un medio de apoyar a clientes movistar a través del foro que soporta tanto tecnológica como comercialmente a empresas desarrolladoras. Una iniciativa que tendrá una importante presencia en la feria de este año gracias a la participación como expositor de empresas pertenecientes a movilforum Latinoamérica y a través de diversas actividades, que en un futuro próximo tendrán correspondencia como oportunidades en los países del entorno de Latinoamérica. De la misma manera, a través de los productos y desarrollos presentados por la empresa O2, que se encontrará entre los colaboradores, los visitantes podrán conocer en qué estado se encuentra el mercado de los aplicativos móviles en otros países europeos. A través de la presencia de los responsables de Telefónica Móviles España en ponencias, foros sectoriales y mesas redondas temáticas, podrán recoger de primera mano la visión de la situación del mercado de telefonía móvil y sus tendencias de evolución futura. Más información en www.feria. movilforum.com. CATÁLOGO MOVILFORUM MovilForum presenta el nuevo Catálogo de Soluciones Móviles, que reúne más de 220 productos desarrollados por 70 empresas miembro. El catálogo se ha dividido en una guía de soluciones de movilidad y una colección de 9 catálogos sectoriales. El Catálogo de Soluciones Móviles está accesible para todos aquellos interesados en la movilidad a través de www.movistar.es/empresas/servicios. Presentación de Windows Vista y 2007 Microsoft Office System en SIMO 2006 La edición 2006 de la feria teccompañía en la feria, que este año nológica SIMO ha sido el marco ocupa el Pabellón 2 de IFEMA en elegido por Microsoft para realizar su totalidad. Para ello, Microsoft el lanzamiento a empresas de dos de contará con un auditorio en el que los productos insignia de la comse realizarán presentaciones y sesiopañía: Windows Vista y 2007 nes demo, con capacidad para alberMicrosoft Office system. gar a 1.500 personas. El anuncio oficial de estos PRESENTACIONES Presentación para empresas: martes 7 a las 17.00 horas productos Presentación para profesionales TI: miércoles 8 a las 10.30 horas tendrá lugar en Presentación para desarrolladores: miércoles 8 a las 16.00 horas el stand de la Microsoft hizo este anuncio en el marco de la Embedded Systems Conference en Boston. El nuevo Micro Framework permite a los desarrolladores construir aplicaciones para dispositivos muy pequeños (limitados por el coste, la memoria, el procesador y/o el consumo de energía) como sensores, monitores corporales para la atención médica, automatización del hogar, controles remotos, etc. Puede ver más información en la crónica del MEDC de Niza, publicada en el número 28, de julio-agosto, de dotNetManía y en http://www.aboutnetmf.com. Visual Studio 2005 SP1 Beta Microsoft ha anunciado la disponibilidad de la primera beta del service pack 1 para Visual Studio 2005. Una vez recibidos los comentarios de esta beta por los usuarios, aproximadamente dentro de unos 3 ó 4 meses estará lista la versión definitiva. Si quiere información técnica de esta beta y descargas diríjase a http://connect.microsoft.com/VisualStudio. ASP.NET AJAX Beta 1 Microsoft ha anunciado la Beta 1 de ASP.NET AJAX v1.0 (antes ATLAS). La idea es sacar una nueva beta en unas pocas semanas, después una release candidate y finalmente la versión final 1.0, que aún no tiene fecha oficial. Más información y descargas en: http://ajax.asp.net. Presentación de esta beta por Scott Guthrie en su blog: http://weblogs.asp.net/scottgu/archive/2006/10/20/ASP.NET-AJAX-Beta-1Released.aspx. Virtual PC 2007 Beta 1 Virtual PC 2007 Beta 1 está disponible para su descarga en: https://connect. microsoft.com/programdetails.aspx?Program DetailsID=874. Virtual PC 2007 está optimizado para trabajar correctamente con Windows Vista. dnm.noticias Tercera edición de expo:QA, Jornadas de Calidad y Testing de Software expo:QA consolida su presencia en el sector de la calidad y el testeo del software anunciando su 3ª edición los próximos 27, 28, 29 y 30 de noviembre en el Hotel Meliá Barajas de Madrid. expo:QA responde a la necesidad de crear en España un espacio especializado, donde los profesionales de la ingeniería, la calidad y las pruebas de software puedan compartir conocimientos. Es un lugar de encuentro para descubrir las últimas soluciones, conocer prácticas reales y compartir experiencias con expertos en temas de automatización del testeo, gestión de procesos de desarrollo, gestión de proyectos y testeo de software, entre otros temas. Las jornadas están dirigidas a directores de desarrollo, responsables de proyectos, gerentes de calidad y profesionales de TI. En estas jornadas podrán disfrutar de: • Presentaciones y exposición de las empresas más importantes de la indus- tria: Borland, Compuware, TCP, Telelogic, PRQA, Mercury, Gesein, inQA.labs, Microsoft e IBM, siendo estos dos últimos los patrocinadores Premium del evento. • Conferencias técnicas impartidas por destacados profesionales del sector. • Taller “Hands On” de soluciones de calidad y testeo de software de la compañía Mercury. • Cursos para los profesionales que quieran ampliar sus conocimientos en temas de calidad y testeo de software, impartidos por especialistas que abordarán temas actuales y prácticos. inQA:labs, el equipo organizador de expo:QA busca asociaciones, entidades, instituciones, universidades y medios de comunicación involucrados en el sector de las TIC e interesados en fomentar la calidad del software en España para apoyarle en la iniciativa de la expo:QA 2006. Si está interesado o necesita más información no dude en contactarnos en [email protected] (www.expoqa.com) o al teléfono +34-932917632. Tech-Ed 2006 Developers e IT Forum Tech-Ed 2006 Developers se celebrará en Barcelona entre los días 7 al 10 de noviembre. Este evento es el más importante que se realiza en la zona EMEA para desarrolladores y arquitetos de software que usan tecnologías de Microsoft. Más información en: http://www.ms eventseurope.com/TechEd/06/pre/defaultdev.aspx. Tech-Ed 2006 IT Forum se celebrará también en Barcelona entre los días 14 y 17 de noviembre. Este evento está diseñado para profesionales TI. Más información en: http://www.ms eventseurope.com/TechEd/06/pre/defaultitf.aspx. Microsoft organiza la conferencia de SOA y Business Process con la participación de David Chappell Microsoft celebra el 13 de noviembre, en las instalaciones de Microsoft en Pozuelo de Alarcón (Madrid), la conferencia de SOA y Business Process Management (BPM) para proporcionar una mayor perspectiva sobre estas áreas y una visión general de las tecnologías de Microsoft como WCF (Windows Communication Foundation), BizTalk Server y Windows SharePoint Services. La finalidad de este encuentro, dirigido a los responsables de la toma de decisiones en TI, arquitectos, desarrolladores, administradores de TI y otros interesados en ampliar sus conocimientos, es intercambiar información y experiencias sobre estos productos de servidor para la construcción de soluciones de proceso de negocios e integración. Para ello, se contará con la participación especial de David Chappell, quien analizará el mercado actual y examinará tanto los beneficios potenciales como la inversión requerida para lograr el éxito empresarial. Los interesados en registrarse al evento pueden hacerlo directamente a través de la dirección Web http://www.microsoft.es/biztalk o en el teléfono 902 197 198. David Chappell David Chappell, Principal de Chappell & Associates (www.davidchappell.com) en San Francisco, ha participado en numerosos eventos y conferencias en Estados Unidos, Europa, Asia y Latinoamérica, y a sus seminarios han asistido decenas de miles de desarrolladores, arquitectos, y responsables de la toma de decisiones de 40 países. Los libros de Chappell sobre software empresarial se han publicado en diez idiomas y se han utilizado en ciertas carreras del MIT, la ETH de Zurich y docenas de otras universidades. Y en sus prácticas de consultoría, ha ayudado a clientes de la talla de Hewlett-Packard, IBM, Microsoft, Universidad de Stanford y Target Corporation a adoptar nuevas tecnologías, comercializar nuevos productos, formar al personal de ventas y crear planes de negocio. dnm.noticias << dotNetManía David Chappell participará en este evento para facilitar una amplia perspectiva de las tecnologías de Microsoft en SOA y BPM, así como los beneficios que se obtienen al utilizar Microsoft BizTalk Server 7 dnm.directo.eventos Hadi Hariri EuroDevCon 06 y EKON 10 Coincidiendo con el reciente lanzamiento de la línea de productos Turbo de Developer Tools Group (una división de Borland), tuvo lugar en Frankfurt,Alemania, del 25 al 29 de septiembre, la décima edición de la Entwickler Konferenz (EKON), combinada con la sexta Euro Developer Conference (antigua European BorCon). << Un cambio muy significativo fue la presencia de numero- Hadi Hariri es desarrollador y ponente habitual en conferencias internacionales sobre .NET y otras tecnologías. Además es el fundador del grupo de usuarios .NET de Málaga y actualmente trabaja en Atozed Software sas personalidades de la división de Developer Tools Group (DTG) de Borland, incluyendo a David Intersimone (evangelista por excelencia), Jason Vokes, Jon Harrison, Gerard van der Pol de EMEA y Nick Hodges, antiguo miembro de TeamB y nuevo Product Manager de Delphi. Después de la inauguración oficial de la conferencia por parte de Massoud Kamali y Sebastian Meyen, de Software & Support Verlag, organizadores del evento, se dio paso al Delphi Product Address, donde Nick Hodges deleitó al público con las novedades del compilador, entre las cuales destacan las clases parciales y los tipos parametrizados (genéricos). Aunque inicialmente estas características serán solo para los compiladores .NET, se mencionó que se estaba estudiando la posibilidad de portar la funcionalidad a Win32 y consecuentemente a los compiladores de 64 bits de Delphi que verán la luz en 2008. Se recalcó que Highlander, la próxima versión de Delphi, estará disponible para el primer cuatrimestre de 2007 y un poco más adelante también verá la luz la VCL para Compact Framework, lo cual supone todo un acontecimiento para los desarrolladores de CF. También se anunció que ECO (Enterprise Core Objects), la plataforma de diseño y generación de código basada en UML de Borland Developer Studio dará soporte para la VCL.NET y no solo para Windows Forms y ASP.NET como hace actualmente. Claramente, se trata de una apuesta de DTG por la VCL.NET y por proporcionar una ruta fácil de migración para sus clientes de Win32 a .NET, sin problemas de compatibilidad. La agenda tenía aproximadamente la mitad de las charlas en inglés y la otra mitad en alemán. Estuvieron presentes ponentes de reconocido prestigio como David Intersimone junto a la tarta del EKON 10 Michael Li, Marco Cantú, Ray Kanopka, Bernd Ua y Neal Ford. En la sección de fabricantes, no faltaron las empresas que asisten todos los años como Atozed Software, Raize Software, IB Experts o Advantage Database iAnywhere, entre otros. Y los Delphi Code Camps fueron una ocasión perfecta para que los asistentes y ponentes intercambiaran opiniones y discutieran cuestiones de actualidad. Otro de los cambios importantes este año fue el énfasis en DTG y no en Borland. La presencia exclusiva de desarrolladores y personas técnicas en el stand de DTG, así como la ausencia de los productos englobados bajo lo que Borland denomina ALM, indicaba claramente el compromiso de DTG de ser una empresa de productos para desarrolladores y cercana a ellos. Al ser el décimo aniversario de EKON, se celebró la ocasión con una fiesta sorpresa, tanto para Massoud Kamali como para los asistentes, con una tarta enorme, así como con la presencia de bailes al más puro estilo de los carnavales de Rio. Obviamente, al haber tenido lugar el evento en Alemania, no faltó en ningún momento la cerveza. dnm.opinion Antonio Quirós Métricas para la evaluación de procesos de construcción de software En la anterior entrega cogimos el metro para estimar la carga de trabajo necesaria a fin de realizar un proyecto de construcción de software. Medimos, diseñamos, construimos y ahora vuelve a tocar sacar el metro del bolsillo para comprobar si lo que hemos realizado se corresponde con lo que planificamos, así como para verificar si el proceso de construcción ha seguido las normas adecuadas y/o si tenemos evidencias de que no habrán demasiados defectos que compliquen el mantenimiento futuro del mismo. << El objetivo es que aprendamos de lo sucedido en los Antonio Quirós es colaborador habitual de dotNetManía. Co-fundador de las revistas clippeRManía, FOXManía y Algoritmo.Actualmente es Director de Operaciones en Alhambra-Eidos proyectos para poder predecir en el futuro lo que sucederá en los nuevos que abordemos. Imaginemos el siguiente caso. Tenemos una compañía que sistemáticamente obtiene una media de defectos en el software que construye que supone un 5% del tiempo total empleado en cada proyecto. Esto quiere decir que cada 100 horas estimadas lo normal es que el equipo necesite 105 para lograr la estabilización del software que ha construido. La estimación de las 100 horas la obtiene con técnicas de medida estándar (puntos por función u otras similares), pero su repositorio histórico de proyectos le indica que el 5% de los defectos es la media de impacto sobre el software que construye. ¿Qué debe hacer en sus siguientes estimaciones? Pues evidentemente, aprender de su historia e incrementar en un 5% su estimación de carga de trabajo necesaria. Si no lo hace así perderá dinero y creará incertidumbre en las expectativas que el cliente tiene en el software que construye, ya que sistemáticamente el tiempo previsto se verá incumplido. Lo que cada empresa o equipo de desarrollo puede medir para lograr este objetivo quizá sea diferente en función del tipo de proyectos que aborde y de sus intereses particulares. En lo que a mí respecta, voy a mencionar a continuación un conjunto de indicadores que usamos (entre otros) en mi compañía y que nos ayudan en las reseñadas facetas de seguimiento y predecibilidad. El objetivo es que aprendamos de lo sucedido en los proyectos para poder predecir en el futuro lo que sucederá en los nuevos que abordemos Desviaciones en las fechas de entrega Este indicador nos proporciona el porcentaje de retraso en los procesos de análisis y construcción. La fórmula que empleamos para el cálculo es: % de retrasos = 100 * (días de retraso / días de duración total) Estabilidad de recursos humanos en proyectos Se trata de medir qué recursos se han mantenido asignados al proyecto durante todo el tiempo inicialmente previsto. Evidentemente, la estabilidad de los recursos y el hecho de que se cumpla que una tarea planificada para un recurso es realizada por dicho << dnm.opinion Promedio diario de producción por proyecto recurso, y no por otro, es una garantía de calidad. La fórmula que empleamos para el cálculo es: % recursos estables = 100 * (recursos estables / recursos totales) Al igual que el anterior, éste no es un indicador de calidad sino de eficiencia de equipo. Lo que trata de medir es el volumen económico medio que la compañía es capaz de facturar cada día. Si el equipo de trabajo es estable, una mejora en este objetivo nos indicaría que la productividad es mejor. Si el equipo crece o disminuye hay que ponderar el indicador con estos cambios. La fórmula que empleamos para el cálculo es: promedio = € de proyectos / días totales tardados en realizar dichos proyectos Defectos en pruebas de aceptación indice defectos = defectos reportados / horas de la aplicación Evidentemente, la aplicación de esta fórmula de cálculo debe hacerse para una unidad de tiempo concreta que permita el seguimiento evolutivo, así tendremos en cuenta, por ejemplo, los proyectos cerrados en un mes, en un trimestre, etc. Utilización de capacidad de desarrollo Al igual que los dos anteriores, éste es un indicador de eficiencia. Trata de medir hasta qué punto tenemos empleados a los recursos de desarrollo de la compañía en proyectos facturables. La fórmula que empleamos para el cálculo es: El empleo en el denominador de las horas que ha costado construir la aplicación tiene como finalidad la de trabajar con una unidad de medida fácil de calcular en cada momento, pero podría sustituirse por los puntos por función totales de la aplicación o por las líneas de código (LOC). Siendo las horas teóricas aquellas que la suma de los desarrolladores de la plantilla pueden realizar excluidas vacaciones. Eficiencia en proyectos de desarrollo Defectos en garantía La eficiencia no es, desde luego, un indicador de calidad, pero sí nos indica hasta qué punto somos productivos haciendo lo que hacemos, lo que, sin duda, nos ayudará a hacer las cosas mejor en el futuro. Lo que realmente tratamos de medir aquí es la diferencia que existe entre las horas que estimamos que durará un proyecto y las que realmente nos lleva a hacerlo. Una cifra baja aquí no dirá nada acerca de si hacemos buen o mal software, pero probablemente nos lleve a la ruina. La fórmula que empleamos para el cálculo es: Volvemos a los indicadores de calidad, aunque éste (como en realidad todos) también tiene connotaciones económicas. Lo que mide es el impacto que tienen los reportes de errores de los clientes una vez que la aplicación está terminada y aceptada. La fórmula que empleamos para el cálculo es: % eficiencia = 100 * (horas previstas / horas reales) % utilización = 100 * (horas reales facturables / horas teóricas) índice defectos garantía = horas dedicadas resolución defectos / 1000 LOC En este caso se han empleado indicadores de medida como el tiempo y las LOC, pero igual que en casos anteriores, éstos pueden ser sustituidos por otros cualesquiera que cumplan la misma función. <<dotNetManía Este indicador trata de medir el número de fallos que los usuarios reportan en el proceso de realizar las pruebas de aceptación de una aplicación, es decir, en el último momento del ciclo de desarrollo de la misma y donde el software ha debido pasar ya todos los controles de calidad necesarios. Un número alto en este dato hablaría bastante mal de nuestra capacidad de prueba. La fórmula que empleamos para el cálculo es: 11 Suscríbase y llévese los tres próximos libros gratis además, el CD Vol. 2 con los números 12 al 22 en PDF ❑ Nº17 (6,50€) ❑ Nº18 (6,50€) ❑ Nº19 (6,50€) ❑ Nº20 (8,50€) ❑ Nº21 (6,50€) ❑ Nº22 (6,50€) ❑ Nº23 (6,50€) ❑ Nº24 (6,50€) ❑ Nº25 (6,50€) ❑ Nº26 (6,50€) ❑ Nº27 (6,50€) ❑ Nº28 (6,50€) ❑ Nº29 (6,50€) ❑ Nº30 (6,50€) ✃❑ ❑ Oferta válida hasta el 30 de noviembre de 2006 o hasta agotar existencias Deseo suscribirme a dotNetManía por un año (11 números) por un precio de 65,00€ IVA incluido y recibir gratuitamente los tres próximos cuadernos técnicos que publique Netalia, y además el CD Volumen 2 con los ejemplares desde el 12 al 22 en formato PDF de alta calidad de forma gratuita. Si su dirección está fuera de España consulte los detalles en www.dotnetmania.com Deseo que me envíen los números atrasados marcados según el precio de portada. Otros: DATOS DE ENVÍO CIF/NIF. . . . . . . . . . . . . . . . . . . . Empresa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nombre y apellidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dirección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Población . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Código Postal . . . . . . . . . . . . . . . . . . . Provincia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Teléfono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fax . . . . . . . . . . . . . . . . . . . . . . . . . . . email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DATOS DE FACTURACIÓN (sólo si son distintos a los datos de envío) CIF/NIF. . . . . . . . . . . . . . . . . . . . Empresa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nombre y apellidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dirección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Población . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Código Postal . . . . . . . . . . . . . . . . . . . Provincia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Teléfono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fax . . . . . . . . . . . . . . . . . . . . . . . . . . . email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . FORMA DE PAGO ❑ Talón nominativo a nombre NETALIA, S.L. ❑ Transferencia bancaria a nombre de NETALIA, S.L. a: La Caixa - Número de cuenta 2100 4315 48 2200014696 (Indique su nombre en la transferencia) ❑ Domiciliación Bancaria (con renovación automática, previo aviso) Indique su número de cuenta: ❑ Tarjeta de crédito ❑ VISA ❑ MASTERCARD Número de su tarjeta: Fecha de caducidad: / (imprescindible) Firma y/o sello a de Puede enviar sus datos por Fax al 91 499 13 64, o por teléfono al 91 666 74 77, o por email a la dirección [email protected], o también puede enviarlos por correo postal a la siguiente dirección: de 2006 Usted autoriza a la mecanización de estos datos. El responsable y destinatario de éstos es Netalia, S.L. Usted tiene derecho a acceder a sus datos, modificarlos y cancelarlos cuando lo desee. Sus datos no serán cedidos en ninguna de las formas posibles a terceras partes y no se utilizarán más que para el buen funcionamiento de su suscripción a la revista dotNetManía y para informarle de las actividades comerciales que realice la editorial Netalia, S.L. Si no desea recibir información comercial de dotNetManía marque la casilla siguiente ❑ Netalia, S.L. C/ Robledal, 135 28529- Rivas Vaciamadrid (Madrid) dnm.asp.net José M.Alarcón Fundamentos de AJAX Cómo utilizarlo sin ayudas externas Si hay una palabra de moda últimamente en el mundo del desarrollo Web, ésta es sin duda AJAX. En este artículo vamos a aprender sus fundamentos, independientes de la tecnología de servidor utilizada. Ello nos será útil para comprender mejor las nuevas bibliotecas especializadas (como Atlas) y evitar posibles errores. José Manuel Alarcón Aguín es redactor de dotNetManía. Es ingeniero industrial y especialista en consultoría de empresa. Ha escrito varios libros, y ha publicado más de trescientos artículos sobre informática e ingeniería en revistas especializadas. Es MVP de ASP.NET, MCTS, MCPD, MCT y tutor de campusMVP. Visite su blog en www.jasoft.org desde sus comienzos. Las limitaciones propias del protocolo HTTP utilizado en las páginas Web han impuesto el tradicional modelo de “petición-cargaprocesado de cliente” y vuelta a empezar. En una aplicación Web normal el usuario solicita una página, el servidor devuelve el contenido HTML de ésta (normalmente generado a partir de alguna tecnología de servidor como ASP.NET), el navegador lo procesa y visualiza su contenido. Una vez que el usuario interactúa con el HTML, envía un formulario al servidor o pulsa un enlace, y se repite el ciclo: se solicita la página, se devuelve su contenido, se procesa y se visualiza. Este proceso es el más natural para HTTP (pensado desde luego de esta manera), pero tiene el problema de que, a veces, para obtener una página prácticamente igual pero con pequeñas modificaciones es necesario recargar la página completa. Esto está especialmente vigente desde que ASP.NET apareció en escena hace unos años con su novedoso sistema de postback, gracias al cual una aplicación Web se programa prácticamente igual que una de escritorio, respondiendo a eventos y accediendo directamente a las propiedades de los objetos. El problema de este sistema es que cada uno de los postbacks al servidor hace que se recargue la página completa, lo cual es percibido de manera evidente por los usuarios (es decir, “se nota”) y crea una sensación poco amigable. Si bien el concepto de postback es extre- madamente útil, las actuales tendencias en el desarrollo Web hacen que éstas sean cada vez más parecidas a aplicaciones de escritorio (se han dado en llamar aplicaciones Web 2.0). Esto implica que los molestos y a la vez inevitables viajes al servidor no deben ser percibidos por los usuarios. La sensación para éstos debe ser la de que la aplicación está todo el tiempo en su equipo, dejando de lado al servidor, como en una aplicación de escritorio tradicional. Cualquiera que haya usado GMail o Flickr sabe de qué estoy hablando. <<dotNetManía << Las aplicaciones Web llevan siendo más o menos iguales 13 <<dotNetManía << dnm.asp.net 14 Desde que el HTML Dinámico (HTML + Javascript) y las hojas de estilo CSS hicieron su aparición, cada vez más aplicaciones hacen uso de las posibilidades de modificación “al vuelo” de contenidos que estas tecnologías brindan. Hoy en día todos los navegadores soportan DHTML, por lo que escribir complejos programas que interactúen con los contenidos de la página no implica, como antes, tener que dejar fuera a parte de tus posibles usuarios. Desde hace ya bastantes años existen aplicaciones que haciendo uso de DHMTL crean espectaculares efectos en las páginas y modifican dinámicamente contenidos. Lo que ya no es tan habitual es que estos contenidos dinámicos vengan determinados por programas que están en el servidor. La idea es hacer las peticiones al servidor (donde está la lógica de nuestro programa escrita en ASP.NET, PHP, JSP o el lenguaje que sea), pero de forma que este hecho sea transparente para los usuarios. Este es el objetivo perseguido por AJAX. Este simpático acrónimo hasta hace poco asociado con el apasionante mundo de la limpieza, viene del inglés Asynchronous Javascript And XML. Se basa en el uso de un objeto llamado XMLHttpRequest, presente en los navegadores modernos, que como es de imaginar sirve para hacer peticiones de documentos XML a través del protocolo HTTP, y que apareció por primera vez en las bibliotecas XML de Microsoft (MSXML). Con este objeto se piden documentos XML que luego es posible manipular mediante código Javascript desde dentro de una página y mostrar resultados dentro de elementos de la misma. Esta es la idea básica, aunque como veremos da mucho más de sí. Aunque ahora parece que los chicos de Google han inventado la pólvora con GMail, lo cierto es que el concepto original de esta tecnología fue creado por Microsoft (se llamaba Remote Scripting). El primer navegador en soportarlo fue Internet Explorer y la primera aplicación de este tipo fue Outlook Web Access, para acceder a buzones Exchange. Como veremos enseguida, aparte de que su nombre original haya perdurado por ser simpático, la realidad es que AJAX no siempre es asíncrono ni siempre usa XML. Lo que de verdad importa es el objeto XMLHttpRequest; lo demás son opciones. Este artículo presenta los fundamentos de la tecnología para que usted no dependa de biblioteca alguna a la hora de implementar estas características, y sobre todo –seamos realistas– para que cuando utilice una de dichas bibliotecas (en este número de dotNetManía se habla de las más importantes) comprenda lo que hay debajo y pueda determinar posibles problemas. • • • El objeto XMLHttpRequest Para sacar partido a AJAX, aparte de saber HTML y Javascript, el primer objeto que debemos conocer a fondo es XMLHttpRequest. Se trata de una clase disponible en todos los navegadores modernos que permite lanzar desde Javascript peticiones de recursos GET y POST a través de HTTP. En lenguaje llano, esta clase nos permite simular desde el código de nuestras páginas llamadas a Internet como si fueran hechas por los usuarios. Si ha utilizado alguna vez las bibliotecas MSXML con Visual Basic 6.0 o ASP 3.0, es probable que ya lo conozca. Aunque en el caso de Internet Explorer se sigue exponiendo su funcionalidad como un objeto ActiveX, en el resto de los navegadores (Firefox, Opera, Safari...) ya forma parte de sus clases nativas. Los métodos y propiedades básicos de esta clase que debemos conocer son los siguientes (los corchetes indican parámetros opcionales): • open(metodo, URL, [asincrono], [usuario], [clave]): sirve para abrir una conexión al servidor. No envía ni obtiene información, sólo se conecta. El tercer parámetro es booleano y sirve para indicar si la conexión se realizará de forma asíncrona (por defecto) o no. Los dos últimos parámetros sirven para especificar un nombre de usuario y una contraseña de acceso para recursos protegidos por autenticación básica, si bien esto es bastante absurdo pues estarán escritos en claro en el Javascript. • send(contenido): envía una petición. Si el método es POST, se pueden • • • • incluir los datos a enviar en el parámetro; en caso contrario, se usa un nulo. abort(): cancela un envío/petición. onreadystatechange: se le asigna un método que será llamado automáticamente cuando se descargue del todo el recurso apuntado por la URL remota (cuando se llama asíncronamente). readyState: informa del estado de la petición: - 0 = no iniciada - 1 = cargando - 2 = terminada pero sin procesar - 4 = completada status : código de estado HTTP resultado de la petición: por ejemplo 200 (éxito), 404 (no encontrado), etc. statusText: mensaje de información del estado anterior. responseXML: documento DOM que representa el XML devuelto por la petición (se espera XML, claro). responseText: el contenido puramente textual del recurso remoto. Útil si no nos devuelve XML, como es muy habitual. Aunque la clase dispone de algunos métodos y propiedades más, con éstas tendremos suficiente para el 99% de los casos que nos vamos a encontrar. Menos teoría, vamos a la práctica Veamos cómo se usa la clase XMLHttpRequest con un ejemplo sencillo. Consideremos algo simple como el ejemplo de la figura 1. Hay una lista desplegable que contiene una serie de categorías. Al elegir una de éstas, en la lista de al lado deberá aparecer una lista de elementos asociados, obtenidos dinámicamente mediante una llamada al servidor. Este ejemplo es muy sencillo, pero nos ayuda a centrarnos sólo en la parte que nos interesa ahora, que es la de cliente. Es obvio que lo que debemos hacer para que esto funcione es responder a los eventos de cambio de selección de la primera lista, lanzando por detrás una petición a una página del servidor que nos devolverá los elementos de la lista secundaria. << dnm.asp.net Lo primero que debemos hacer para lanzar una llamada al servidor desde nuestro código Javascript es obtener una referencia a un objeto de la clase XMLHttpRequest que utilizaremos. Dado que Internet Explorer es diferente a los demás navegadores en este aspecto, debemos distinguir con quién estamos trabajando para poder instanciarlo. Podemos encapsular esta funcionalidad en el código del fuente 1. function getHttpRequest() { var httpReq; //Si es Mozilla, Opera, etc... if (window.XMLHttpRequest) { httpReq = new XMLHttpRequest(); } //Internet Explorer lo expone como control ActiveX else { httpReq = new ActiveXObject(“Microsoft.XMLHTTP”); } } Fuente 1 Una vez que tenemos una referencia al objeto, usaremos sus métodos y propiedades para lanzar una petición a la página de servidor que nos interese, por ejemplo así: http = getHttpRequest(); http.onreadystatechange = finCarga; http.open("GET", "http://www.miserv.com/misdatos.aspx",true) http.send(null); En la segunda línea establecemos la función que se llamará automáticamente cuando cambie el estado de la petición que vamos a hacer. Ello no implica que dicha petición tenga éxito o que sea llamada sólo cuando termine, como veremos enseguida. function finCarga() { if (http.readyState == 4) //4: completado { if (http.status == 200) //200: OK { res = http.responseXML; Procesarespuesta(); } else //Se produjo un error { alert(“No se pudo recuperar la información: “+ http.statusText); } } } Fuente 2 <<dotNetManía Figura 1 La tercera línea abre el conducto de petición que en este caso usará el método GET para cargar una determinada URL de modo asíncrono (true en el tercer parámetro). Por fin, debemos hacer la llamada (open no la hace, sólo la prepara), usando para ello el método send. Se le pasa un valor nulo porque no enviamos ninguna información extra (es una petición GET). El hecho de que sea una llamada asíncrona hará que se devuelva el control inmediatamente a Javascript al pasar por esta línea, por lo que podríamos seguir haciendo otros procesos sin que se viera interrumpida la interacción con el usuario. Podríamos usar llamadas síncronas (false en el tercer parámetro) para lanzar varias llamadas seguidas con la certeza de que se ejecutarán en un determinado orden. Es decir, AJAX en realidad no siempre debe ser asíncrono. Obviaremos de momento el código de la página del servidor, que podría ser cualquiera (acceder a una base de datos para obtener los elementos, leer un archivo o la memoria, etc.). Lo único verdaderamente importante es ponernos de acuerdo en cómo se van a devolver los resultados a través de la petición. Podemos complicarlo todo lo que queramos usando XML o cualquier otra notación que consideremos oportuna. Más tarde retomaremos este tema. De momento, para acabar con el ejemplo vamos a suponer simplemente que el servidor nos devuelve una lista de elementos separados por comas que se desean mostrar en el control secundario. Como hemos visto, se define una función llamada finCarga que es llamada de manera automática al ir cambiando el estado de la petición. Podemos ver su aspecto en el fuente 2. Lo único que hacemos es detectar cuando se ha terminado la petición (readyState será igual a 4) y que ésta haya sido una petición exitosa (el código de estado HTTP debe ser 200). Si el código HTTP es 404 (no encontrado), 500 (error en el servidor) u otro cualquiera se advierte con un mensaje al usuario. En caso de resultado positivo, lo único que hacemos es anotar la res- 15 << dnm.asp.net puesta del servidor en una variable global de la página (res en este caso) y procesar el resultado adecuadamente. En este caso se separan los elementos con las comas y se carga la lista secundaria. Dado que es un código Javascript trivial y no aporta nada al tema que nos ocupa no lo he incluido aquí, pero se puede descargar desde la Web de la revista. Lo único que se usa normalmente al mostrar los resultados son los conocidos métodos getElementsByTagName y getElementByID de HTML dinámico y del DOM. Estudie el ejemplo incluido en el ZIP (www.dotnetmania.com) para ver exactamente cómo se ha hecho. Posibles problemas que debemos tener en cuenta al usar AJAX Ahora que ya conocemos los rudimentos de AJAX “a pelo”, vamos a ver cuáles son los principales problemas que podremos encontrar al usar estas técnicas. Probablemente, serán los mismos que nos encontraremos si utilizamos alguno de los paquetes específicos para AJAX de ASP.NET, por lo que debemos ser conscientes de ellos. Los más importantes son los siguientes: 1. Llamadas fuera del dominio. 2. Llamadas que producen errores o que no vuelven jamás. 3. Envío de datos al servidor. 4. Contenidos no actualizados debido a caché. muy fácil procesar lo que devuelven con las técnicas descritas para, por ejemplo, realizar búsquedas en Google o Amazon con sus API respectivas, enviar posts a nuestro blog, consumir fuentes RSS, etc. Todo esto parece estupendo, pero tiene un gravísimo inconveniente: los navegadores, por cuestiones de seguridad, bloquean todas las peticiones realizadas mediante XmlHttpRequest a dominios que no sean el que aloja la página desde la que se está usando. En realidad se trata de una restricción bastante lógica y que aparece en otras partes del navegador, como las cookies, el acceso a variables de Javascript entre marcos, los objetos Flash o los applets de Java. Pero esto, claro está, supone una limitación importante para ciertos tipos de aplicaciones AJAX que podríamos desarrollar, como las de los ejemplos comentados. zar la llamada a otros dominios devolviendo el resultado a nuestro Javascript (directamente o preprocesándolo de algún modo). En .NET esto implica normalmente crear un manejador de peticiones con extensión .ashx que se encargue de realizar por nosotros las peticiones que nos interesen. Pero ¡mucho ojo con esto! Normalmente este tipo de servicios –al igual que los que se encargan de leer archivos de disco de manera genérica y otros similares– son un verdadero peligro de seguridad si no los programamos bien. Si optamos por esta solución, lo mejor es tomar varias precauciones de cara a la seguridad: tener muy acotados los servicios o las URL a las que se puede llamar desde el proxy. Lo mejor es identificarlos a cada uno con un número o código decidiendo a cuál se llama desde una cláusula switch (o Select Case en VB.NET), nunca poniendo la URL directamente en la llamada desde Javascript. Otra opción es tratar de identificar al script llamante de alguna manera: mediante una cabecera que te debe enviar, comprobando el dominio del referer y cosas similares. Está claro que un cracker experimentado se puede saltar esto, pero le costará bastante trabajo; y así eliminamos de un plumazo a los aficionados que quieran hacer uso ilícito de tu servicio. Si es posible, limite el número máximo de llamadas seguidas que se permite hacer desde una determinada IP o, mejor, en una determinada sesión de servidor. Toda precaución es poca. Atlas (más adelante en este mismo número), ofrece la posibilidad de crear este tipo de proxies de manera sencilla. Otra opción más simple aunque un poco “chapucera” (y también más tediosa y propensa a errores) consiste en usar un marco interno (IFRAME) oculto. En él se carga la URL que deseamos llamar usando su propiedad src. Al ser un marco interno, tenemos acceso a todas las propiedades de su objeto document; es decir, que podemos detectar cuándo ha AJAX se basa en el uso de un objeto llamado XMLHttpRequest, presente en todos los navegadores modernos <<dotNetManía Llamadas fuera de dominio 16 Una vez que uno empieza a juguetear con las posibilidades de AJAX enseguida se nos ocurren ideas geniales para sacarle partido. La más obvia, claro está, es la de utilizar las técnicas para acceder desde el cliente a ciertos servicios Web ajenos de utilidad ubicados en Internet. Así, dado que los servicios Web están basados en XML, es La pregunta ahora es: ¿cómo solucionamos este problema? En Internet Explorer basta con bajar el nivel de seguridad para que ya funcione correctamente, pero no es una buena solución (no le puedes pedir esto a tus usuarios). En Firefox, Opera y Safari no hay forma de saltarse esta restricción. Existe una salvedad en Firefox que consiste en firmar digitalmente el Javascript que usas, pero tampoco vale de mucho pues sólo funcionaría en este navegador. La única forma de resolver el problema de manera independiente al navegador es, aunque sea de Perogrullo, hacer que no dependa de éste; es decir, llevarnos el problema al servidor. Para ello lo que debemos hacer es construir un servicio proxy que esté en nuestro servidor (al que sí podremos llamar con AJAX) y que sea éste el que se encargue de reali- << dnm.asp.net Gestión de errores y llamadas que no vuelven No podemos asumir que las llamadas que hagamos al servidor van a funcionar siempre. Puede haber un error en el código del servidor, puede haber cambiado la URL y no aparecer la página que llamamos, haber errores de permisos, etc. Lo que pase en el servidor está fuera de nuestro control. Ante eso hay que estar preparado. La forma de controlar estas situaciones es, como en cualquier componente de comunicaciones por HTTP, a través del código de estado que devuelva el servidor. Todo esto ya se había apuntado antes y se había tenido en cuenta en el código del fuente 2. Podríamos afinar más en el tratamiento de errores y devolver un mensaje diferente según el código de estado. Hay, sin embargo, una situación menos frecuente pero más peligrosa que se puede producir: que la llamada asíncrona al servidor no vuelva o no lo haga en un tiempo razonable (timeout). ¿Qué hacemos en ese caso? No podemos contar con la notificación de final de carga puesto que, al no regresar la llamada, no saltará, así que el código del fuente 2 no nos sirve. Lo que se hace en estos casos es establecer un temporizador con el tiempo máximo que deseemos esperar, para que al cabo de ese intervalo la petición sea anulada directamente, sin esperar más por la respuesta. Podemos ver un ejemplo en el fuente 3. En él se ha modificado el código de llamada anterior para añadir la creación de un temporizador que se encarga de anular la petición al pasar un tiempo determinado (en este caso de 20 segundos, pero puede ajustarse a cualquier otro valor). Observe también cómo en el evento de fin de carga se elimina el temporizador cuando la petición termina de procesarse en caso de que regrese. Envío de datos al servidor Normalmente cuando pensamos en AJAX, es decir, en llamadas asíncronas a servicios, lo hacemos desde el punto de vista de obtener información: llamo a una página que me devuelve unos valores y los muestro en la interfaz de usuario. Aunque éste es el uso más común de AJAX, lo cierto es que también es muy útil usarlo en el sentido inverso, para enviar datos al servidor. Las utilidades y necesidades que puede cubrir este caso son múltiples, y de hecho hay muchos sistemas que le sacan partido. La forma más sencilla y directa de enviar datos simples al servidor es incluirlos en la URL a la que llamamos como parámetros GET: urldestino.aspx?Parametro1=1234&Parametro2=5 Aunque esto puede servirnos para cosas muy sencillas, no es lo que necesitaremos en la mayor parte de los casos. http = getHttpRequest() http.onreadystatechange = finCarga; http.open(“GET”, “http://www.miserv.com/misdatos.aspx”, true) //20 segundos var tmrAnular=setTimeout(“AnularPeticion()”, 20000); http.send(null); function AnularPeticion() { http.abort(); } function finCarga() { if (http.readyState == 4) //4: completado { clearTimeOut(tmrAnular); if (http.status == 200) //200: OK { res = http.responseXML; ProcesaRespuesta(); } else //Se produjo un error { alert(“No se pudo recuperar la información: “+ http.statusText); } } } Fuente 3 Lo habitual es que la información haya que enviarla con el método POST. La principal diferencia entre GET y POST estriba en que el método GET hace una sola llamada al servidor, solicitando una página y enviando algunos parámetros de datos en la propia petición. POST, por el contrario, realiza dos conexiones al servidor. En la primera solicita una URL y en la segunda envía los datos. Mediante GET lo máximo que se puede enviar son 2 Kb de información, mientras que POST no tiene esta limitación. Para enviar datos al servidor mediante POST, nuestro código AJAX sería similar al siguiente: http = getHttpRequest() http.onreadystatechange = finCarga; http.open("POST", "http://www.miserv.com/misdatos.aspx", true) http.send('Parametro1=1234&Parametro2=5'); Con esto no hemos ganado demasiado. Ahora se envían los datos con POST (sólo cambia el primer parámetro de open) pero los hemos tenido que introducir en el método send en lugar de en la propia URL. Esto sólo simularía el envío de parámetros mediante POST desde un formulario HTML (que, por otro lado, en ocasiones puede ser lo que queramos). <<dotNetManía terminado de cargar y leer sus contenidos, procesándolos también mediante DOM. 17 << dnm.asp.net Lo habitual es que, en lugar de enviar parámetros, queramos enviar información pura y dura del tamaño que sea preciso, que es para lo que suele usarse POST. Esto se puede conseguir modificando ligeramente el código anterior para incluir una cabecera que indique al servidor que lo que le llega son, precisamente, datos (línea 3 del fragmento del fuente 4). Con esto nuestro problema queda resuelto. Si queremos asegurarnos de que la petición va a llegar a su destino podemos hacer fundamentalmente dos cosas: 1. Agregar una cabecera que indique que se debe obtener el contenido siempre que éste sea posterior a una fecha, por ejemplo así: http.setRequestHeader( 'If-Modified-Since', 'Wed, 1 Jan 2003 00:00:00 GMT'); http = getHttpRequest() http.onreadystatechange = finCarga; http.setRequestHeader('content-type', 'application/x-www-form-urlencoded'); http.open("POST", "http://www.miserv.com/misdatos.aspx", true) http.send('Aquí ahora mando la información que quiera al servidor'); Fuente 4 Contenidos no actualizados debido a caché Cuando se envía una petición HTTP es posible que, si la caché del lado servidor no está correctamente configurada, el navegador realice su propia caché y por lo tanto la llamada no llegue al servidor jamás. O puede que exista un proxy-caché por medio (Telefónica, por ejemplo, los utiliza) que almacene peticiones anteriores y por lo tanto obtengamos únicamente una copia, sin realizar la llamada al servidor real. Eso puede ser estupendo (muchas veces es lo que querremos para ahorrar procesamiento), pero otras veces puede ser una maldición, ya que no obtendremos los datos actualizados. A la hora de enviar datos por POST no hay problemas, porque con este método no actúa nunca la caché. El problema, si se da, está en las peticiones GET, por otro lado las más habituales. Si el servidor tiene bien configurada la caché (es decir, indica cuándo caducan los contenidos o marcamos en IIS que éstos caduquen inmediatamente), no deberíamos experimentar fallos, a excepción de lo comentado respecto a los proxy-caché de algunos proveedores. Indicaremos siempre una fecha anterior a la actual (como la del ejemplo), y se den dos peticiones idénticas incluso a través de un proxy-caché. Obviamente, ese parámetro adicional de nombre inventado no debería afectar en absoluto a la llamada puesto que no está siendo tenido en cuenta por la aplicación. Esta segunda técnica es la más fiable, aunque un poco más tediosa de implementar. Los datos de retorno: JSON En el ejemplo anterior hemos hecho que la página del servidor devuelva ciertos valores separados por comas. Si bien esto puede ser suficiente en los casos más sencillos, en otras ocasiones necesitaremos manejar estructuras de datos más complejas. El recurso al que llamemos en el servidor debe devolver siempre texto. Éste puede ser cualquier cosa: texto plano, XML, código Javascript o incluso HTML. En este último caso, podemos obtener desde el servidor un contenido HTML completo que se debe escribir en una zona de la página (por ejemplo un <DIV> o un <SPAN>). Sin embargo, la mayor parte de las veces lo que tendremos que procesar es alguna estructura de datos. La “X” de AJAX significa XML, ya que el origen de esta técnica deriva inicialmente del uso del objeto XMLHttpRequest, pensado para obtener este tipo de información. Como hemos demostrado en el ejemplo, esto no es necesariamente así. De hecho, hoy en día el XML se usa muy poco a la hora de representar los datos textuales devueltos desde el servidor en páginas AJAX. El motivo de esto es principalmente que los datos representados con XML, si bien son ricos en estructura, hacen que el resultado devuelto ocupe mucho debido a las etiquetas de apertura y cierre de los diferentes nodos. Gracias al DOM es fácil procesar la información jerárquica que se representa mediante XML; aún así, debería existir algún método más directo y que ocupe menos ancho de banda. <<dotNetManía Como alternativa a XML ha surgido un nuevo estándar llamado JSON que lo sustituye con muchas ventajas añadidas 18 así siempre se pedirá la última versión al servidor. 2.- Añadir un número aleatorio (o cadena) a la URL de cada petición. En este caso suele funcionar muy bien el agregarle una marca temporal, de modo que cada una de las peticiones que se hagan sea diferente y por lo tanto los caché que existan por medio tengan que repetir siempre la petición. Por ejemplo: http.open("POST", "http://www.miserv.com/misdatos.aspx? pasacache=" + new Date().getTime(), true); Aquí se añade a la URL un parámetro que lleva como valor la fecha y hora en formato numérico (es decir, un número muy largo y que varía varias veces cada milisegundo), por lo que es muy difícil que << dnm.asp.net var cliente = eval(res); JSON permite representar objetos en forma de código JavaScript que luego podremos evaluar Siendo res el nombre de la variable que contiene el JSON obtenido del servidor. Es decir, lo único que hacemos es procesar la expresión JSON. Al hacerlo obtenemos en la variable cliente un objeto cuyas propiedades son los datos que queremos manejar. De este modo, lo único que tenemos que hacer para leerlos es escribir directamente expresiones como ésta: Como alternativa a XML ha surgido un nuevo estándar llamado JSON, que lo reemplaza con mucha ventaja en la mayor parte de los casos. JSON es el acrónimo de Javascript Object Notation, y como su propio nombre indica permite representar objetos (en realidad estructuras complejas) en forma de código Javascript que luego podemos evaluar. JSON tiene varias ventajas sobre XML, a saber: 1. Ocupa mucho menos al transmitirlo por la Red. 2. El acceso a los elementos de datos representados es directo y sin necesidad de procesamiento farragoso usando el DOM o expresiones regulares. 3. Los datos pueden ir colocados en cualquier posición. alert("El nombre de la empresa es " + cliente.empresa); Consideremos el siguiente código XML que representa los datos de un cliente: <cliente> <nombre>José Manuel</nombre> <apellidos>Alarcón Aguín</apellidos> <empresa>Krasis</empresa> <telefono>902 876 475</telefono> <edad>34</edad> </persona> Ahora consideremos la misma representación en JSON: { "nombre" : "José Manuel", "apellidos" : "Alarcón Aguín", "empresa" : "Krasis", "telefono" : "902 876 475", "edad" : 34 Más fácil imposible. Nada de recorrer una jerarquía XML con el DOM o ir buscando nodo a nodo en el contenido. Se convierte en Javascript puro y utilizable nada más llegar desde el servidor. El uso de JSON como formato de intercambio sólo tiene dos problemas aparentes. El primero de ellos es el más obvio: generar XML con C# o VB.NET es muy fácil pero generar JSON requiere un cierto trabajo por nuestra parte. Para evitárnoslo existe una biblioteca llamada Jayrock (http://jayrock.berlios.de) que permite convertir objetos .NET directamente a su representación JSON. El otro problema es tal vez menos evidente pero más importante: la seguridad. Dado que se usa una expresión eval para convertir el texto en objetos Javascript, podría utilizarse de manera malintencionada para inyectar código peligroso en la página al efectuar la evaluación. Para evitarnos este peligro, en JSON.org tenemos un script (http://www.json. org/json.js) que extiende las cadenas de Javascript para convertirlas a JSON verificando la sintaxis y evitando lo que no sean datos. Si incluimos este script en nuestra página, en lugar de utilizar eval podemos escribir: var cliente = res.parseJSON(); para obtener el mismo resultado. El script nos ofrece además la funcionalidad inversa de la siguiente manera: var miCadena = cliente.toJSONString(); } Esto nos puede servir para enviar datos JSON al servidor, para almacenar un objeto en una cookie, etc. En resumen En este artículo hemos aprendido los fundamentos de AJAX, así como los principales problemas que nos podemos encontrar al utilizarlo. La comprensión de todo ello nos va a resultar útil, aún cuando no utilicemos las técnicas más rudimentarias sino que recurramos a un kit especializado como Atlas o AJAX.NET. <<dotNetManía Crear esta representación es muy fácil pues es sintaxis Javascript normal (en www.json.org es posible encontrar una explicación completa). Como se puede comprobar, ocupa menos espacio, es igual de fácil de leer y permite usar datos nativos y no sólo cadenas. En estructuras más complejas todavía se puede apreciar más el ahorro de datos que implica. En cualquier caso, lo más espectacular de JSON es lo fácil que resulta utilizarlo. Basta con escribir lo siguiente: 19 dnm.asp.net José M.Alarcón AJAX con ASP.NET 2.0 Script callbacks La reciente versión 2.0 de ASP.NET ofrece una nueva técnica para implementar páginas AJAX pero usando métodos nativos de servidor. Nos abstrae de la mayor parte de las complejidades asociadas al código de script de cliente,limitándose nuestra aportación en este sentido a procesar los resultados devueltos. En este artículo veremos cómo funcionan los script callbacks. << La filosofía de los script callbacks de ASP.NET 2.0 es la José Manuel Alarcón Aguín es redactor de dotNetManía. Es ingeniero industrial y especialista en consultoría de empresa. Ha escrito varios libros, y ha publicado más de trescientos artículos sobre informática e ingeniería en revistas especializadas. Es MVP de ASP.NET, MCTS, MCPD, MCT y tutor de campusMVP. Visite su blog en www.jasoft.org misma que la de AJAX. Es decir, desde el cliente se provoca una llamada en segundo plano al servidor, el cual procesa la petición y devuelve al cliente un resultado textual que es procesado por un método Javascript construido a tal efecto. De hecho, por debajo lo que se hace es utilizar un objeto XMLHttpRequest, tal y como hemos visto en el anterior artículo de fundamentos de AJAX. La diferencia principal entre la técnica de script callbacks que ofrece ASP.NET 2.0 y lo que hemos estudiado hasta ahora es que nos podemos despreocupar totalmente de la complejidad inherente al manejo de XMLHTTPRequest, y de la gestión de la mayor parte de los errores, pues de ello se encarga por nosotros la infraestructura de .NET de manera transparente. Además –y esto es importante– en lugar de llamar a otra página del servidor llamaremos a la misma página (como si fuera un postback), o incluso solo a determinadas partes de ésta si implementamos la técnica en un control en lugar de en la página entera. Esta técnica se ha incluido en ASP.NET 2.0 específicamente para realizar postbacks al servidor en segundo plano, y así seguir sacando partido al poderoso modelo de eventos de servidor de .NET sin que el usuario aprecie los “viajes” de ida y vuelta realizados. Cómo usar los script callbacks El uso de los script callbacks es sencillo, pero hasta que se ve un ejemplo completo cuesta un poco entender su funcionamiento. En los próximos apartados desgranaré poco a poco sus elementos y pido al lector un poco de perseverancia hasta llegar a la parte final, en la que todo “encaja”. Lo primero que debemos saber es que para sacar partido a esta nueva técnica, el control o la página a la que queramos dotar de funcionalidad AJAX deberá implementar la interfaz ICallbackEventHandler. Para ello podemos incluir una etiqueta: <%@ Implements interface= "System.Web.UI.ICallbackEventHandler" %> en el código HTML de la misma, o mejor todavía, hacer que la clase code-beside (la clase parcial incluida en el archivo .cs o .vb relacionado) implemente explícitamente dicha interfaz, tal y como se muestra en la figura 1. Como se puede apreciar, al escribir el nombre de la interfaz tras la definición de la clase veremos que en la etiqueta inteligente (smart tag) asociada se ofrece la posibilidad de generar de manera automática las definiciones de los miembros de la misma, para que podamos implementarlos tanto implícita como explícitamente. Antes de pasar a ver con detalle esta interfaz, es preciso señalar que no solo podremos implementarla en una página que contenga controles cuyo uso provocará llamadas asíncronas al servidor. Podemos crear también nuestros propios controles de usuario o controles Web que implementen dicha interfaz y que, al ser colocados sobre una página, provocarán la ejecución en el servidor de sus propias llamadas, lo cual nos permite un gran nivel de encapsulado. Figura 1 << dnm.asp.net La interfaz que debemos implementar es muy sencilla, pues solo consta de dos miembros: • Método RaiseCallbackEvent: se llama de manera automática al producirse un callback (o llamada en segundo plano) al servidor mediante código de script. Recibe como parámetro una cadena que se genera en el lado de cliente (en el navegador) antes del envío. Enseguida veremos la manera de hacerlo y qué información le pasaremos. Lo importante es saber que dentro de este método haremos todo el procesamiento que sea necesario como resultado de la llamada. Por ejemplo, recibimos un identificador y vamos a una base de datos para obtener los datos de detalle de una entidad asociada. Su firma es la siguiente: void ICallbackEventHandler.RaiseCallbackEvent( string eventArgument) • Método GetCallbackResult: este método se llama automáticamente en el servidor a la hora de devolver los resultados del procesamiento al cliente. Dichos resultados se devuelven en forma de cadena de texto y se reciben en el navegador en una función Javascript (¿se aprecia la similitud con lo visto en el artículo anterior?). En esta cadena de resultados podemos meter cualquier información en el formato que deseemos, tal y como ya hemos analizado: valores separados por comas, XML, JSON, etc. La firma de este método es ésta: string ICallbackEventHandler.GetCallbackResult() Generar la llamada desde el cliente Ahora que ya conocemos la teoría sobre cómo proceder en el servidor, estudiaremos cómo se provoca la llamada desde el navegador. Para ello hay que usar obviamente Javascript, solo que en esta ocasión no tendremos que encargarnos nosotros de ello, sino que ASP.NET proporciona todo lo necesario de manera automática. Para provocar la llamada al servidor se utiliza una función Javascript llamada WebForm_DoCallback que acepta unos determinados parámetros. Ésta se encuentra definida en uno de los manejadores .AXD que ASP.NET incluye de manera automática por nosotros en las páginas asíncronas. Eso sí, no debemos hacer uso de ella directamente. El hecho de que sepamos cómo se llama e incluso podamos averiguar para qué se usa cada uno de sus parámetros no es motivo para que la usemos de modo directo. En versiones o revisiones posteriores de ASP.NET podría cambiar de nombre o de parámetros. Por eso, para evitarnos este problema, dentro de la clase ClientScript de ASP.NET hay un método llamado GetCallback EventReference que sirve precisamente para generar una llamada Javascript con el nombre y parámetros adecuados a esta función, obteniendo algo análogo a este código: WebForm_DoCallback('__Page',document.getElementById( 'ddlCategorias').value,ActualizaVista,null, MuestraError,false) GetCallbackEventReference tiene tres versiones sobrecargadas que se pueden llamar. A la más común se le pasan los siguientes parámetros: • Control: una referencia al control ASP.NET que implementa la interfaz ICallbackEventHandler, y que obviamente puede ser la propia página actual (que hereda de la clase Control). • Argumento Javascript: la expresión Javascript que se evaluará en el navegador antes de enviar al servidor la petición, y cuyo resultado es precisamente lo que recibiremos en el método RaiseCall BackEvent visto antes. Puede ser una simple cadena o número, siendo con más frecuencia una expresión Javascript completa que devuelve algún resultado obtenido de los controles de la página. • Nombre de función Javascript de retorno: el nombre de una función Javascript que se llamará en el cliente cuando se devuelva la llamada del servidor. A ésta se le pasará el resultado devuelto por el miembro GetCallbackResult (una cadena), así como una variable de cadena para marcar el contexto de la llamada (información auxiliar opcional para saber desde dónde se llama, [ ] NOTA IMPORTANTE En la mayor parte de los artículos que se pueden encontrar en Internet sobre los script callbacks, viene documentado el trabajo con esta característica tal y como estaba definida en las primeras betas de ASP.NET. Casi no hay información actualizada, y todo aquello no funciona con la versión definitiva de .NET 2.0. Por ejemplo, antes la interfaz solo disponía de un método. Ahora son dos, por lo que nos vemos obligados a usar una variable de clase, común a ambas, para devolver el resultado al cliente. Como ventaja tenemos que se separa el procesamiento de la llamada de su resultado, de modo que, aunque se produzca un error en el evento, se sigue llamando igualmente a GetCallbackResult para devolver el resultado, y podemos jugar con eso. Existen muchas otras diferencias entre esas primeras versiones y la definitiva, así que no se puede fiar uno de lo que lea por ahí sobre este tema. <<dotNetManía La interfaz ICallbackEventHandler en detalle 21 << dnm.asp.net como se explica en el siguiente parámetro). • Contexto: se trata de un identificador de contexto (puede ser una cadena cualquiera o un número, etc.) que servirá para identificar el contexto de la llamada. De este modo podemos reutilizar la misma función de cliente o de servidor (se recibe en ambas) pero tratarla de forma diferente según el contexto. Este parámetro cobra importancia cuando desde una misma página se reciben llamadas asíncronas diferentes provocadas por distintos controles en el navegador, ya que todas se procesan con el método RaiseCallBackEvent y hay que distinguir unas de otras. ¿JAX? ¡esto es SÍNCRONO por defecto! <<dotNetManía Un momento, ¿la “A” de “AJAX” no es por “Asíncrono”? Sí. Sin embargo, por defecto, con los parámetros pasados en el método anterior, la función de script generada (WebForm_DoCallback) hace una llamada síncrona al servidor. No pasa nada, normalmente no notaremos diferencia, pero claro, en caso de tener una conexión lenta (o fallar ésta) podríamos notar una cierta paralización de la interfaz del navegador. Por ello es recomendable utilizar una forma sobrecargada del método que nos permite especificar que las llamadas sean asíncronas, y que añade dos parámetros más a los cuatro que acabamos de ver: • Función Javascript para errores: el nombre de una función Javascript que se llamará de forma automática en caso de producirse cualquier error en la llamada al servidor. Toma los mismos parámetros que en el caso de la función Javascript de retorno. • ¿La llamada es asíncrona?: si ponemos true en este último parámetro la llamada será asíncrona, y si ponemos false (valor por defecto) será síncrona. 22 ¿Para qué puede ser útil hacer llamadas síncronas? Pues como ya hemos visto en el artículo anterior, para asegurarnos de que se van a ser efectuadas en un determinado orden, o cuando existen dependencias entre unas y otras para evitarnos complejos códigos de sincronización. Recapitulemos antes de continuar Lo que hemos visto hasta ahora puede resultar en primera instancia un poco lioso. Sin embargo, si lo repasamos poniéndolo todo junto paso a paso se entenderá mejor: 1. Definimos un atributo para un control que, respondiendo a un evento de HTML, hará una llamada en segundo plano al servidor que será la que nos devuelva los resultados. Puede ser un clic, un cambio de selección, etc. Para saber qué código Javascript debemos usar para generar la llamada utilizamos el método GetCallbackEventReference. 2. En el servidor, en uno de nuestros controles o en la propia página, implementamos la interfaz ICallbackEvent Handler, cuyos métodos serán ejecutados automáticamente cuando se realice la llamada en segundo plano desde el navegador. 3. Definimos en el código HTML de nuestra página una función Javascript que toma como parámetros una cadena con los resultados de la llamada que hemos realizado al servidor, y una variable de contexto para distinguirla de otras en caso de que todas se gestionen con esta misma función. Hagamos un par de puntualizaciones más: • Esta técnica funciona con cualquier navegador moderno como FireFox, Safari u Opera, y no solo con Internet Explorer, como afirman algunos artículos por ahí. • Al llamar en segundo plano a la página también se lanzan los eventos de ésta, como en una llamada normal. Para distinguir –por ejemplo desde Page_Load u otro evento– si una llamada al servidor se corresponde con una llamada asíncrona de tipo script callback, la clase Page define una propiedad llamada IsCallback que permite distinguir éstas y funciona del mismo modo que la propiedad IsPostBack sobradamente conocida. De este modo, podremos distinguir este tipo de llamadas y gestionar el código de la página de forma diferente al de una llamada común. Figura 2 Un ejemplo completo Para entender mejor todo lo visto hasta ahora vamos a realizar un ejemplo completo. El código fuente está disponible para su descarga desde la página Web de dotNetManía. Nuestro ejemplo será muy sencillo pero suficiente para comprender todo lo explicado hasta ahora. Por esta razón, obviaremos cualquier otro código que nos pueda descentrar de nuestro objetivo, que es entender los script callbacks . Crearemos una página con una lista de categorías y un botón que, al ser pulsado, mostrará debajo (sin hacer postback) los contenidos de dicha categoría. La figura 2 muestra el ejemplo en funcionamiento. Para empezar, vamos a crear un nuevo proyecto de Visual Web Developer. Sobre la página por defecto ( Default.aspx ) arrastraremos un control DropDownList de nombre ddlCategorías. Le asignaremos una lista de elementos (“Empresas”, “Libros”, “Blogs”, “Revistas”...). Es importante no marcar su opción de “AutoPostback”. Ahora añadimos un botón. Pero atención, muy importante: no nos sirve un botón de ASP.NET (control Web) ya que este tipo de control siempre se genera como un botón de envío de formulario (submit) y es precisamente eso lo que queremos evitar. Debemos utilizar un botón de HTML (o sea, un INPUT de toda la vida) arrastrándolo desde la categoría HTML de los controles de ASP.NET. Una vez en el formulario, pulsaremos sobre él con el botón derecho y escogeremos la opción de ejecutarlo en el servidor (realmente solo se le añade un atributo runat="server" en su definición). Le llamaremos cmdVer. Para finalizar, añadimos debajo y desde el mismo grupo de controles HTML una capa (DIV) con el nombre divResultados, asignándole manualmente un estilo que permita que crezca adap- << dnm.asp.net AJAX de forma sencilla en el control GridView El control GridView que viene con ASP.NET 2.0 es un estupendo control que nos permite dotar de funcionalidades de paginación y ordenación de datos a un origen de datos sin necesidad de escribir código alguno.Lo que mucha gente desconoce es que,además,en la mayoría de los casos se puede conseguir esta funcionalidad sin tener que refrescar la página completa, al más puro estilo AJAX. Mediante esta vía, al pulsar sobre la cabecera de la rejilla o cambiar de página se recargan exclusivamente los contenidos de ésta,pero sin realizar un postback al servidor que fuerza el refresco de la página completa. Para conseguirlo solo es necesario establecer a true la propiedad EnableSortingAndPagingCallbacks del control,como ilustra la figura adjunta. Para dotar a la rejilla de esta útil característica los programadores de ASP.NET han utilizado script callbacks.El control GridView implementa la interfaz ICallBackEventHandler. No mostraremos el código aquí por falta de espacio, pero es interesante estudiarlo con cualquier decompilador como .NET Reflector.Lo dejamos como ejercicio. Aunque la propiedad es ciertamente útil y funciona muy bien en la mayor parte de los casos, hay un par de detalles que se deben tener en cuenta: 1. La técnica no funcionará si alguna columna de la rejilla es de tipo plantilla, es decir, no es un control BoundField o derivado (que son los que añade automáticamente el GridView). Si convertimos alguna columna en plantilla, la próxima vez que ejecutemos la página que contiene la rejilla se producirá una excepción que nos avisará de la incompatibilidad. 2. Si no hemos usado como origen de datos un control DataSource (SqlDataSource, ObjectDataSource,etc.),no funcionarán la ordenación ni la paginación estilo AJAX.Ello es debido a que el código llama al método DataBind al final y por lo tanto debe haber algún control enlazado permanentemente a la rejilla. tándose a su contenido (style="overflow: visible; width: 90%"). Con todo ello el código de la página quedará como el del fuente 1. Ya tenemos la base necesaria para crear el ejemplo. Ahora vamos a ver lo importante. Fuente 1 Figura 3 la lista), el nombre de la función a llamar tras terminar la petición al servidor (ActualizaVista), el dato de contexto (en este caso un nulo), el nombre de la función Javascript que se llamará si hay un error en la comunicación, y un booleano que indica si queremos que la llamada sea asíncrona o no. Por fin, se asigna ese código Javascript al evento onClick del botón (que no deja de ser más que un atributo del mismo). Al ejecutar la página obtendremos el HTML para el botón: <input name="cmdVer" type="button" id="cmdVer" value="Ver fuente" onClick="Javascript:WebForm_DoCallback( '__Page',document.getElementById( 'ddlCategorias').value, ActualizaVista,null,MuestraError, false)" /> <<dotNetManía nos ocurra. Es obvio que tendremos que escribir un manejador para el evento onClick del botón que provocará la 1.- Realizar las peticiones al servidor llamada en Lo primero en el orden lógico es pensegundo plasar cómo vamos a enviar las peticiones al no. El código servidor. En nuestro ejemplo lo haremos que debemos incluir para conseguirlo nos cuando se pulse el botón, aunque podría lo da el método GetCallbackEvent Reference estudiado antes. Por lo tanto, ser al cambiar la selección de la lista o con cualquier otro evento de Javascript que se lo único que debemos hacer es asociarlo al botón, lo que <body> haremos durante la <form id=”form1” runat=”server”> carga de la página. <div> Para ello necesitare<asp:DropDownList ID=”ddlCategorias” runat=”server”> mos decidir qué <asp:ListItem>Revistas</asp:ListItem> <asp:ListItem>Blogs</asp:ListItem> valor se pasará al ser<asp:ListItem>Empresas</asp:ListItem> vidor durante la lla<asp:ListItem>Libros</asp:ListItem> mada, qué función <asp:ListItem>Provoca error</asp:ListItem> de Javascript se va a </asp:DropDownList> <input id=”cmdVer” runat=”server” type=”button” llamar como resvalue=”Ver fuente”/> puesta final al call<br /><br /> <div id=”divResultados” style=”overflow: visible; width: 90%”> back, un dato de contexto (no lo usare</div> </div> mos en nuestro </form> ejemplo) y el nom</body> bre de la función Javascript que se llamará en caso de producirse un error. Teniendo todo eso en cuenta, el código resultante se presenta en la figura 3. Lo que se hace es obtener el identificador para la lista desplegable que se usará en el HTML resultante (no tiene por qué coincidir en general con el que le hemos dado en la página ASPX; depende de donde esté colocado) y con eso construimos una cadena Javascript que simplemente sirve para obtener el valor del elemento que esté seleccionado en ésta (este código Javascript lo almacenamos en la variable jsItem). A continuación, generamos el código Javascript que va a provocar la llamada al servidor con el método GetCallbackEventReference . Como parámetros se le pasan el control que gestionará el callback (la propia página, es decir, this en C# o Me en VB), el código Javascript que nos da el valor a enviar al servidor (el elemento seleccionado en 23 << dnm.asp.net #region Miembros de ICallbackEventHandler private string resCallBack = “”; string ICallbackEventHandler.GetCallbackResult() { return resCallBack; } void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument) { //Se recibe como argumento el nombre seleccionado en la lista switch (eventArgument) { case “Revistas”: resCallBack = “DotNetMania,MSDN Magazine,The Code Project”; break; case “Blogs”: resCallBack = “www.jasoft.org,www.geeks.ms,weblogs.asp.net”; break; case “Empresas”: resCallBack = “Krasis [www.krasis.com],Microsoft [www.microsoft.com], Plain Concepts[www.plainconcepts.com]”; break; case “Libros”: resCallBack = “Crimen y castigo,Cien años de soledad,El Quijote”; break; default: Response.StatusCode = 500; Response.End(); break; } } #endregion Fuente 2 <script> <!— //Nombre del control DIV asignado por ASP.NET en el cliente var NombreDiv = “divResultados”; //Escribe dentro del DIV el HTML que se le pase function EscribeTexto(txt) { document.getElementById(NombreDiv).innerHTML = txt; } //Procesa los resultados del servidor function ActualizaVista(res, context) { EscribeTexto(res.replace(/,/g, “<BR/>”)); } //Muestra un mensaje de error en el DIV function MuestraError(txtError, context) { EscribeTexto(“Error: “ + txtError); } Fuente 3 2.- Definir la interfaz ICallbackEventHandler <<dotNetManía 3.- Implementar las funciones de recepción de resultados en el cliente Solo nos resta una cosa y es decidir qué hacemos con los resultados una vez que se termine la llamada. En nuestro caso haremos algo muy sencillo: al igual que en el ejemplo anterior, separaremos los elementos recibidos como resultado sustituyendo las comas por retornos de carro (<BR/> en HTML) y esta cadena resultante la introduciremos directamente en el <DIV> de resultados que hemos incluido. El código Javascript es muy sencillo y se muestra en el fuente 3. Fijémonos en las funciones. La primera de ellas es general y se usa desde las otras dos simplemente para introducir el HTML que queramos dentro del DIV. Las otras dos funciones son la implementación de los métodos de resultado y de error, respectivamente. Deben tener los mismos nombres que escogimos en el paso 1, al generar la llamada al servidor. En el primer caso se sustituyen las comas por un retorno de carro, y en el caso del error se muestra el mensaje de error en el DIV en lugar de los resultados. Así de sencillo. En ejemplos reales podríamos hacer cosas mucho más complejas con HTML dinámico, todo dependerá de nuestro dominio de Javascript. En el código del fuente 2, para simular un error y facilitar la prueba del método correspondiente, hemos incluido un elemento en la lista (el último) que provoca al ser elegido un código de estado HTTP 500 (código estándar para indicar que se han producido errores en el servidor). De esta manera, al escoger la última opción de la lista en el navegador se interpreta como si fuese un error en nuestra página ASPX y se fuerza así la llamada a la función de error. Conclusiones //—> </script> 24 ICallbackEventHandler. En nuestro ejemplo, el código sería el del fuente 2. Si nos fijamos, el código es muy sencillo. Hemos eliminado acceso a datos y otras cuestiones para centrarnos en lo que nos ocupa. Así que según el valor que se le pase al método (la selección de la lista desplegable) anotamos una u otra lista de elementos separados por comas en una variable. El contenido de ésta es lo que se devuelve en el método GetCallbackResult, y por lo tanto lo que se le pasa al cliente como resultado. Con esto hemos finalizado la implementación de la interfaz. Ahora que ya estamos provocando las peticiones al servidor vamos a definir los métodos que se ejecutarán en éste como resultado de la llamada y que son los que obtienen el resultado a devolver. Como hemos visto, para ello es necesario implementar la interfaz La técnica de script callbacks tiene muchas aplicaciones, aunque la verdad es que queda un poco deslucida si la comparamos con las posibilidades que nos da Atlas para ASP.NET (tecnología que se describe en este mismo número). Ahora bien, para muchos casos sencillos en los que no queramos (o no podamos) instalar Atlas o que no se justifique la carga adicional asociada a éste, resultará una opción simple y segura para conseguir efectos AJAX. dnm.asp.net Román Fresneda Miguel Katrib AJAX, redefiniendo la forma de ver la Web AJAX es el nombre con que se ha “popularizado” a un grupo de tecnologías que juntas han cambiado la forma en que vemos la Web. AJAX abre la posibilidad de invocar asíncronamente desde Javascript a código del lado del servidor en una aplicación Web, usando XML como transporte (aunque se verá que esto último no es necesariamente así). << Los que estábamos habituados al desarrollo de aplicacio- Miguel Katrib Miguel Katrib es Dr.en Computación y Catedrático del Dpto.de Ciencia de la Computación de la Universidad de La Habana.Dirige el Grupo WEBOO dedicado a la enseñanza y desarrollo de la Orientación a Objetos y la Programación en la Web.Miguel es redactor de dotNetmanía y asesor de programación y tecnología .NET para CARE Technologies SA. Román Fresneda Quiroga es instructor de programación en C# del Dpto. de Ciencia de la Computación de la Universidad de La Habana. Román es desarrollador y webmaster del grupo WEBOO y entusiasta de ASP .NET y de la tecnología .NET. nes de escritorio, cuando comenzamos a desarrollar aplicaciones Web en ASP.NET no nos acostumbrábamos al navegador “colgado” esperando por la respuesta del servidor Web. Aunque por el momento ya existían medios (entre los que se encuentra el muy popular Javascript) para superar este aparente escollo de los escenarios Web, todavía no se hablaba conscientemente de una solución eficaz a tal problema. Pero fueron llegando después aplicaciones como Gmail (http://www.gmail.com), Google Maps (http://maps.google.com) y Flickr (http://www.flickr.com), que nos hicieron ver que las aplicaciones Web podían acercarse al tiempo de respuesta de las aplicaciones de sobremesa. Por lo general, la interacción con una aplicación Web tradicional sigue un patrón común: - Inicialmente, el usuario accede e interactúa con un formulario, provocando una petición al servidor Web. Esto desencadena toda la lógica de la aplicación en el servidor, quien puede a su vez interactuar con bases de datos u otras aplicaciones no visibles directamente por el usuario. - El servidor responde a la aplicación cliente (en su mayoría navegadores) en forma de HTML (XML). La aplicación cliente interpreta ese HTML y muestra un nuevo “formulario” al usuario (figura 1). cia de las aplicaciones Web. Con independencia de su ancho de banda, mientras el servidor procesa la petición el usuario espera… y desespera. El propósito de AJAX es atenuar este efecto, al darle más responsabilidad al navegador en tareas que antes podrían haber requerido una petición al servidor, enviando menos datos hacia éste o haciendo peticiones al servidor en el trasfondo, es decir, sin esperar por una interacción explícita del usuario (como la pulsación de un botón de envío). Entre las principales ventajas técnicas de este enfoque está la independencia de la plataforma cliente, pero puede llegar a ser no completamente agradable a los usuarios finales fundamentalmente por la latenEn este artículo se usa una implementación de AJAX para .NET conocida como Ajax.NET (de Michael Schwarz [1]) ya popular en Internet.Para ilustrar cómo usar esta biblioteca y algunos de sus pros y contras se desarrolla como ejemplo una aplicación para ofrecer un álbum de fotos vía Web. << dnm.asp.net Figura 1. El modelo clásico de aplicación Web. Una aplicación AJAX es diferente en el sentido de que se sustituye el patrón típico de interacción por la utilización de un intermediario, el mecanismo AJAX (figura 2), entre el cliente y el servidor, haciendo que la aplicación ofrezca una mejor respuesta. En vez de cargar una página Web completa al principio de la sesión, el navegador carga el motor AJAX, que está escrito en Javascript. Este motor es el responsable de dibujar la interfaz de usuario y de comunicarse con el servidor. El primer subproducto de la introducción de esta capa extra es permitir que la comunicación con el servidor sea ahora asíncrona; de este modo disminuye en el usuario la sensación de ver el navegador “colgado”. Cada acción del usuario que normalmente generaría una petición al servidor toma la forma de una llamada Javascript al motor AJAX. El mecanismo AJAX maneja aquellas respuestas que no requieran un viaje al servidor (figuras 3 y 4). Figura 2. El modelo de aplicaciones Web AJAX. Figura 4. El patrón de interacción asíncrono de una aplicación Web AJAX. Algunos de los conceptos AJAX que se pueden encontrar en el trabajo “Patrones AJAX” (ver [7]) reflejan lo dicho anteriormente: - Sensación de continuidad. - Actualizaciones en tiempo real. - Interacción gráfica más rica. Estos conceptos implican a su vez la adopción de ciertos “patrones” de implementación para su realización en cualquier aplicación. Ejemplos de estos patrones son: • Clientes más gruesos: las aplicaciones AJAX deben ser lo suficientemente ricas para evitar llamadas innecesarias al servidor. Sólo se harán llamadas al servidor si no se puede lograr el mismo efecto directamente en el navegador cliente. • Descarga predictiva: en ciertos casos, las aplicaciones deben anticiparse a las acciones del cliente y descargar datos que éste probablemente vaya a usar luego. • Refrescamiento periódico: El navegador refresca la información volátil, encuestando al servidor periódicamente de un modo transparente al usuario. • Validaciones del lado del cliente: Se harán todas las validaciones posibles del lado del cliente para evitar envíos hacia el servidor. Para la implementación de estos patrones, la mayoría de los frameworks Las figuras 3 y 4 (ver [2]) muestran el patrón de interacción de un cliente con una aplicación Web tradicional y una aplicación Web AJAX. En este artículo se muestra como ejemplo de aplicación AJAX la implementación de un álbum de fotos para colocar y compartir fotos en la Web, pero evitando el tedio y la lentitud que algunas de estas aplicaciones presentan. El objetivo principal del ejemplo se centra en mostrar cómo se puede hacer una aplicación Web donde no hay que refrescar toda la interfaz que se le muestra al usuario para poder visualizar cambios en ésta. Se ha utilizado como plataforma de desarrollo a ASP.NET 2.0 y Visual Studio .NET 2005, aunque la solución puede ser portada con mínimo esfuerzo al .NET Framework 1.1. Además, se hace uso de Javascript y DHTML para las tareas del lado del cliente. Figura 5. Creación del proyecto Web con VS.NET 2005 en el sistema de archivos. Para que nuestro álbum de fotos pueda ser reutilizado en diferentes aplicaciones Web, será implementado como un control de usuario Web. Para ello se crea un nuevo proyecto Web llamado PhotoGallery (figura 5). <<dotNetManía Figura 3. El patrón de interacción síncrono de una aplicación Web tradicional AJAX usan una combinación de las siguientes tecnologías: • DHTML/CSS y DOM, para lograr una presentación dinámica. • XML y XSLT, para el intercambio y manipulación de los datos. • XmlHttpRequest o iframes para la transmisión asíncrona de los datos. • Javascript como lenguaje para lograr los tres propósitos anteriores. 27 << dnm.asp.net Incluso es posible escribir conversiones especializadas de objetos .NET en objetos Javascript y viceversa, permitiendo con ello desarrollar aplicaciones más personalizadas Figura 6. Creación del control de usuario. Después de creado el proyecto Web, se le agrega el control de usuario, al que llamaremos AlbumFotos.ascx (figura 6). VS .NET crea entonces una clase que representa a este control de usuario y despliega el diseñador para que indiquemos cómo se quiere visualizar este control. Gracias a las clases parciales de VS 2005, la clase del control queda “limpia” del código necesario para el trabajo del diseñador (que mayoritariamente se esconde en el método InitializeComponent). Consideremos que después de trabajar con el diseñador el control para el albúm de fotos ha alcanzado el estado que se muestra en la figura 7. dro de texto a su lado; uno para mostrar una “presentación” del álbum completo, una etiqueta para mostrar el nombre de la foto, una para mostrar el orden dentro del álbum y otra para mostrar la descripción dada por el dueño; una imagen (<IMG> de HTML) para mostrar la imagen actual, y tres botones con fines “administrativos” (borrar, adicionar y renombrar), que sólo serán visibles para el dueño del sitio donde se encuentre el álbum en cuestión. Estos privilegios podrían ser implementados con la API de Membresía que ofrece ASP.NET 2.0; sin embargo, por sencillez nos limitaremos a dar una implementación ingenua. Por otra parte, los datos y comentarios relacionados con una foto en cuestión podrían ser guardados en una base de datos; aquí igualmente para mantener la sencillez se mantendrá un documento de texto para cada foto, en el que se guardará la descripción dada por su autor, el nombre de la imagen y los comentarios hechos por los demás usuarios. Registro de AJAX.NET en la aplicación <<dotNetManía Figura 7 El álbum de fotos en vista Diseño 28 Al control se le han incluido los cuatro botones clásicos para indicar la navegación (primera, anterior, siguiente y última), un botón para comentar una foto, uno para ir a una foto específica, en base a un número indicado en el cua- A diferencia de cualquier control de usuario común en ASP.NET 1.x/2.0, con AJAX gran parte del código para manejar los eventos que provocan los botones en la interfaz de usuario no van a ser manejados del lado del servidor, sino que van a tener una fuerte carga de código del lado del cliente. El código en el cliente es en este caso Javascript, el lenguaje de script por excelencia en la mayoría de los navegadores. Hay plataformas AJAX (como [4] y [5]) que ocultan todo el código Javascript. Sin embargo, en este trabajo se ha escogido AJAX.NET porque es una imple- mentación que posibilita al programador tener control sobre todo el proceso; es decir, desde el código Javascript del lado del cliente hasta el código del lado del servidor. Incluso es posible escribir conversiones especializadas de objetos .NET en objetos Javascript y viceversa, permitiendo con ello desarrollar aplicaciones más personalizadas. Lo primero que hay que hacer para poder usar esta biblioteca es agregar una referencia a AJAX.NET en la carpeta bin. En [1] hay dos versiones, una para la versión 1.1 y otra para la versión 2.0 de .NET Framework. Se ha utilizado en este ejemplo la versión para .NET Framework 2.0. No basta con agregar la referencia, también se debe registrar un manejador de petición (HTTP handler) que usa AJAX.NET. Este manejador convierte las llamadas del código cliente en llamadas a métodos del lado del servidor de un modo transparente y genera el Javascript apropiado en el código cliente. Más adelante veremos que el tipo donde se encuentran los métodos que se deseen invocar debe ser “registrado para AJAX”, de tal manera que el HttpHandler (para un buen artículo sobre HTTP handlers, vea [6]) sepa a qué método de qué tipo debe llamar al hacer la citada conversión. Hay que generar ahora el archivo web.config y añadir en la sección <system.web> las siguientes líneas: <httpHandlers> <add path=”ajaxpro/*.ashx” verb=”POST,GET” type=”AjaxPro.AjaxHandlerFactory, AjaxPro2”/> </httpHandlers> Con esto se le dice a ASP.NET que toda petición que venga a la carpeta vir- << dnm.asp.net El código del lado del servidor, los métodos AJAX Casi todas las implementaciones de los conceptos de AJAX utilizan el objeto XmlHttpRequest (algunas usan iframes) para despachar las peticiones desde el cliente y procesar las respuestas del servidor en el código Javascript. En particular, AJAX.NET genera, para cada tipo registrado por el usuario, un proxy Javascript que se encargará, mediante el objeto XmlHttpRequest, de enviar asíncronamente las llamadas a métodos del lado del servidor y recibir la respuesta de éstos (incluida alguna posible excepción). Se ha usado mucho XML para el intercambio de datos entre el cliente y el servidor, por el soporte de API que dan muchos navegadores para el trabajo con documentos XML. Sin embargo, las últimas tendencias (como las que se muestran en [7]) indican que XML se ha ido sustituyendo por JSON [8], el formato nativo en Javascript para representar objetos; JSON es, en la mayoría de los casos, menos engorroso que XML para representar la misma información. Esto ayuda a disminuir el tráfico cliente-servidor y hacer más fácil la conversión de la información textual que envía el servidor en objetos Javascript. Lo que se pretende es enviar hacia el servidor solo los datos necesarios para poder refrescar una parte de la interfaz Las llamadas que se producen desde Javascript usando el proxy van a ser interceptadas por el manejador HTTP y transformadas en llamadas a métodos AJAX mediante reflexión. Para redondear la ilusión del programador cliente de AJAX.NET, el proxy Javascript sigue una sintaxis casi idéntica a aquélla del lado del servidor. Esto se verá en el ejemplo que se muestra más adelante. Para que el control pueda usar AJAX.NET debe ser registrado. Esto se hace en el evento Load del con- trol llamando al método RegisterTypeForAjax de la clase Utility de la biblioteca AJAX.NET: protected void Page_Load(object sender, EventArgs e) { Utility.RegisterTypeForAjax(type of(AlbumFotos)); ... } El método RegisterTypeForAjax también puede ser utilizado para generar tipos Javascript a partir de tipos .NET, de manera que en tiempo de ejecución los conversores AJAX transformen “automáticamente” objetos .NET en objetos Javascript y viceversa. Lo único que se requiere es que el tipo .NET esté marcado con el atributo Serializable. La invocación a este método emite algunas referencias en la página HTML que se genera hacia el cliente: <script type=”text/javascript” src=”/PhotoGallery/ajaxpro/prototype.ashx”> </script> <script type=”text/javascript” src=”/PhotoGallery/ajaxpro/core.ashx”> </script> <script type=”text/javascript” src=”/PhotoGallery/ajaxpro/converter.ashx”> </script> <script type=”text/javascript” src=”/PhotoGallery/ajaxpro/AlbumFotos, App_Web_albumfotos.ascx.cdcab7d2.4deryp-x.ashx”> </script> Las tres primeras son referencias al núcleo Javascript de AJAX.NET, generado por el HTTP handler mencionado anteriormente; la cuarta es una referencia al archivo que contendrá al tipo Javascript que servirá de proxy a nuestro control de usuario. Recordemos que la tarea fundamental de este ejemplo es ganar tiempo evitando refrescar la interfaz completa del cliente. Lo que se pretende es enviar hacia el servidor solo los datos necesarios para poder refrescar una parte de la interfaz de acuerdo con la acción realizada por el usuario. El soporte que nos brinda public interface IAlbumFotos { //borra una foto del álbum void Borrar(string dirBase,string caminoFoto); //agrega una foto al álbum void Adicionar(string dirBase, string caminoFoto); //renombra una foto del álbum void Renombrar(string dirBase, string caminoFoto, string nuevoNombre); //comenta una foto específica void Comentar(string dirBase, string caminoFoto, string comentario); //devuelve la ruta de una foto dado su índice InformacionFoto IrAFoto(string dirBase int cual); //devuelve el total de fotos del álbum int TotalDeFotos(string directorioBase); } Fuente 1 La interfaz funcional del álbum <<dotNetManía tual /ajaxpro con extensión .ashx será procesada por una instancia del manejador AjaxPro.AjaxHandlerFactory. Ahora bien, nosotros no hemos creado ninguna carpeta virtual con ese nombre; es AJAX.NET quien usa esta carpeta virtual para fines internos. 29 << dnm.asp.net AJAX.NET para lograr este cometido son los métodos AJAX. AJAX.NET interpretará como tales a aquellos métodos que se hayan marcados con el atributo AjaxMethod (el tipo AjaxMethodAttribute forma parte de la biblioteca AJAX.NET). La funcionalidad del álbum de fotos se resume en el fuente 1. El control Web de usuario deberá entonces implementar esta interfaz IAlbumFotos. Para que nuestros métodos puedan ser “invocados” desde el lado del cliente, es necesario marcarlos con el atributo AjaxMethod. En caso de que un método necesite hacer uso de la sesión, entonces hay que indicarle al constructor del atributo un parámetro del tipo enumerado HttpSessionStateRequirement. Este tipo enumerado ofrece tres posibilidades: lectura, escritura y lectura/escritura. Por ejemplo, el método TotalDeFotos va a necesitar escribir y leer: protected void Page_Load(object sender, EventArgs e) { Utility.RegisterTypeForAjax(typeof(AlbumFotos)); Utility.RegisterTypeForAjax(typeof(InformacionFoto)); if (!Page.ClientScript.IsClientScriptBlockRegistered(“miScript”)) { Page.ClientScript.RegisterClientScriptBlock( typeof(AlbumFotos), “miScript”, string.Format( “ var directorioBase = \”{0}\”;\n” + “ var contadorID = \”{1}\”;\n” + “ var descripcionID = \”{2}\”;\n” + “ var imagenID = \”{3}\”;\n” + “ var nombreFotoID = \”{4}\”;\n” + “ “ “ “ <<dotNetManía btnPrimera btnAnterior btnProxima btnUltima = = = = “ var panelComentariosID “ var numeroFotosTbxID “ var nombreFotoBaseID Una propiedad fundamental de nuestro álbum, y que pudiera mostrarse en la interfaz de usuario con fines administrativos, es el directorio base de donde se van a obtener las imágenes. Esta propiedad va a ser usada solamente para poder configurar el directorio desde el diseñador de la página. primeraImgBtn.ClientID, anteriorImgBtn.ClientID, proximaImgBtn.ClientID, ultimaImgBtn.ClientID, Implementación del control borrarImgBtn.ClientID, adicionarImgBtn.ClientID, renombrarImgBtn.ClientID, comentarImgBtn.ClientID, Quizás una limitación de AJAX.NET es que no soporta la propiedad ViewState (lo que se manifiesta en que al invocar esta propiedad se devuelve null). Como es sabido, esta característica es útil para almacenar la información relacionada con un control y que no trasciende la página donde éste se encuentra. La razón que alega el autor es que esto aumenta el tráfico desde y hasta el servidor y limita la velocidad de ejecución de la aplicación. Sin embargo, a nuestro juicio la incomodidad por la falta de ViewState no se ve compensada por la supuesta ganancia en el rendimiento por prescindir de ésta. Es por este motivo de ausencia de ViewState que los métodos del fuente 1 reciben cómo parámetro la ruta del directorio donde se encuentran las fotos. Más adelante en el artículo se dará una explicación más detallada de cómo se hará para que el valor de esta propiedad viaje del cliente al servidor y viceversa. \”{5}\”;\n” \”{6}\”;\n” \”{7}\”;\n” \”{8}\”;\n” + + + + = \”{9}\”;\n” + = \”{10}\”;\n” + = \”{11}\”;\n” + “ var btnBorrar = \”{12}\”;\n” + “ var btnAdicionar = \”{13}\”;\n” + “ var btnRenombrar = \”{14}\”;\n” + “ var btnComentar = \”{15}\”;\n” + “ var btnPresentacion = \”{16}\”;\n” + “ var btnIrFoto = \”{17}\”;\n” + “ var imageBase = \”{18}\”;\n” + “ var operationsPanelID = \”{19}\”;\n”, this.Attributes[“DirectorioBase”], contadorLabel.ClientID, descripcionFotoLabel.ClientID, fotoActualImage.ClientID, nombreFotoLbl.ClientID, [AjaxMethod(HttpSessionStateRequirement.ReadWrite)] public int TotalDeFotos(string directorioBase) { List<InformacionFoto> dirInfo = ActualizaCache(directorioBase); return dirInfo.Count; } 30 var var var var panelComentarios.ClientID, numeroFotoTbx.ClientID, nombreFotoBase.ClientID, presentacionImgBtn.ClientID, irFotoImgBtn.ClientID, imageBase.ClientID, operationsBasePanel.ClientID ), true ); } //eventos Javascript //navegación primeraImgBtn.Attributes[“onclick”] anteriorImgBtn.Attributes[“onclick”] proximaImgBtn.Attributes[“onclick”] ultimaImgBtn.Attributes[“onclick”] irFotoImgBtn.Attributes[“onclick”] //administración borrarImgBtn.Attributes[“onclick”] renombrarImgBtn.Attributes[“onclick”] comentarImgBtn.Attributes[“onclick”] adicionarImgBtn.Attributes[“onclick”] presentacionImgBtn.Attributes[“onclick”] = = = = = “IrPrimera();”; “IrAnterior();”; “IrProxima();”; “IrUltima();”; “IrAFoto()”; = = = = = “Borrar();”; “PreparaRenombrado();”; “PreparaComentario();”; “PreparaAdicion();”; “PrepararPresentacion();”; } Fuente 2 El método Page_Load del control AlbumFotos << dnm.asp.net El método Page_Load Para poder acceder a los controles desde el código Javascript es necesario que el código del control emita hacia el código del cliente para cada control una variable Javascript que contenga el nombre real del control del lado del cliente. La razón detrás de esto es que en el HTML que se emite hacia el cliente ASP.NET renombra a cada control de la interfaz de forma jerárquica, de manera que, al ocurrir un postback, la jerarquía de controles impuesta por nosotros en el diseñador (o mediante código en el caso de los controles personalizados) pueda ser recompuesta (para más detalles ver otro trabajo publicado en dotNetManía [3]). Note en el fuente 2 que al principio del método se registran dos tipos: AlbumFotos, que representa al álbum de fotos e InformacionFoto, que nos va a servir para contener diferentes datos relacionados con una foto específica. Ambos tipos tuvieron que ser marcados con el atributo Serializable. Debemos generar además algunas variables “de estado” hacia el código Javascript del lado del cliente. En este caso, una variable para el directorio base de modo de poder pasarlo como parámetro a cada uno de los métodos AJAX (marcados con el atributo AjaxMethod) que son llamados desde el cliente hacia el servidor. El valor de esta variable se extrae directamente del atributo DirectorioBase del control, que debe ser especificado en la página que use el control en cuestión, como se muestra en el fuente 3. <<dotNetManía <%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”SamplePage.aspx.cs” Inherits=”SamplePage” EnableEventValidation=”false” %> %> <%@ Register Src=”AlbumFotos.ascx” TagName=”AlbumFotos” TagPrefix=”weboo” %> %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd”> 32 <html xmlns=”http://www.w3.org/1999/xhtml” > <head runat=”server”> <title>Untitled Page</title> </head> <body> <form id=”form1” runat=”server”> <table> <tr> <td> <weboo:AlbumFotos ID=”AlbumFotos1” runat=”server” DirectorioBase=”MisImagenes”/> </td> </tr> </table> </div> </form> </body> </html> Fuente 3 Note que es importante haber registrado el control al inicio de la página mediante: <%@ Register Src=”AlbumFotos.ascx” TagName=”AlbumFotos” TagPrefix=”weboo” %> Observe también que al final del fuente 2 se incluye código para enlazar el evento onclick de cada uno de los controles de navegación y administración del álbum con las funciones Javascript adecuadas. Éstas serán las que finalmente invocarán a los métodos AJAX, como veremos en la próxima sección. Llamada a un método AJAX desde el cliente Para ilustrar, se describe a continuación el código del método Comentar que forma parte de la funcionalidad de nuestro álbum. Del lado del servidor, el código queda como se muestra en el fuente 4. [AjaxMethod] public void Comentar(string directorioBase, string caminoFoto, string comentario) { caminoFoto = CreaCamino(directorioBase, caminoFoto); string caminoMetadata = CreaCamino( directorioBase, Path.GetFileNameWithoutExtension(caminoFoto)+ “.cmt”); FileStream fStream=new FileStream( caminoMetadata, FileMode.Append); using (StreamWriter writer=new StreamWriter(fStream)){ if (fStream.Length == 0) { writer.WriteLine(“#descripcion”); writer.WriteLine(); writer.WriteLine(“#comentarios”); } writer.WriteLine(comentario); } } Fuente 4. El código del método Comentar. Los comentarios a cada unas de las fotos podrían ser guardados en alguna base de datos o usando algún otro mecanismo sofisticado. Por simplicidad, en este ejemplo nos limitamos a usar archivos de texto adicionales ubicados en la misma carpeta de la foto y con el mismo nombre pero extensión .cmt. Estos archivos podrán contener la descripción dada originalmente por el propietario del álbum más todos los comentarios hechos por los usuarios con acceso al álbum. El método Comentar anterior va a ser invocado asíncronamente a través del código Javascript, como se muestra en el fuente 5. << dnm.asp.net [Serializable] public class InformacionFoto { private string nombreArchivo; private string descripcion; private string[] comentarios; public InformacionFoto(string nombreArchivo, string[] comentarios) { this.nombreArchivo = nombreArchivo; CreaComentarios(comentarios); descripcion = comentarios.Length > 0 ? comentarios[0] : null; } AlbumFotos.Comentar( directorioBase,fotoActual, text,rComentar); } private void CreaComentarios(string[] comentarios) { if (comentarios.Length > 1) { this.comentarios = new string[comentarios.Length - 1]; Array.Copy( comentarios, 1, this.comentarios, 0, this.comentarios.Length); } } public string[] Comentarios { get { return comentarios; } } Fuente 5. La función Comentar en Javascript. Note que el método Comentar del lado del servidor (fuente 4) tiene sólo 3 parámetros y sin embargo la invocación que se hace desde Javascript (fuente 5) tiene 4 parámetros. Los tres primeros parámetros son variables de estado Javascript para controlar el funcionamiento de la interfaz del lado del cliente, y cuyos valores son transformados automáticamente por el HTTP handler de AJAX.NET a los valores .NET del método Comentar del fuente 4. El cuarto es una referencia a un callback Javascript que va a ser invocado al término de la llamada asíncrona al servidor, forma muy parecida a la usada en el patrón asíncrono de la propia plataforma .NET. El código de este método rComentar que hace de callback es el siguiente: function rComentar(response){ alert('Su comentario ha sido agregado');} El parámetro response contiene información acerca de la respuesta del servidor. De particular interés son las siguientes propiedades de response: value: contendrá el valor devuelto por el método asíncrono invocado del lado del servidor, en caso de que éste devuelva alguno. error: en el caso que el método del servidor provoque una excepción, ésta viajará hacia el cliente en esta propiedad. Se puede conocer el mensaje de la excepción usando la expresión response.error.Message. Por ejemplo, el método IrAFoto que se utiliza en el fuente 7 devuelve un valor del lado del servidor, con información acerca de la foto a la cual se quiera navegar. Esta información va a estar encapsulada en un objeto de tipo InformacionFoto, cuya definición se muestra en el fuente 6. El código Javascript que invoca al método IrAFoto se muestra en el fuente 7. Observe en el uso de las propiedades Descripcion, Comentarios y NombreArchivo la manera en que AJAX.NET mimetiza el tipo .NET en el proxy Javascript generado. En este caso el valor de res- public string Descripcion { get { return descripcion; } } public string NombreArchivo { get { return nombreArchivo; } } } Fuente 6. La clase InformacionFoto. function ActualizaFoto(indiceFoto, enableCtrls) { ... AlbumFotos.IrAFoto(directorioBase,indiceFoto,rActualizaFoto); ... } function rActualizaFoto(response) { var info = response.value; var src = directorioBase + “/” + info.NombreArchivo; document.getElementById(imagenID).src = src; document.getElementById(nombreFotoID).innerHTML = fotoActual = info.NombreArchivo; document.getElementById(contadorID).innerHTML = “” + (indiceActual+1) + “ de “ + total; document.getElementById(descripcionID).innerHTML = info.Descripcion == null ? “<i>Sin Descripción</i>” : info.Descripcion; var comentarios = info.Comentarios; var panelComentarios = document.getElementById(panelComentariosID); if(comentarios != null) { panelComentarios.innerHTML = “”; for(i = 0 ; i < comentarios.length; i++) { panelComentarios.innerHTML += comentarios[i] + “</br>”; } } else { panelComentarios.innerHTML = “<i>Sin comentarios </i>”; } } Fuente 7. Usando el proxy Javascript generado para InformacionFoto. <<dotNetManía function Comentar() { text = EliminaControlesComentario(); var panelComentarios = document.getElementById(panelComentariosID); panelComentarios.innerHTML = panelComentariosPrevText.startsWith(“<I>”) ? text : panelComentariosPrevText+”<br/>”+text; panelComentariosPrevText = “”; 33 << dnm.asp.net ASP.NET reconstruye la jerarquía de controles a partir del HTML que se envía al servidor en postback. Este mecanismo tiene fuertes controles de seguridad para evitar ataques maliciosos por inyección de código script dentro del HTML que se envía ponse.value es de un tipo Javascript generado al vue- lo por el manejador HTTP de AJAX.NET y que sirve de proxy al tipo .NET mostrado en el fuente 6. AJAX y la seguridad Un último detalle importante: ASP.NET reconstruye la jerarquía de controles a partir del HTML que se envía al servidor en postback. Este mecanismo tiene fuertes controles de seguridad para evitar ataques maliciosos por inyección de código script dentro del HTML que se envía. Como ahora aquí con AJAX.NET se ha modificado dinámicamente el HTML, es necesario validar todo lo que viaja hacia el servidor. Por defecto, ASP.NET lanzaría una excepción al tratar de validar el HTML enviado originalmente hacia el cliente contra el enviado por el cliente hacia el servidor, especialmente en los datos que forman parte de los controles del formulario. Una alternativa para evitar este comportamiento de ASP.NET es especificar que no se va a validar automáticamente la información que venga desde el cliente. Esto se logra usando el atributo EnableEventValidation de la directiva <%@Page> de la página que use nuestro control de usuario: <%@ Page Language=”C#” ... EnableEventValidation=”false”%> En un ejemplo sencillo como el presentado en este artículo, esto sería suficiente para poder combinar el comportamiento usual de algunos controles en ASP.NET, que es producir postbacks, con el control que se está definiendo y que depende en su mayoría de callbacks Javascript. Sin embargo, de modo general la solución no puede ser renunciar a la seguridad; en un escenario más complejo y realista habría que validar en el código Javascript los datos enviados hacia el servidor. Por razones obvias de simplicidad esto no se ha incluido aquí. <<dotNetManía Conclusiones 34 En este artículo se ha mostrado con un pequeño ejemplo cómo usar la biblioteca AJAX.NET para implementar conceptos AJAX en aplicaciones Web ASP.NET. Hay otras alternativas interesantes, como [4] y [5], pero se ha escogido la biblioteca AJAX.NET por su popularidad y por la granularidad que permite. Otros temas más avanzados, como son los convertidores AJAX de dicha biblioteca, podrían servir como tema para futuros artículos. El código fuente completo del ejemplo está disponible a los lectores en el sitio Web de dotNetManía, http://www.dotnetmania.com. La primera respuesta de Microsoft a este “nuevo” estilo de programación de aplicaciones Web ha sido incluir los script callbacks en ASP.NET 2.0 (ver en este mismo número el artículo “Ajax con ASP.NET 2.0. Script callbacks”). Sin embargo, la simpleza de éstos (ya que solo permiten el intercambio entre el código script de cliente y el código de servidor mediante cadenas de caracteres) hizo que la compañía lanzara la propuesta de ATLAS, que promete ser una de las mejores plataformas AJAX para el desarrollo de aplicaciones Web. Ud. puede tener ya un primer encuentro con ATLAS a través del artículo de Miguel Jiménez “Microsoft AJAX Library (Atlas). Cómo extender ASP.NET con lo más ‘cool’ de la Web 2.0” que también está en este número de dotNetManía. Referencias [1] Michael Schwarz, Ajax.NET- The Free Library for NET, http://www.schwarz-interactive.de. [2] Jesse James Garrett, Ajax, A New Approach to Web Applications, http://adaptivepath.com/publications/ essays/archives/000385.php [3] Luis Miguel Blanco, Emitir código JavaScript desde WebForms y controles Web personalizados, dotNetManía Nº 15. [4] Anthem.NET, http://anthem-dot-net.sourceforge.net [5] MagicAjax, http://www.magicajax.net [6] Michael Flanakin, Implementing HTTP Handlers in ASP.NET, http://www.developerfusion.co.uk/show/4643 [7] Ajax Patterns, http://ajaxpatterns.org [8] JSON, JavaScript Object Notation, www.json.org dnm.asp.net Miguel Jiménez Microsoft AJAX Library (Atlas) Cómo extender ASP.NET con lo más “cool” de la Web 2.0 La combinación tecnológica de XHTML, CSS, Javascript y XMLHttpRequest, acuñada bajo el término AJAX desde 2005, representa la fórmula mágica de la poción que está revolucionando el concepto de la Web. Los desarrolladores de ASP.NET pueden unirse a la cruzada tecnológica gracias a Microsoft AJAX Library, una extensión de ASP.NET que proporciona la funcionalidad deseada desde la comodidad del .NET Framework 2.0 y Visual Studio 2005. << Hace algún tiempo que se habla de la revolución de la Web La base de Atlas: callbacks vs. postbacks Miguel Jiménez es Software Development Engineer y Responsable de Formación en ilitia Technologies. MVP de Visual C# desde 2005,es líder de INETA en España y coordinador del Madrid .NET User Group.Colabora frecuentemente con MSDN y otros grupos de usuarios. 2.0 y de las virtudes de AJAX (acrónimo en inglés para Asynchronous Javascript And XML) para crear aplicaciones Web más ligeras, ricas, interactivas y usables. El tipo de desarrollo que propone esta combinación de tecnologías se basa en el uso del objeto XMLHttpRequest desde Javascript para hacer llamadas al servidor que no son percibidas por el usuario. El problema que AJAX intenta solventar está generado por el propio protocolo HTTP, el estándar usado por los navegadores para comunicarse con servidores Web y enviar de vuelta la información. HTTP es un protocolo sin estado, es decir, que para preservar los datos del usuario entre las distintas peticiones hay que escribir código en el servidor que se encargue de ello. La experiencia típica del usuario Web dicta que la página completa se envía al servidor para realizar la persistencia de datos; el servidor devuelve la página actualizada y durante el proceso el usuario percibe un refresco en su navegador, siendo totalmente incapaz de realizar ninguna operación en la aplicación Web mientras se produce la actualización del contenido. Hay muchos avances en esta dirección desde los tiempos “ancestrales” de ASP. Por ejemplo, con la introducción de ASP.NET y el viewstate se eliminó por completo todo el trabajo de gestionar manualmente la persistencia de estado a través de los objetos Request y Response de las aplicaciones Web. Tras la experiencia con los postbacks en las versiones 1.0 y 1.1 del Framework, se intenta mejorar la experiencia del usuario introduciendo el concepto de ASP.NET 2.0 callbacks en el desarrollo Web. El concepto de postback es bien conocido por los desarrolladores de ASP.NET. Es el proceso de enviar la información de un formulario Web desde el navegador del cliente al servidor a través del método POST del protocolo HTTP. Esto sucede cada vez que un control, método o servicio se ha de ejecutar en el servidor o requiere de una actualización. Es tan frecuente en las aplicaciones desarrolladas con ASP.NET que puede llegar a ser extremadamente frustrante. Con ASP.NET 2.0 se introducen los callbacks. Un callback es similar a un postback en que actualiza infor- << dnm.asp.net ¿Qué es Atlas? Atlas [1] se ha construido sobre .NET Framework 2.0 y extiende el soporte de scripts de cliente en los controles de servidor. Se basa en los principios de encapsulación, abstracción y orientación a objetos de ASP.NET 2.0, puesto que no se trata de otra librería que encapsula de forma sencilla las llamadas al objeto XMLHttpRequest, sino de un completo modelo de desarrollo cliente-servidor basado en AJAX y .NET Framework. Atlas proporciona funcionalidad en el cliente y en el servidor. Incluye un conjunto de extensiones de servidor y una librería de scripts de cliente, cuya interacción proporciona un conjunto de tecnologías que da como resultado aplicaciones Web más ricas a la vez que ligeras. Atlas es, por tanto, una librería de desarrollo Web compuesta por controles, scripts, servicios y extensiones de servidor. Scott Guthrie [2] anunció recientemente en su blog la disponibilidad y el nombre definitivo para Atlas, que proporciona además una clara idea de su objetivo y arquitectura: • La librería de scripts de cliente se llamará Microsoft AJAX Library, funcionará con cualquier navegador y con cualquier servidor de backend (PHP, Cold Fusion). • Las extensiones de servidor se llamarán ASP.NET 2.0 AJAX Extensions, y como parte del cambio se modificará el prefijo de las etiquetas de <atlas:> a <asp:>. • El set “Atlas Control Toolkit” se llamará ASP.NET AJAX Control Toolkit e incluirá una extensión de controles para maximizar el valor proporcionado por Atlas. Por último, Scott hizo público que la versión 1.0 de Atlas estará disponible antes de final de año y no junto con el lanzamiento de Orcas en 2007, como estaba previsto inicialmente. Tras esta información, se despejan varias dudas con respecto a Atlas: no es una simple librería para gestionar callbacks y actualizar porciones de páginas Web de manera asíncrona; no es una librería de uso exclusivo para entornos de desarrollo Microsoft; y finalmente, es una librería totalmente extensible y compatible con los estándares actuales. Los escenarios soportados por Atlas no se limitan a actualizar información en el servidor o actualizar porciones de páginas Web con llamadas asíncronas. Atlas permite el desarrollo de interfaces de usuario más ricas, que serían poco prácticas sin este tipo de librería. Por ejemplo, imaginemos una aplicación Web de recetas donde el usuario busca en función de diferentes parámetros: tipo, dificultad, calorías, ingredientes. Se puede escribir el código para realizar una búsqueda basada en estos criterios, pero sería poco usable presentar un DropDownList donde haya cientos de opciones para cada uno de esos parámetros. En este caso, Atlas nos permite utilizar un TextBox donde al escribir las primeras letras de un ingrediente, por ejemplo, se realiza una consulta al servidor que presenta una lista mucho más amigable que coincide con el filtro que se está introduciendo. Este comportamiento se mejora si se realizan sucesivas búsquedas conforme se va completando el ingrediente deseado, añadiendo lo que se conoce como AutoComplete a un TextBox. Es una forma de sugerir el contenido que se puede incluir en un campo determinado sin utilizar el control estándar para esta acción (DropDownList) pero limitando el conjunto de opciones que se pueden introducir. Figura 1 La arquitectura de Atlas En el diagrama de arquitectura mostrado en la figura 1 se observa que la funcionalidad de servidor de Atlas (en la parte derecha) se ha construido extendiendo la funcionalidad de servidor proporcionada por ASP.NET 2.0 y que se engloba dentro de las ASP.NET AJAX Extensions. Incluye un conjunto de controles y puentes de servicios en el lado del servidor. <<dotNetManía mación en el servidor, pero no lanza el proceso para la totalidad de la página, sino que utiliza el objeto XMLHttpRequest para realizar la operación entre bastidores. En el servidor, el proceso tampoco lanza el ciclo de vida completo de un formulario Web, siendo por tanto mucho más ligero de ejecutar. En septiembre de 2005, y como extensión del modelo de callbacks introducido en ASP.NET 2.0, el equipo de desarrollo de ASP.NET lanzó públicamente la primera CTP (Community Technology Preview) de Atlas, una extensión para ASP.NET 2.0 que permitiría crear aplicaciones Web más ricas y ligeras basadas en los principios de AJAX. 37 <<dotNetManía << dnm.asp.net 38 La capa de cliente presentada en el diagrama (en la parte izquierda), “Microsoft AJAX Library”, ofrece una serie de scripts que se encargan de garantizar la compatibilidad entre navegadores, un conjunto de tipos y todo el modelo de controles, componentes y servicios. Tal y como se extrae del anuncio de Scott Guthrie, esta librería de scripts no está atada al lado servidor y se puede utilizar para crear aplicaciones basadas en Javascript sin intervención de un servidor ASP.NET o que utilicen cualquier otro servidor como backend. Sin embargo, el nuevo conjunto de controles de servidor desarrollados para ASP.NET 2.0 con Atlas hace un uso extensivo de esta librería de cliente. La utiliza para comunicar todos los cambios, peticiones y eventos de manera asíncrona al código del servidor. El nuevo modelo de interacción entre cliente y servidor difiere un poco del modelo tradicional presentado por el protocolo HTTP. Gracias al uso de la abstracción del objeto XMLHttpRequest, se pueden actualizar porciones de la página sin provocar un refresco, en lugar de actualizar la página completa en cada petición. El usuario puede seguir trabajando con la aplicación Web e incluso sin percibir que se ha realizado una llamada al código de servidor. El objeto XMLHttpRequest debe su versatilidad a que puede devolver texto plano, XML o notación JSON en una llamada a servidor y posteriormente interpretarlo en el cliente. Para conocer más detalles sobre ambos modelos de interacción entre cliente y servidor, consulte el artículo de Román Fresneda y Miguel Katrib [3] en este mismo número de dotNetManía. El modelo de desarrollo en Atlas es muy práctico, ya que permite desarrollar la misma funcionalidad de varias formas: a través de los controles de servidor de Atlas, programáticamente en el cliente usando las librerías de scripts o usando el nuevo lenguaje declarativo XML Script. Todas las opciones proporcionan la misma funcionalidad y potencia, pero a través de un modelo de desarrollo distinto que ha sido pensado con diferentes perfiles en mente (desarrolladores de controles, diseñadores gráficos y programadores Web). Las extensiones y librerías de Atlas se pueden descargar de http://atlas.asp.net y se instalan localmente en el equipo del desarrollador. Añaden a la herramienta Microsoft Visual Web Developer una plantilla adicional de sitios Web para C# y Visual Basic que aparece cuando seleccionamos la opción “File” > “New” >“Web Site”, tal y como se muestra en la figura 2. El modelo de despliegue de Atlas no implica ninguna instalación en el servidor que aloje las Webs desarrolladas con él. La principal referencia de una aplicación Atlas es la librería Microsoft.Web.Atlas.dll; ésta se copia localmente al directorio bin y actualiza el fichero web.config de la aplicación; las librerías de scripts de cliente se copian igualmente de manera local Figura 2 a la aplicación. Por tanto, las aplicaciones Web desarrolladas con Atlas se pueden desplegar de manera sencilla, sin requisitos de instalación y proporcionando un sistema más flexible de cara a la actualización e instalación side-by-side de diferentes aplicaciones con diferentes versiones del motor de Atlas. Microsoft AJAX Library La librería de cliente es la responsable de generar el modelo de clases y tipos en Javascript que permite utilizar un entorno más familiar para desarrollar aplicaciones AJAX. Esta librería se presenta en diferentes piezas, siendo la base de ellas la capa de Browser Compatibility. Uno de los puntos fuertes de Atlas es el hecho de que sea multiplataforma, es decir, que funcione en la mayor cantidad de navegadores posibles. Esta capa garantiza el funcionamiento de los scripts de cliente en cualquier navegador (Internet Explorer, Firefox, Safari y Opera) y se encarga de realizar la abstracción de las diferentes peculiaridades de Javascript en cada navegador de forma que no afecten al resto de la librería. Se incluyen distintas librerías de Javascript en función del navegador que realiza la petición, por lo que el proceso es totalmente transparente para el desarrollador y para el usuario. Por encima de la compatibilidad de navegadores se encuentra el Type System, una aproximación del sistema de tipos de .NET Framework a Javascript. Permite implementar espacios de nombres, clases y simular herencia haciendo más similares el desarrollo de scripts al de código de servidor y acercando la orientación a objetos a Javascript. La Base Class Library, al igual que su homóloga en .NET Framework, se apoya en el sistema de tipos. Incluye tipos familiares como StringBuilder, Debug, Event e IDisposable, y además contiene: la encapsulación y abstracción del objeto XMLHttpRequest a través de WebRequest, WebResponse y WebMethods; los métodos de serialización con JSON (Javascript Object Notation [4]); y las API de Membership, como Profile y Authentication. << dnm.asp.net El conjunto de controles que se incluirán en Atlas promete ser bastante extenso (casi todos los controles básicos de ASP.NET serán migrados) scripts, aísla la capa gráfica de la de comportamiento, y finalmente se centra en el comportamiento de los objetos y no en cómo implementar dicho comportamiento. Nikhil Khotari [6], desarrollador del equipo de Atlas, expone en su blog más detalles sobre las ventajas y motivos que impulsaron a desarrollar Atlas XML Script en la capa de presentación. Es en el UI Framework donde se agrupan las diferentes tareas asociadas a los controles y sus actividades o comportamientos. Existen actions (acciones), <input type=”text” id=”searchText” /> <input type=”button” id=”searchButton” /> <script type=”text/xml-script”> <page xmlns=”http://schemas.microsoft.com/xml-script/2005”> <references> <add src=”ScriptLibrary/Atlas/AtlasUI.js” /> <add src=”ScriptLibrary/Atlas/AtlasControls.js” /> </references> <components> <textbox id=”searchText” /> <button id=”searchButton”> <bindings> <binding property=”enabled” dataContext=”searchText” dataPath=”text.length” transform=”NumberToBoolean” /> </bindings> <click> <!— Call the invoke method of ServiceMethod when the button is clicked —> <invokeMethod target=”searchMethod” method=”invoke” /> </click> </button> <serviceMethod id=”searchMethod”> <bindings> <!— Bind the query field of the parameters property of the ServiceMethod to the text property of searchText (and keep them in sync) —> <binding property=”parameters” propertyKey=”query” dataContext=”searchText” dataPath=”text” /> </bindings> </serviceMethod> </components> </page> </script> Fuente 1 que representan acciones que llaman a componentes o servicios en un control, behaviors (comportamientos) como el drag and drop y validators (validadores), similares a los comportamientos, pero dedicados a validar controles. Y por supuesto, un completo modelo de binding que permite enlazar diferentes propiedades de los controles con otros controles, objetos, componentes o servicios. El conjunto de controles que se incluirán en Atlas promete ser bastante extenso (casi todos los controles básicos de ASP.NET serán migrados), entre ellos, por ejemplo, temporizadores, contadores, vistas de lista y un divertido control de mapas basado en VirtualEarth. Como el modelo es 100% extensible, se ha creado un proyecto open source donde desarrollar aquellos controles que sean interesantes para la comunidad de programadores, que se ha denominado Atlas Control Toolkit [7] y se puede encontrar en Codeplex [8]. ASP.NET 2.0 AJAX Extensions Finalmente, llegamos a la parte de servidor. Se distribuirá con nombre y funcionalidad muy distinta a la librería de cliente. Es la encargada de instrumentar ASP.NET 2.0 con operaciones AJAX basándose en la Microsoft AJAX Library. Por un lado, como se apreciaba en la figura 1, tenemos la nueva rama de controles de servidor, Atlas Server Controls. Son similares en nombre y funcionalidad a los actuales controles Web, pero incluyen nuevos métodos y propiedades para gestionar eventos y scripts de cliente orientados a crear aplicaciones AJAX. Dentro de este conjunto de controles hay dos especialmente importantes, que <<dotNetManía Desarrollar una capa de controles y componentes es una tarea mucho más sencilla una vez se dispone de una sólida base de desarrollo con orientación a objetos, tipos y un lenguaje más familiar. Estas capas se sitúan sobre las tres anteriores y se denominan: Controls and Components y Component Model and UI Framework. La capa de controles y componentes no es de uso obligatorio. Se puede desarrollar una aplicación AJAX usando únicamente el núcleo de Atlas, pero no tendremos acceso a los controles de servidor y otras funcionalidades altamente recomendables. Esta capa de componentes incorpora un nuevo lenguaje de persistencia que, sin escribir una línea de Javascript, permite definir el comportamiento de un control. Este lenguaje se denomina Atlas XML Script, y es un lenguaje declarativo basado en XML que, tal y como se puede observar en el fuente 1, aporta varias ventajas: simplifica la lectura del código, elimina la necesidad de escribir 39 <<dotNetManía << dnm.asp.net 40 usados conjuntamente minimizan los postbacks de cualquier aplicación Web. Por un lado, el control ScriptManager, que se encarga de modificar el modelo postback desde cliente, y en segundo lugar el control UpdatePanel, que controla el ciclo de vida de la página en el servidor para conseguir actualizar solo porciones en el cliente. El control ScriptManager se ha de incluir en todas las páginas que utilicen funcionalidad de Atlas y se encarga de manejar el código HTML, Javascript, XML Script y datos del viewstate en las llamadas de callback al servidor. Este control se guía por el UpdatePanel para determinar qué regiones ha de gestionar y actualizar. Pueden existir tantos UpdatePanel como se desee, de forma que diferentes regiones de la página se actualicen de forma independiente. Además, Atlas incluye dos bridges (puentes) a servicios. Un bridge es un enlace que permite comunicar la capa de cliente con servicios remotos o locales. Sirven de punto de entrada o conexión a la capa cliente con una determinada funcionalidad en el servidor. En primer lugar, disponemos del App Services Bridge que enlaza con los servicios de aplicación de ASP.NET 2.0 como Membership, Roles y Authentication. Está directamente representado en el especio de nombres Sys.Services.Authentication de la librería de cliente y permite acceder desde Javascript a toda la funcionalidad proporcionada por ASP.NET 2.0. En segundo lugar, tenemos el Web Services Bridge, que como su nombre indica enlaza con servicios Web locales o remotos para que puedan ser llamados directamente desde la capa de cliente. Los servicios accesibles incluyen aquellos desarrollados con ASP.NET (.asmx), los desarrollados con Windows Communications Foundation (.svc) y aquellos métodos marcados como [WebMethod] en las páginas Web. Son directamente accesibles desde el código cliente a través de un proxy que se genera en Javascript. La creación de este proxy es posible gracias a un HttpHandler introducido por Atlas que gestiona el código generado para un WSDL en Javascript (utilizando la librería de cliente de Microsoft AJAX Library). En el fuente 2 se puede observar el código Javascript generado como proxy de un var SearchAutoComplete=new function() { this.path = “http://localhost/TestAtlas/SearchAutoComplete.asmx”; this.appPath = “http://localhost/TestAtlas/”; var cm = Sys.Net.ServiceMethod.createProxyMethod; cm(this,”GetCompletionList”,”prefixText”,”count”); } Fuente 2 <script type=”text/javascript” language=”JavaScript”> function CallWebService() { requestSimpleService = SearchAutoComplete.GetCompletionList( 5, // Parametros OnComplete, // Evento OnComplete OnTimeout // Evento TimeOut ); return false; } function OnComplete(result) { alert(result); } function OnTimeout(result) { alert(“Timed out”); } </script> Fuente 3 servicio Web local con un único métorio. Microsoft AJAX Library y Microsoft do, y en el fuente 3 como utilizarlo desASP.NET 2.0 AJAX Extensions proporde cliente con Atlas. cionan las herramientas que simplifican Los servicios han de ser generalel desarrollo de Webs más ligeras y ricas. mente locales, puesto que hay que utiPuede que la próxima killer app esté desalizar el HttpHandler que genera el proxy rrollada con Atlas, no podría garantizarlo… pero sí puedo garantizar que pronto y por tanto, para enlazar con un servitendremos mucho más contenido relacio remoto (proporcionado por otro proveedor) es necesario crear un Service cionado con Atlas y la creación de aplicaBridge local que se enlazará desde la capa ciones Web 2.0. de cliente. Esto representa todo un avance en el desa- Referencias rrollo de aplicaciones Web MashUp [9] con Atlas, que [1] Microsoft Atlas, http://atlas.asp.net. hasta ahora no presentaba [2] Scott Guthrie, http://weblogs.asp.net/scottgu una alternativa muy alentaRomán Fresneda y Miguel Katrib, AJAX: Redefiniendo la dora para reutilizar servicios [3] forma de ver la Web, dotNetManía Nº 31 (este ejemplar). desarrollados por terceros. [4] Javascript Object Notation (JSON), http://www.json.org Conclusiones Las aplicaciones Web del futuro son una realidad hoy en día. Utilizan servicios Web, carga asíncrona de datos e interfaces de usuario que tienen poco que envidiar a las aplicaciones de escrito- [5] Historia de XMLHttpRequest, http://en.wikipedia.org/wiki/XMLHTTP [6] [7] [8] Nikhil Kothari, http://www.nikhilk.net [9] MashUp, http://en.wikipedia.org/wiki/Mashup_(web_ application_hybrid) Atlas Control Tookit, http://atlas.asp.net/atlastoolkit Codeplex, http://www.codeplex.com dnm.sharepoint Gustavo Vélez Presentación de SharePoint SharePoint es el servidor con el crecimiento más acelerado de todos los productos de Microsoft. Éste es un artículo introductorio sobre el producto, su arquitectura, programabilidad y la nueva versión que aparecerá en corto plazo. << Qué es SharePoint Figura 1. Página principal del portal SharePoint 2003 Arquitectura Windows SharePoint está basado en Microsoft SQL Server (o MSDE) como repositorio de configuración e información y ASP.NET como framework. Un concepto básico del diseño de SharePoint es que todos los documentos, datos de listas y la información sobre configuración y contenido en general son guardados en las bases de datos y no en archivos físicos en los servidores. WSS utiliza dos bases de datos, una para configuración del sistema y otra para contenido; SPS agrega otras dos bases de datos, una para guardar datos sobre los usuarios que permite personalizar individuamente el sistema, y otra para el funcionamiento de la máquina de búsqueda. <<dotNetManía Gustavo Vélez es Ingeniero Mecánico y Electrónico, especializado en el diseño, desarrollo e implementación de software (MCSD) basado en tecnologías de Microsoft, especialmente SharePoint. Es creador y webmaster de http://www.gavd.net/servers, y trabaja com Senior Developer en Winvision (http://www.winvision.nl) Microsoft SharePoint es la familia de servidores creados por Microsoft con el propósito de servir como herramientas de colaboración y comunicación, y diseñados para conectar personas, información, procesos y sistemas dentro y fuera de una organización. SharePoint 2003 está constituido por dos componentes: Windows SharePoint Services (WSS) es un integrante de Windows 2003 y Windows 2003 R2 que permite compartir datos y documentos, cooperar en tareas compartidas e intercambiar mensajes sin abandonar las aplicaciones de Microsoft Office, y que además ofrece la infraestructura para crear sitios Web que pueden servir como sitios de reunión e intercambio, configurar su seguridad y los permisos necesarios para los usuarios. Los servicios por defecto de WSS incluyen la máquina de búsqueda dentro del contexto de cada sitio, sistemas de alertas y flujo de trabajo para aprobación de documentos. Windows SharePoint Server (SPS) está construido sobre la base de WSS y amplía sus posibilidades de colaboración ofreciendo un portal que permite organizar la información en una forma estructurada; provee una máquina de búsqueda más poderosa que permite indexar información no solo dentro del contexto de diferentes sitios, sino también en sistemas externos a SharePoint (otros servidores Web, Exchange), provee un “Mi Sitio” (portal personal para cada usuario), audiencias para dirigir información a grupos de usuarios específicos y “SingleSign-On” para conectar a otras aplicaciones utilizando las credenciales del usuario sin necesidad de volverse a identificar. 41 << dnm.sharepoint Funcionalmente hablando, SharePoint utiliza una serie de plantillas que sirven como base para el diseño y formación gráfica de cada página en cada sitio. Las plantillas proveen el código HTML estático básico para crear cada página. Detrás de cada plantilla existe un archivo dinámico, programado en Collaborative Application Markup Language (CAML), que contiene grupos de definiciones para ampliar y generar el código HTML específico de cada página dentro del sitio. Las plantillas son cargadas en memoria interna en el servidor al inicio de su funcionamiento, y cuando un usuario solicita una página, SharePoint busca la información necesaria (basada en los derechos del usuario) en la base de datos, la integra en la plantilla respectiva y envía el código HTML resultante de regreso. Este diseño garantiza que los tiempos de respuesta sean lo más cortos posibles: el “esqueleto” de cada página está siempre disponible, y solamente es necesario recuperar la información delta específica desde la base de datos, mezclar ambos y generar el código HTML. SharePoint utiliza servidores virtuales para facilitar la creación de servidores aislados en un solo sistema. Por defecto, después de una instalación estándar, solamente se crea un servidor virtual que sirve como sitio de administración, pero el administrador del sistema puede crear hasta 99 servidores virtuales por instalación física de SharePoint. En SPS, cada portal es de hecho un servidor virtual. Todos los servidores virtuales utilizan el mismo conjunto de plantillas, por lo que los cambios realizados en ellas afectarán a todos los sitios y portales creados. Internet Information Server (IIS) es el servidor dentro de Windows encargado de manejar las solicitudes HTTP, pero SharePoint 2003 modifica su comportamiento por medio de un filtro ISAPI para controlar rutas administradas o inclusiones y exclusiones. El filtro ISAPI se encarga de determinar si una solicitud debe ser procesada dentro del contexto de SharePoint, o si se trata de un proceso separado, ejecutado por otra aplicación o por el servidor Web. En SharePoint 2007 el filtro ISAPI ya no es necesario, pues SharePoint se comporta como una aplicación ASP.NET manejada dentro del contexto normal de IIS. IIS además controla toda la autenticación primaria de usuarios (anónima, básica o integrada de Windows) para cada servidor virtual, y administra la forma de habilitar solicitudes anónimas, si es necesario. Después de que un usuario ha sido autenticado por IIS y Windows, y ha sido aceptado por el sistema, SharePoint se encarga del proceso de autorización, basado en los permisos definidos dentro de WSS/SPS para cada usuario. El Directorio Activo de Windows puede ser utilizado como sistema de autenticación, y SharePoint se encarga de definir los derechos que cada usuario tiene en cada página, e inclusive dentro de los diferentes componentes de una misma página. Administración y escalabilidad SharePoint está diseñado para poder responder rápidamente con cargas muy altas de usuarios. El sistema de mezcla de plantillas en memoria y contenido delta desde la base de datos garantiza que la respuesta del sistema no se degrada con el aumento de usuarios. Cuando las cargas empiezan a ser demasiado altas, la arquitectura del sistema permite crecer horizontalmente, es decir, con agregar nuevos servidores físicos al lado de los existentes, e implementando un sistema de balanceo de cargas, el aumento de usuarios se puede absorber de una forma sencilla. Según las especificaciones, una instalación de SharePoint puede contener hasta 2 millones de documentos por cada librería (cada documento con un máximo de 2 GB), 2.000 librerías por sitio Web y 250.000 sitios por cada servidor virtual. En cuanto a usuarios, si son registrados individualmente (no en grupos de AD), el sistema puede manejar un máximo de 2 millones. La cantidad de documentos está más limitada por la capacidad máxima de SQL Server que por SharePoint, y la cantidad de servidores en una configuración de granja depende de la versión y configuración de Windows, no de SharePoint. La configuración y administración de SharePoint se realiza desde una aplicación Web, e incluye la distribución de la topología del sistema (cuáles servidores realizan qué tipo de tarea), configuración de bases de datos y sistemas auxiliares, importación de datos de usuarios desde el Directorio Activo, configuración de grupos de usuarios y sus derechos y creación (y eventual eliminación) de servidores virtuales. Los usuarios con suficientes derechos pueden crear sitios Web y determinar qué <<dotNetManía SharePoint está aquí para quedarse y su importancia aumenta cada día más 42 usuarios pueden trabajar dentro de ellos, el administrador del sistema solamente necesita darles derechos locales de administrador a los usuarios encargados de la creación de sitios. SharePoint viene por defecto con herramientas especializadas para darle respaldo al sistema, que junto con las herramientas de respaldo de SQL forman la estrategia indicada para recuperación de desastres. Figura 2.Administración central de SharePoint 2003 Programabilidad SharePoint 2003 está basado en el ASP.NET Framework 1.1 de Microsoft, aunque WSS y algunas partes de SPS son compatibles con el Framework 2.0. Por lo tanto, Visual Studio 2003 es la herramienta de programación, y CSharp y Visual Basic .NET son los lenguajes recomendados. SharePoint presenta una extensa API que cubre todos los aspectos de WSS/SPS y permite interactuar programáticamente con el sistema. La API de WSS 2003 contiene 13 namespaces con aproximadamente 170 clases, y SPS añade otros 16 namespaces con 310 clases. Además, existen otros 20 namespaces no documentados por Microsoft, dedicados al funcionamiento interno de SharePoint. El modelo de objetos tiene tres objetos principales de alto nivel: SPSite, que representa una colección de sitios Web, SPWeb, que representa un sitio Web individual, y SPGlobalAdmin, utilizado para la administración y configuración global. Cada elemento funcional de WSS y SPS puede ser programado, incluyendo añadir, editar, borrar y devolver datos de listas y librerías, crear nuevas listas con sus metadatos (campos personalizados), trabajar con documentos de librerías (proteger, desproteger, aprobar, rechazar, crear, modificar, eliminar), y todas las tareas administrativas como crear, eliminar y modificar sitios Web, añadir usuarios y modificar sus derechos. Una característica especial de SharePoint son sus WebParts. Windows SharePoint Services 2001 fue el primer servidor de Microsoft que introdujo el concepto de WebPart, un elemento programáticamente aislado del centro funcional de SharePoint, pero que se puede instalar en una página para realizar una función específica. Las WebParts son controles Web que residen en un contenedor (zona de WebParts) dentro de cada página Web. El Framework 2.0 de Windows adaptó y generalizó el sistema de WebParts, haciéndolo utilizable para cualquier aplicación Web, pero SharePoint 2003 no puede utilizar WebParts programadas para el Framework 2.0. Las WebParts representan la forma más fácil y rápida para extender la funcionalidad de SharePoint, y, probablemente, es la labor de programación que más se realiza dentro de WSS/SPS. Una vez creada, una WebPart consta principalmente de un archivo .dll con el código compilado, y un archivo .dwp (XML) con su definición; otros archivos pueden formar parte de una WebPart (recursos, configuración, localización), y SharePoint ofrece la posibilidad de crear un archivo .cab comprimido que contiene todos los archivos necesarios y que se puede instalar en los servidores utilizando la herramienta de administración de SharePoint. Un sistema completo de SOAP WebServices es instalado por defecto con SharePoint. WSS 2003 proporciona 16 WebServices que permiten realizar las tareas básicas del sistema, y SPS agrega otros 3 para trabajar específicamente con el portal. Aunque no tan extendido y poderoso como el modelo de objetos de la API, los WebServices proporcionan la posibilidad de poder interactuar con WSS y SPS remotamente y desde otros sistemas que no necesariamente sean basados en tecnologías Windows. Cuando los WebServices estándar no son suficientes, la API permite programar WebServices personalizados que realicen tareas específicas, y que funcionen dentro de su contexto. Para modificar el layout y capa de presentación de SharePoint se pueden crear nuevas plantillas, y se pueden utilizar hojas de estilo (CSS) personalizadas. Otras plantillas permiten crear páginas Web especializadas en donde aparezca la funcionalidad necesaria para un trabajo específico. Para la programación de plantillas es necesario tener conocimientos de CAML, que en cuanto a estructura y sintaxis difiere bastante de C# y Visual Basic. En cuanto a las hojas de estilo, cada sitio Web utiliza algunos archivos .css predefinidos, pero es posible configurar el sistema para que utilice una hoja de estilo personalizada. Todos los elementos gráficos en cada página están definidos por una clase de estilo, así que es posible cambiar visualmente las páginas de una forma radical. <<dotNetManía << dnm.sharepoint 43 << dnm.sharepoint Cambios esperados en la versión 2007 SharePoint forma parte de la división Office de Microsoft, y como tal, en el año 2007 aparecerá la nueva versión. La familia de servidores, que en la versión 2003 consta de WSS y SPS, será ampliada, incluyendo diferentes versiones de SPS, una de las cuales reemplazará al actual Content Management Server (CMS) de Microsoft como servidor para extranet. Además, incluirá dos servidores auxiliares, uno para Excel (cálculo y contención de hojas de cálculo en un servidor centralizado) y otro para InfoPath (presentación de formularios InfoPath como páginas Web, e interacción con ellos sin necesidad de tener InfoPath instalado localmente). <<dotNetManía Figura 3. SharePoint 2007 como Content Management System 44 Arquitectónicamente, el diseño básico se mantendrá intacto. SharePoint podrá utilizar SQL 2000 o SQL 2005 como base de datos, pero con SQL 2005 se beneficiará de una mejor y más rápida respuesta debido a la mayor optimización de éste. El sistema de plantillas combinadas con información delta de la base de datos para generar HTML es también igual, aunque en la nueva versión se utiliza la tecnología de Páginas Maestras introducida por el Framework 2.0. En cuanto a programación, todo el código está basado en el Framework 2.0 de .NET, siendo ahora Visual Studio 2005 la herramienta a utilizar. Las WebParts podrán utilizar las clases originales de SharePoint 2003 (por compatibilidad), las clases definidas por el Framework 2.0, o las clases definidas por SharePoint 2007 mismo (que contienen algunas mejoras especialmente pensadas para WSS). La API ha sido radicalmente ampliada, incluyendo todos los namespaces y clases necesarias para funcionar como sistema de manejo de contenido (CMS), aunque la compatibilidad con la API de 2003 ha sido garantizada. Funcionalmente han sido introducidos numerosos cambios, como la integración con el Workflow Figura 4. Página principal del portal SharePoint 2007 Foundation para poder utilizar flujos de trabajo especialmente programados (con Visual Studio o con el SharePoint Designer, anteriormente conocido como FrontPage). La infraestructura de permisos ha sido ampliada, cubriendo autorización a nivel de documentos, y no solamente a nivel de librerías, como ocurre en la versión 2003. Nueva es también la posibilidad de crear blogs y páginas Wiki (páginas Web colaborativas), y la mejora de la máquina de búsqueda y la forma de presentación de datos encontrados. SharePoint proporcionará herramientas de migración, tanto para migrar sistemas de CMS hacia la nueva versión, como para migrar instalaciones de WSS y SPS. Las herramientas incluyen no solamente la migración propiamente dicha, sino también herramientas de análisis para poder predeterminar los posibles problemas. Microsoft ha definido tres estrategias de migración, que cubren toda la gama de sistemas empleados: migración “En sitio” (actualización del sistema) para sistemas pequeños, “Gradual” (las dos versiones instaladas paralelamente) para sistemas medianos, y “Migración de Bases de Datos” para sistemas con grandes cantidades de contenido. Conclusiones SharePoint es el servidor que Microsoft ha escogido como centro para su estrategia de intercambio de información. Como tal, el producto esta aquí para quedarse, y su importancia y aceptación aumentan cada día. El servidor ha llegado también a un punto de madurez tecnológica que lo hace muy estable, fácilmente escalable y flexible por las posibilidades que ofrece como plataforma de desarrollo. La versión 2007 continúa el camino señalado, aumentando la funcionalidad por defecto, e integrando extranet e intranet en un solo servidor. Referencias http://www.microsoft.com/spain/servidores/sharepoint http://www.gavd.net/servers dnm.inicio.fundamentos dnm.incio.fundamentos Guillermo “Guille” Som Relación entre delegados y eventos El avisador que te avise, buen avisador será En el número anterior vimos con detalle casi todo lo concerniente a los delegados, y aunque solo lo viésemos de pasada, comprobamos la relación entre los delegados y los eventos. En este número nos centraremos en los eventos, pero antes comprobaremos que hay ciertas características de los delegados que los hacen imprescindibles para usarlos con los eventos. << Delegados Delegados multidifusión: unión de varios delegados [ ] NOTA Guillermo “Guille” Som es Microsoft MVP de Visual Basic desde 1997. Es redactor de dotNetManía, miembro de Ineta Speakers Bureau Latin America, mentor de Solid Quality Iberoamericana y autor del libro Manual Imprescindible de Visual Basic .NET. http://www.elguille.info A lo largo de este artículo, usaré delegate con la primera letra en minúscula para referirme a la instrucción que tanto C# como Visual Basic utilizan para definir delegados. Pero cuando quiera hacer referencia a la clase System. Delegate, usaré la primera letra en mayúscula; así los programadores de C# no se confundirán con los cambios de mayúsculas y minúsculas que tanto les afecta, porque en ese lenguaje, el tamaño (de las letras) sí que importa. Como ya comenté en el artículo anterior, los delegados multidifusión son los que en realidad nos permiten que los eventos tengan el comportamiento que tienen y nos permitan utilizarlos de forma muy flexible. En un momento veremos por qué. Al usar la instrucción delegate, creamos en realidad un objeto de tipo MulticastDelegate. Veamos que nos dice la documentación de Visual Studio 2005 sobre esta clase: Representa un delegado multidifusión; es decir, un delegado que puede tener más de un elemento en su lista de invocación. Está claro, en este caso no hay dudas sobre el significado. Y debido a que éste es el tipo de delegado que siempre usaremos (o al menos el que usaremos en un gran porcentaje de las ocasiones), en adelante al indicar que usamos un delegado será para referirnos a este tipo de delegado que permite tener más de un elemento asociado, ya que, como acabamos de comprobar, los delegados que podemos crear por medio de la instrucción delegate son de este tipo de delegados “compuestos”. Ahora que sabemos qué es un delegado multidifusión, veamos cómo podemos unir varios delegados en uno solo. Agregar delegados a la lista de un delegado multidifusión En C# los operadores += y -= están sobrecargados para poder utilizarlos con este tipo de delegados, de forma que si queremos añadir más de un dele- <<dotNetManía Cuando definimos un delegado tanto en C# como en Visual Basic usamos la instrucción delegate. Esa instrucción en realidad lo que hace es definir un tipo de datos especial. Y la primera impresión es que en realidad esa instrucción utiliza el tipo definido en la propia librería de clases de .NET que tiene el mismo nombre: System.Delegate. Pero no es así: en realidad el tipo de datos que obtenemos con una declaración por medio de la palabra clave delegate es System.Multicast Delegate, que está basada en la clase Delegate. En esta primera parte del artículo nos centraremos en la clase MulticastDelegate y en cómo se pueden agrupar varios métodos delegados en un mismo objeto delegado, además de ver cómo podemos invocar a todos esos métodos con una sola llamada. 45 << dnm.inicio.fundamentos gado a la lista de delegados lo haremos usando precisamente el operador de asignación e incremento (+=). Veamos un ejemplo de cómo agrupar varios delegados y cómo invocarlos, y cuando veamos lo que ocurre, lo tendremos todo más claro. En el fuente 1 tenemos una definición de un delegado, el cual es una plantilla para un método de tipo void (no devuelve nada) y que recibe como parámetro una cadena. En ese mismo código fuente, tenemos tres métodos que podemos usar con una variable definida mediante ese delegado; cada uno de los métodos muestra la cadena pasada como argumento en la consola, pero de forma diferente, con la idea de que podamos ver que es lo que en realidad está ocurriendo. Pero lo que aquí tenemos que “demostrar” es cómo agregar más de un método a una misma variable, y tal como vimos al principio de esta sección, debemos hacerlo mediante el operador +=, por tanto, si usamos el código mostrado en el fuente 3, conseguiremos lo que estamos buscando. // La definición del delegado delegate void MostrarCadenaCallback(string str); Como vemos en dicho código fuente, la forma de asociar varios delegados es la misma que cuando asignamos solo uno, con la única diferencia del operador usado para dicha asignación. Y con el operador de asignación y suma también podemos usar las dos formas de asignar el método al que se llamará desde el delegado. Lo más interesante de todo esto está en la última línea. Cuando invocamos al delegado pasándole el parámetro que espera (en este caso una cadena), éste se encargará de llamar secuencialmente a todos y cada uno de los métodos delegados que hayamos añadido a la variable que hace referencia al delegado multidifusión. El orden de llamada a cada uno de los métodos que tenemos en la lista del delegado es el mismo en el que hemos añadido esos métodos; por tanto, el código del fuente 3 producirá la siguiente salida: // Varias definiciones del método con la firma adecuada // para el delegado MostrarCadenaCallback // Muestra la cadena sin alterar static void mostrarStr(string str){ Console.WriteLine(str); } // Muestra la cadena en mayúsculas static void mostrarUpper(string str){ Console.WriteLine(str.ToUpper()); } // Muestra la cadena en minúsculas static void mostrarLower(string str){ Console.WriteLine(str.ToLower()); } Fuente 1. Definición de un delegado y tres métodos que tienen la misma firma Para usar ese delegado y asociarlo a cualquiera de los métodos lo haríamos tal como vemos en el fuente 2. En este caso solo usamos uno de los tres métodos que hemos definido, en particular el método mostrarUpper. MostrarCadenaCallback delegado1; //delegado1 = new MostrarCadenaCallback(mostrarUpper); delegado1 = mostrarUpper; delegado1(“Hola delegado”); <<dotNetManía Fuente 2. La forma habitual de usar un delegado e invocarlo 46 Al ejecutar el código del fuente 2, comprobaremos que el mensaje indicado se muestra completamente en mayúsculas, que en realidad es lo que esperamos que ocurra, y tal como vimos en el artículo anterior tenemos dos formas de asignar a la variable delegado1 el método que vamos a usar; la asignación que está comentada es la que tendríamos que usar en las versiones anteriores a Visual C# 2005. MostrarCadenaCallback delegado2; delegado2 = new MostrarCadenaCallback(mostrarStr); delegado2 += new MostrarCadenaCallback(mostrarLower); delegado2 += mostrarUpper; delegado2(“¡Hola Delegado!”); Fuente 3.Asociar varios métodos con una misma variable de tipo delegado ¡Hola Delegado! ¡hola delegado! ¡HOLA DELEGADO! De la misma forma que podemos añadir nuevos métodos a un delegado, podemos quitar métodos que previamente hayamos añadido. Para ello usaremos el operador -=, el cual se usa exactamente como el que acabamos de ver, pero su función es eliminar delegados de la lista. Si queremos quitar un delegado que no está previamente añadido no se produce ninguna excepción; simplemente la petición se ignora. Si al código del fuente 3 le agregamos la siguiente línea antes de llamar al delegado, lo que conseguiremos es que solo haya dos métodos en la lista del delegado: delegado2 -= mostrarLower; Nuevamente comprobamos que también podemos usar la forma “abreviada” para quitar métodos de la lista de delegados. << dnm.inicio.fundamentos NOTA Definir eventos En Visual Basic no hay forma de añadir y quitar métodos de la lista de un delegado multidifusión,al menos de la forma como se hace con C#. La única forma de hacerlo es por medio de los métodos compartidos Combine y Remove de la clase Delegate o del delegado que definamos, aunque el valor devuelto siempre es del tipo Delegate. Para llamar al delegado podemos usar el método Invoke de la clase Delegate o bien usar la llamada directa, en cuyo caso el objeto debe ser del tipo del delegado que estamos combinando. En el código de ejemplo que acompaña al artículo hay varios métodos con distintas formas de usar el método Combine y Remove. Todo esto es así de complicado si trabajamos directamente con delegados que no están relacionados con eventos,ya que si trabajamos con eventos, podemos usar las instrucciones AddHandler y RemoveHandler para conseguir la misma funcionalidad de los operadores += y -= respectivamente. Como ya vimos en el artículo anterior, la definición de un evento está estrechamente ligada con los delegados, particularmente en el caso de C#, ya que en Visual Basic podemos definir eventos sin que tengamos que asociarlos con delegados, al menos desde el punto de vista del programador; el compilador de Visual Basic se encarga de la relación entre la definición del evento y el delegado que debe tener asociado el evento que definamos. El hecho de que cada evento esté relacionado con un delegado es porque la forma de lanzar ese evento (o lo que es lo mismo, la forma de notificar que ese evento ha ocurrido) es llamando al delegado con los parámetros que hayamos definido. Por ejemplo, si queremos tener un evento en una clase para que nos notifique cada vez que se modifica el contenido de una propiedad, tendremos que definir un delegado que indique la “firma” que debe tener el método que vaya a recibir dicha notificación. Además, debemos definir el evento propiamente dicho, el cual será una variable especial del tipo del delegado. Lo de “variable especial” es porque en realidad se define como cualquier otra variable (solo que con un tipo delegado como tipo de datos), pero añadiéndole la instrucción event. En el fuente 4 vemos la definición del delegado y el evento. Nomenclatura en las definiciones de los delegados Para finalizar el tema de los delegados, una nota sobre la nomenclatura recomendada. En la definición de los delegados se recomienda el sufijo EventHandler para los nombres de delegados que se utilizan en eventos y el sufijo Callback para los nombres de delegados que no sean manejadores de eventos. En caso de que definamos una clase para usar como parámetro de un delegado relacionado con un evento, debemos añadirle el sufijo EventArgs si dicha clase se deriva de System.EventArgs. Una vez hechas estas aclaraciones, pasemos a ver qué son y cómo definir y usar los eventos. public delegate void NombreCambiadoEventHandler( string nuevo, string anterior); public event NombreCambiadoEventHandler NombreCambiado; Fuente 4. Definición de un evento y el delegado asociado ¿Qué es un evento? En este ejemplo, definimos un delegado que recibe dos parámetros; el primero es el nuevo valor que hemos asignado a la propiedad y el segundo el que tenía antes de asignar ese nuevo valor. A continuación definimos el evento, que es del tipo del delegado. Como vemos, en realidad la definición del evento no se diferencia mucho de cómo definiríamos una variable que quisiéramos tener relacionada con un evento, salvo porque utilizamos la instrucción event para definirla. Esa instrucción hace que exista “automáticamente” una relación entre el delegado y el evento, de forma que no tengamos que instanciar expresamente el delegado para poder usarlo. Usar los eventos de una clase Una vez que tenemos definido el evento en una clase, podemos recibir notificaciones cada vez que ese evento se produzca. Por supuesto, la clase que define el evento es la que se encargará de producir el evento para informar a los objetos que deseen recibir dicha notificación. <<dotNetManía Un evento es un mensaje (o notificación) que lanza un objeto de una clase determinada cuando algo ha ocurrido. El ejemplo más clásico y fácil de entender es cuando el usuario pulsa con el ratón en un botón de un formulario. Esa acción produce, entre otros, el evento Click del botón en el que se ha pulsado. De esa forma, el botón notifica que esa acción ha ocurrido, y ya es cuestión nuestra que hagamos algo cuando eso ocurra. Si estamos interesados en interceptar ese evento tendremos que comunicárselo a la clase que define el botón; si no lo estamos, simplemente no es necesario que indiquemos nada. Como es de suponer, los eventos se pueden definir en cualquier clase, y no solo en clases que tengan algún tipo de interacción con el usuario, aunque lo más habitual es que precisamente se usen con clases que forman parte de la interfaz gráfica que se le presenta al usuario de una aplicación. De esa forma podremos saber que algo está ocurriendo y en qué control, de forma que sepamos en todo momento lo que el usuario quiere hacer o lo que está haciendo. 47 << dnm.inicio.fundamentos Para recibir el mensaje del evento, debemos crear un método que tenga la misma firma que el delegado que hemos asociado a dicho evento. Usando el evento definido en el fuente 4, la asociación deberíamos hacerla tal como vemos en el código del fuente 5. Cliente cli = new Cliente(); cli.NombreCambiado += new Cliente.NombreCambiadoEventHandler( cli_NombreCambiado); Figura 1. Creación automática del delegado adecuado desde el editor de Visual C# 2005 Figura 2. Creación automática de un método con la firma del delegado asociado con el evento Fuente 5.Asociación de un evento con un método [ ] NOTA El método indicado en el constructor del delegado debemos definirlo con la firma determinada por el propio delegado, quedando la definición tal como vemos en el fuente 6. void cli_NombreCambiado(string nuevo, string anterior) { label2.Text = “Se ha cambiado el nombre:\n” + “Nuevo valor: “ + nuevo + “\n” + “Valor anterior: “ + anterior; } Debido a que los eventos, de forma predeterminada, son miembros de instancia (están asociados con cada instancia de la clase que los define), si creamos un nuevo objeto de esa clase debemos volver a asociar el método que recibirá la notificación del evento. Esto no es necesario si esa clase solo la instanciamos una vez y usamos siempre la misma instancia. Fuente 6. Definición del método que recibirá la notificación cuando se produzca el evento. <<dotNetManía Producir un evento 48 Como podemos apreciar, la forma de asociar el evento con el método que recibirá la notificación cada vez que éste se produzca es usando el operador +=, que como vimos es la forma que tienen los delegados multidifusión de añadir los métodos que recibirán el aviso cada vez que dicho delegado sea llamado; en el caso de los eventos, ese aviso se iniciará cuando lancemos el evento desde la clase que lo define (en un momento veremos cómo). Una pega que podemos encontrarnos es con la definición del método que recibe el evento. En realidad no es un problema, ya que si sabemos que definición tiene el delegado sabremos cuál debe ser la definición de dicho gestor de evento. Pero para que nos resulte más cómodo, el editor de Visual C# 2005 nos facilita dicha creación; incluso nos permite saber cuál es el delegado asociado con el evento que queremos interceptar. En las figuras 1 y 2 vemos cómo el IDE de Visual Studio 2005 nos permite tanto usar el delegado correcto (figura 1) como la creación del método con la firma adecuada (figura 2). De esta forma, no tendremos que buscar la definición del delegado para crear de forma fácil el método que debemos usar. Una vez que tenemos la definición del delegado y el evento en nuestra clase, tenemos la posibilidad de lanzar o producir dicho evento. Cuándo y dónde lanzar el evento depende de nuestro código. En el ejemplo de la clase Cliente que produce un evento cada vez que se modifica la propiedad Nombre, lo haremos de la forma que mostramos en el fuente 7. private string m_Nombre; public string Nombre { get { return m_Nombre; } set{ if( NombreCambiado != null ) { NombreCambiado(value, m_Nombre); } m_Nombre = value; } } Fuente 7. La forma de producir un evento en C# En el bloque set es donde lanzamos el evento. En este ejemplo lo lanzamos se modifique o no el contenido de la propiedad, pero ese detalle no es lo << dnm.inicio.fundamentos [ ] NOTA Veremos cómo definir, interceptar y lanzar los eventos en Visual Basic en un próximo artículo dedicado exclusivamente a los eventos desde el punto de vista de ese lenguaje, en el que también veremos cómo usar la nueva instrucción Custom Event , exclusiva de Visual Basic 2005. Interceptar el mismo evento más de una vez Como podemos comprobar en el código mostrado en las secciones anteriores, la asociación entre un evento y el método que recibirá la notificación de que dicho evento produce lo hacemos mediante el operador +=. Si esa asociación la hacemos con varios métodos, todos y cada uno de esos métodos recibirán la notificación de que el evento se ha producido. Esto es posible porque en el fondo la instrucción event en realidad está definiendo un objeto del tipo MulticastDelegate , y como vimos al principio de este artículo por medio Un evento es un mensaje (o notificación) que lanza un objeto de una clase determinada cuando algo ha ocurrido de ese tipo de delegado podemos “asociar” varios métodos con un mismo delegado. Por tanto, todos los métodos que agreguemos por medio del operador += estarán listos para recibir el mismo mensaje que lancemos (ver fuente 7). Y tal como vimos en el código del fuente 3, el orden en el que se notificarán será el mismo en el que hayamos añadido esos métodos a la lista de métodos que quieren recibir el evento. Esa asociación la podemos realizar tanto usando un nuevo método como usando un método ya existente. En este último caso, ese método se ejecutará tantas veces como veces esté en la lista de delegados que recibirán la notificación, algo que seguramente no será de mucha utilidad, pero que es posible. Y debido a que podemos hacerlo, debemos tenerlo en cuenta, para que no ocurra esa múltiple notificación. Por ejemplo, si la clase que produce eventos solo la instanciamos una vez, y utilizamos el siguiente código para “ligar” el método con el evento: cli.NombreCambiado += new Cliente.NombreCambiadoEventHandler( cli_NombreCambiado); Cada vez que ejecutemos esa línea se añadirá el método cli_NombreCambiado a la lista de métodos que recibirán la notificación, y cuando el evento se produzca, se llamará esa misma cantidad de veces, consiguiendo algo que seguramente no era lo que queríamos. Un mismo método que recibe eventos de clases diferentes En el mismo ejemplo que estamos usando, podemos asociar un mismo método para que reciba notificaciones de objetos diferentes, ya que si la firma del método coincide con la del delegado del evento, ese método lo podremos usar sin ningún tipo de problema. Esto es aplicable no solo al objeto “cli” que hemos definido en el ejemplo, sino a cualquier otra instancia que creemos del tipo Cliente (o cualquier otra clase que queramos usar, siempre que el método tenga la misma firma que el delegado correspondiente); de esa forma podremos ahorrarnos algo de código. Debido a que el ejemplo de la clase Cliente puede que no nos aclare mucho, veamos esto último usando controles y eventos definidos en los controles de Windows.Forms. Por ejemplo, si tenemos varios controles de tipo TextBox en un formulario y queremos seleccionar todo el texto que tenga ese control al recibir el foco (cuando el control es el control activo), podemos hacer una múltiple asociación con un mismo método, tal como vemos en el fuente 8. Ni qué decir tiene que todos los eventos (como es este caso), deben tener la misma firma, lo cual no implica que deban ser del mismo tipo, ya que lo único que en realidad importa es que el delegado asociado con el evento tenga la misma definición que el método que recibirá la notificación del evento. En el caso de los contro- this.textBox1.Enter += new System.EventHandler(this.textBox_Enter); this.textBox2.Enter += new System.EventHandler(this.textBox_Enter); this.textBox3.Enter += new System.EventHandler(this.textBox_Enter); Fuente 8.Asociación de eventos de clases diferentes con un mismo método <<dotNetManía importante; en lo que de verdad debemos fijarnos es en la comprobación de si el evento no es nulo, ya que debemos hacer esa comprobación, con idea de lanzar el evento solo si alguien lo está interceptando; en caso contrario no debemos llamar al delegado multidifusión, que es en realidad el que se encarga de “propagar” el mensaje a todos los métodos que hayamos definido para recibir el mensaje. Si alguien está esperando la notificación del evento, usamos el mismo nombre del evento (que en realidad es un MulticastDelegate) para lanzar el evento, indicando los parámetros adecuados (en nuestro ejemplo, el nuevo valor de la propiedad y el valor que tenía antes). Y una vez que hemos producido el evento es que asignamos el nuevo valor al campo que mantiene el contenido de esa propiedad. 49 << dnm.inicio.fundamentos les de Windows.Forms, ese mismo método lo podríamos asociar a un botón: this.button1.Enter +=new EventHandler(this.textBox_Enter); Lo que sí debemos tener en cuenta es que el código que usemos en ese método esté preparado para que los controles puedan ser de tipos diferentes, tal como vemos en el código del fuente 9. private void textBox_Enter(object sender, EventArgs e) { labelInfo.Text = “El foco lo tiene “+ ((Control)sender).Name; if( sender is TextBox ) { ((TextBox)sender).SelectAll(); } } Fuente 9. Si un mismo método se producirá desde clases diferentes debemos tenerlo en cuenta en el código. <<dotNetManía Añadir “manejadores” de evento 50 Cuando estamos trabajando con formularios y controles, la asociación entre un evento y el método que usaremos para interceptarlo lo podemos hacer de varias formas. Una de ellas es de forma totalmente manual, que es la que hemos visto anteriormente; pero para ser sinceros, esa no será la forma habitual de asociar un evento con un método, ya que el diseñador de formularios de Visual Studio 2005 nos ofrece una forma más sencilla. Para “ligar” un evento con un método (y crearlo si no existe), debemos seleccionar el control que define el evento que queremos usar y en la ventana de propiedades seleccionar “Eventos” (el botón con la imagen de un rayo amarillo). De esa forma tendremos una lista de los eventos definidos por ese control (o al menos de los eventos que el creador del control haya decidido que se muestren en esa ventana de propiedades). En la figura 3 podemos ver algunos de los eventos de un formulario. Como vemos en la figura 3, si el evento está asociado a un método, se muestra el nombre del mismo; si no hay ninguna asociación, el campo se muestra en blanco. Para crear un nuevo método y asociarlo al evento, simplemente tendremos que hacer una doble pulsación en la caja de textos en blanco. Pero si lo que queremos es usar uno de los métodos existentes, podemos seleccionar el método de la lista desplegable; en esa lista solo se mostrarán los métodos que tengan la misma firma del delegado asociado con ese evento, tal como podemos ver en la figura 4, donde el delegado del evento Click tiene la misma firma que los mostrados en dicha lista, lo que nos permite usar cualquiera de los existentes o bien crear uno nuevo. Figura 3. Desde la ventana de propiedades podemos seleccionar el evento que queremos interceptar Figura 4. Podemos asociar un evento a un método existente, el cual seleccionamos de una lista desplegable Lo único que no nos permite el diseñador de formularios es asociar varios métodos de eventos a un mismo evento. En ese caso, tendremos que hacer manualmente esa asociación. La pregunta puede ser ¿dónde hacer esa asociación? La respuesta es: donde queramos, pero siempre que ese código no se repita más de una vez, con idea de no agregar más veces de las necesarias el método que intercepta el evento. Por tanto, lo más recomendable es que escribamos ese código en el constructor del formulario, pero justo después de la llamada al método InitializeComponent. Esto también es válido para cuando decidamos asociar manualmente los eventos con los métodos que recibirán la notificación. Conclusiones En este artículo hemos visto cómo trabajar con los eventos en C#: desde cómo definirlos hasta cómo interceptarlos y cómo están relacionados los eventos con los delegados, principalmente con los delegados multidifusión, gracias a los cuales podemos asociar un mismo evento con varios métodos. Si a lo comentado en este artículo le añadimos todo lo dicho en el artículo anterior, dedicado casi exclusivamente a los delegados, tenemos todo lo necesario para entender cómo trabajan los eventos y los delegados. Pero no todo está dicho: aún hay ciertas cosas que necesitamos saber para sacarle todo el rendimiento a los eventos y delegados, principalmente a los que definamos en nuestras propias clases. Pero eso lo dejaremos para otro artículo en el que también trataremos estos conceptos desde el punto de vista del programador de Visual Basic. Como siempre, el código de los ejemplos usados en el artículo está disponible (tanto para C# como para Visual Basic) desde el sitio Web de dotNetManía. dnm.todotnet.qa Dino Esposito Más allá del mito Discusión sobre AJAX y ATLAS << Alguien en Redmond debe haber sido mordido por el gusa- Dino Esposito es mentor de Solid Quality Learning y autor de “Programming Microsoft ASP.NET 2.0 Core Reference” y “Programming ASP.NET 2.0 Applications Advanced Topics”, ambos de Microsoft Press.Afincado en Italia, Dino es un ponente habitual en los eventos de la industria a nivel mundial.Visite su blog en: http://weblogs.asp.net/despos. Puede enviarle sus consultas a [email protected] nillo de la mitología griega, últimamente. Sólo así se entiende la repetida mención de nombres como Ajax –el popular héroe de la guerra de Troya– y Atlas, uno de los Titanes primordiales, condenado a soportar sobre sus hombros el peso de la Tierra. Ciertamente, AJAX no es una marca registrada por Microsoft, sino un término acuñado para identificar un montón de tecnologías Web, utilizadas por Google (y otros) para construir buenas aplicaciones. Como mi hijo de 8 años ya sabe, AJAX significa Asynchronous Javascript And XML. Atlas es simplemente el nombre en código de la plataforma Microsoft basada en AJAX para ASP.NET. Hacia el final del verano de 2006, se cambió el nombre de AJAX por el de ASP.NET 2.0 AJAX Extensions, así que el pobre titán puede descansar en paz. Hola Dino, gracias por tus artículos y tu labor de escritura. Tengo un problema del que estoy casi seguro que habrás escrito algún artículo o que tendrás una respuesta rápida. Estoy tratando de ejecutar Javascript en el cliente en el evento de postback. Más concretamente, intento mostrar un GIF animado del tipo “Por favor, espere” mientras se prepara el servidor. Pero no se produce animación, supongo que porque la página está siendo reprocesada. ¿Quieres primero una respuesta del tipo sí o no? De acuerdo, tu suposición es totalmente correcta y puedes olvidarte de mostrar un GIF animado en una actualización clásica tipo postback en la página activa. Esto es por diseño, y tiene más que ver con el navegador que con ASP.NET. Un GIF animado es sencillamente una colección de sub-imágenes o marcos que la aplicación manejadora muestra periódicamente en una hebra de background. La hebra está activa dependiendo del estado de la página que lo contiene. Cuando haces un post- back, el navegador congela la página y destruye la hebra. Cualquier interacción entre el navegador y cualquier elemento de la página se detiene, y consecuentemente, cesa la animación. Dispones de dos opciones “conservadoras”, y otra algo más intrusiva. La más sencilla es usar un fichero GIF estático o un mensaje. ¿No te gusta, no? La segunda opción supone el uso de una página intermedia o quizás un marco para mostrar el mensaje con soporte completo de animación. Harías el reenvío de la página que muestra el feedback del usuario y cargarías la página de destino en el evento onLoad de la etiqueta <body>; de esta forma, la página de transición se mantiene hasta que se carga la otra. Sin embargo, algunos amigos me han comentado que siguen teniendo dificultades asociadas con esta técnica en lo referente a los GIF animados. ¿Qué es lo que falta? Una aproximación tipo AJAX, o similar. Es una buena solución utilizar las extensiones de AJAX, aunque esto supone añadir algún fichero binario a la aplicación instalada. Si AJAX no es una opción, puedes convertir el control en un botón de cliente y enlazarlo a una rutina script callback. Las rutinas de callback en ASP.NET son una característica nativa de ASP.NET 2.0 y no requieren vínculos externos. El API es un tanto extraño, pero funciona bien. El problema, en este caso, es cómo actualizar la página después del postback. El script callback termina por llamar a un método servidor en la página y devuelve al cliente una cadena. La actualización de la interfaz de usuario del cliente para reflejar esta situación es algo enteramente opcional. Y podría no ser divertido. En resumen, lo más sencillo que podrías hacer para mantener el GIF animado mientras se procesa la página es usar un poco de las extensiones de AJAX. Tienes <<dotNetManía Las extensiones AJAX constituyen la siguiente gran novedad en el desarrollo de ASP.NET,como puede ver el lector en este número de la revista.En esta columna responderé algunas cuestiones que he recogido en las pasadas semanas, tratando de hacer una introducción al mundo AJAX de forma suave y gradual. 51 << dnm.todotnet.qa que encapsular el botón y la porción de interfaz de usuario afectada por el clic en un control UpdatePanel. <atlas:ScriptManager runat=server ID=ScriptManager1/> <atlas:UpdatePanel …> <contenttemplate> <%— Tu viejo código ASP.NET —%> <contenttemplate> </atlas:UpdatePanel> De esta forma, cualquier postback causado por el código incluido en el panel es transformado en un postback de AJAX, sin refresco de la página completa. Si muestras un GIF animado durante el refresco de la página, la animación continuará hasta que la página esté lista. Y existe otro control tipo AJAX que todavía facilita más las labores de este tipo: el control Update Progress. A continuación incluyo un fragmento de código real que recorre las páginas de un DataGrid, utilizando un GIF animado por cada página (fuente 1). El control UpdateProgress se enlaza a cualquier control UpdatePanel de la página y se muestra siempre que se refresca uno de los paneles. No hay que preocuparse por mostrar o esconder el panel de progreso, lo hará ASP.NET. La figura 1 da una idea de lo que puede esperarse ver. Figura 1. Controles UpdatePanel y UpdateProgress mostrando un GIF animado mientras la página se recarga y se refrescan los datos. <atlas:ScriptManager ID=”scriptManager” EnablePartialRendering=”true” runat=”server” /> <<dotNetManía <atlas:UpdatePanel ID=”UpdatePanel1” runat=”server”> <ContentTemplate> <asp:GridView ID=”GridView1” runat=”server” DataSourceID=”ObjectDataSource1” AllowPaging=”True” AutoGenerateColumns=”False”> <Columns> <asp:BoundField DataField=”ID” HeaderText=”ID” /> <asp:BoundField DataField=”CompanyName” H eaderText=”Company”/> <asp:BoundField DataField=”Country” HeaderText=”Country”/> </Columns> </asp:GridView> <asp:ObjectDataSource ID=”ObjectDataSource1” runat=”server” TypeName=”IntroAtlas.CustomerManager” SelectMethod=”LoadByInitial” /> </ContentTemplate> </atlas:UpdatePanel> 52 <atlas:UpdateProgress runat=”server” ID=”UpdateProgress1”> <ProgressTemplate> <div> <img alt=”” src=”/Images/indicator.gif”/> <span id=”Msg”>Please, wait ... </span> <input id=”abortButton” type=”button” runat=”server” value=”Cancel”/> </div> </ProgressTemplate> </atlas:UpdateProgress> Fuente 1 Existen un par de puntos a tener en cuenta. Estoy asumiendo que la operación del lado del servidor lleva un cierto tiempo en completarse: suficiente como para justificar la barra de progreso. Esto no es muy probable en un DataGrid sencillo. Sin embargo, puede aplicarse la combinación de controles usada más arriba siempre que exista un refresco de página que lleve tiempo suficiente. Internamente, el control UpdatePanel ejecuta una petición colateral que simula el clásico postback, excepto que está limitado a los controles del panel. No hay necesidad de cambiar el estilo de programación para poder apreciar los beneficios de AJAX. El segundo punto a considerar tiene que ver con el botón “Cancel” de la figura 1. ¡Exactamente! Puedes abortar la operación e interrumpir el proceso de refresco de la página. Más concretamente, puedes cortar solo la conexión entre navegador y servidor y cerrar el socket relacionado. Si el servidor ha comenzado una operación crítica (tal como vaciar todas las tablas de una base de datos), no hay mucho que puedas hacer para detenerlo. Simplemente, te ahorrarías un mensaje del tipo “misión completada”. Como en el fragmento de código anterior, el botón de abortar es simplemente un botón <input> nombrado como AbortButton y marcado con el atributo runat=”server”. Atlas me interesó mucho al principio porque prometía ejecutar la mayor parte de mi código desde el cliente: en particular el enlace a datos. Me encantaría poder pulsar un botón y descargar un DataSet en el cliente que llenara una tabla de forma incremental. ¿Recuerda cómo funcionaban los ficheros GIF en Netscape hace unos años? ¿Cree que Atlas me ofrece un modo de ver cómo se llena un DataGrid a medida que van descargándose las filas en el navegador del cliente? No estoy seguro de cómo te vas a tomar mi ambigua respuesta. La respuesta es “más o menos”. De otra forma, es como preguntar cómo ves un vaso: ¿medio lleno o medio vacío? Metáforas aparte, el enlace a datos del lado del cliente te suministra la posibilidad de descargar un DataSet y utilizarlo para rellenar elementos HTML enlazados. Pero, deberíamos de ponernos de acuerdo en el significado exacto de “incremental”. No sé realmente cómo Netscape interpretaba gráficamente los ficheros GIF y soy totalmente lego en lo que se refiere a la estructura interna de estos ficheros. Lo que sé de los navegadores se limita al hecho de que establecen una nueva petición por cada imagen enlazada, y solicitan la imagen completa. Es posible que la estructura interna de los ficheros GIF haga posible que los navegadores muestren porciones de la imagen a medida que se descargan. Pero las cosas son diferentes en el enlace a datos para Atlas. El enlace a datos es una operación en dos pasos: primero, obtienes los datos; después los enlazas a un control, y el control los utiliza para rellenar su estructura. En otras palabras, la interpretación gráfica (rendering) sucede incrementalmente; no así la descarga de los datos. El << dnm.todotnet.qa <div id=”tableResults”></div> <div style=”display: none;”> <div id=”table_layoutTemplate”> <table cellpadding=”2”> <thead class=”tableHeader”> <tr> <td><b>Book</b></td> <td><b>Info</b></td> </tr> </thead> <tbody id=”tableResults_itemTemplateParent” class=”tableContent”> <tr id=”table_itemTemplate” > <td> <img id=”table_Cover” src=”” alt=””/> </td> <td> <span id=”table_ISBN”></span><br/> <span id=”table_Title”></span><br/> <span id=”table_Publisher”></span> <br/> </td> </tr> </tbody> </table> </div> </div> Fuente 2 Como puedes ver, la plantilla consta de dos partes. El bloque vacío llamado tableResults es, simplemente, el punto de inserción del resultado final. El bloque oculto no es interpretado gráficamente por el navegador; en su lugar es interpretado por el control ListView para generar el código de marcado final que será inyectado en el bloque previo. La correspondencia entre los elementos HTML de la plantilla y los datos, así como el rol de cada fragmento HTML se define en una rutina de XML Script (fuente 3). <listView id=”tableResults” itemTemplateParentElementId= ”table_itemTemplateParent”> <layoutTemplate> <template layoutElement=”table_layoutTemplate”/> </layoutTemplate> <itemTemplate> <template layoutElement=”table_itemTemplate”> <label id=”tableResults_ISBN”> <bindings> <binding dataPath=”ISBN” property=”text”/> </bindings> </label> <label id=”tableResults_Title”> <bindings> <binding dataPath=”Title” property=”text”/> </bindings> </label> <label id=”tableResults_Publisher”> <bindings> <binding dataPath=”Publisher” property=”text”/> </bindings> </label> <image id=”tableResults_Cover”> <bindings> <binding dataPath=”CoverPicture” property=”imageURL” /> </bindings> </image> </template> </itemTemplate> </listView> Fuente 3 El control ListView contiene dos bloques de etiquetas fundamentales: layoutTemplate e itemTemplate. El nodo <layoutTemplate> señala el ID del elemento HTML que representa la raíz del ListView. El nodo <itemTemplate> indica el bloque de HTML que hay que repetir por cada ítem de datos enlazado. Los nodos <binding> definen enlaces entre propiedades de los datos y elementos del árbol HTML. El control ListView implementa la interpretación gráfica incremental, esto es, muestra código de marcado de forma automática para cada subconjunto de filas que se procesa: 5 a la vez. Sin embargo, cuando empieza el proceso de interpretación los datos ya se han descargado en su totalidad en el cliente. Puedes asociar datos a un control ListView de dos formas: por programa, o de manera declarativa. Si optas por la opción de programa, añadirías algún código Javascript del tipo: var tableResults = $(“tableResults”); tableResults.control.set_data(results); La función $ es un atajo o alias de document.getElement ById. El argumento results indica el valor de retorno del método de un servicio Web, tal como un ADO.NET DataTable o una colección de datos .NET. No hay que decir que la variable results es un objeto Javascript que simula una colección o un objeto DataTable. El enlace declarativo se realiza a través de un componente DataSource de cliente, como se muestra en el fuente 4. El nodo <binding> indica que el ListView está enlazado al origen de datos específico. En particular, la propiedad de datos del control ListView se rellena con los contenidos de la propiedad de datos del origen de datos. Los contenidos del origen de datos se suministran a través de un servicio Web especial: una clase que hereda de la clase base DataService y adorna sus <dataSource id=”dataSource1” serviceURL=”MyDataSource.asmx”/> <listView id=”tableResults” itemTemplateParentElementId= ”table_itemTemplateParent”> <bindings> <binding dataContext=”dataSource1” dataPath=”data” property=”data” /> </bindings> </listView> Fuente 4 métodos con atributos que permiten especificar los métodos Select, Update, Insert y Delete. Me doy cuenta que esta es muy poca información, pero las restricciones de espacio no me permiten explayarme más. Para información más detallada y código fuente, podrías consultar la obra editada por Microsoft Press titulada “Introducing ASP.NET 2.0 AJAX Extensions”, que será publicada en el mes de noviembre de este año. Traducción por Marino Posadas <<dotNetManía enlace a datos requiere la acción combinada de dos componentes: un control de origen de datos y un control de enlace a datos. Atlas dispone de dos controles de cliente enlazados a datos: ListView e ItemView. El primero suministra una vista de datos tipo listado; el segundo provee de una vista de datos para un único registro. Ambos están basados en plantillas y no disponen de mecanismo de interpretación visual incrustado . Pero requieren de una plantilla HTML para definir su interfaz de usuario. A continuación mostramos una plantilla que genera una tabla HTML con una fila de cabecera y dos columnas: 53 dnm.laboratorio.net Lorenzo Ponte TestRunner for Visual Studio 2005 Todo lo que no se gestiona no se puede mejorar. La calidad es uno de los aspectos básicos a la hora de desarrollar una aplicación. En el laboratorio de este número analizamos una herramienta especialmente indicada para gestionar la calidad del software; basada en la realización de pruebas unitarias, nos permitirá cuantificar la calidad de las aplicaciones. << ¿Qué son las pruebas unitarias? Las pruebas unitarias son una aproximación dinámica a la verificación de un programa. Estas pruebas consisten en ejecutar un programa de testing contra el código de la aplicación que estemos desarrollando. Mediante las baterías de pruebas que genera el programa, podremos determinar tanto los errores como la calidad en el rendimiento de la aplicación. TestRunner es uno de esos programas diseñados para realizar pruebas unitarias contra aplicaciones diseñadas en Visual Studio .NET. Integrado en el IDE de Visual Studio (existen versiones tanto para VS 2003 como para 2005), es capaz mediante un solo clic de lanzar aproximadamente 1400 pruebas en 5 segundos. Mediante una interfaz muy intuitiva, la herramienta nos permite planificar diferentes tipos de tests, que incluso se Características principales de TestRunner • Integración en el IDE de Visual Studio • Ejecución a través del menú contextual • Resultados de las ejecuciones en formato gráfico • No bloquea la correcta ejecución de Visual Studio bas, se pueden ver los posibles errores, así como el tiempo que tardan en ejecutarse las distintas pruebas unitarias. Los resultados se almacenan en un fichero de registro con el fin de poder estimar la mejora en el rendimiento de la aplicación una vez se hayan subsanado o corregido las partes del código que TestRunner nos ha indicado. La herramienta también permite ir directamente a la línea de código responsable de un error desde su interfaz. TestRunner se ejecuta en hilos diferentes a los que utiliza Visual Studio. Esto garantiza que no interfiera en la correcta ejecución y compilación de los programas. Conclusiones Lorenzo Ponte es redactor de dotNetManía. Es Arquitecto de Sistemas y Aplicaciones .NET. Experto en Datawarehousing y Business Intelligence, Marketing Intelligence, CRM analítico. Actualmente es consultor de la empresa Matchmind y Webmaster de clikear.com pueden ir modificando a medida que TestRunner se ejecuta. Una de las principales características a destacar de TestRunner es la forma de mostrar los resultados que se van obteniendo de la ejecución. Según van avanzando las prue- Cuantificar la calidad del software es uno de los puntos pendientes todavía en muchos desarrollos. Desde el laboratorio de dotNetManía recomendamos la utilización de este tipo de herramientas, con los que podemos llegar a una aproximación bastante fiable con el fin de obtener una mayor calidad en nuestros proyectos. Ficha técnica Nombre TestRunner Versión 2.2.2005.0615 Fabricante Mailframe Web www.mailframe.net/Products/TestRunner Categoría Calidad del Software Precio Sin especificar Valoración << dnm.biblioteca.net dnm.biblioteca.net Por Marino Posadas Programación con ASP.NET 2.0 Jesse Liberty y Dan Hurwitz Editorial: Anaya Multimedia & O’Reilly ISBN: 8441520526 Páginas: 1.056 Primera edición: 2006 Idioma: Castellano Como el lector podrá adivinar por su extensión, se trata de una auténtica enciclopedia del desarrollo de ASP.NET 2.0, abarcando todos los problemas comunes (y otros que no lo son tanto), con un espíritu didáctico y abundantes ejemplos de código sin dejar atrás ningún tema importante. Fundamentos de Bases de datos con Visual Basic 2005 Thearon Willis Editorial: Anaya Multimedia & Wrox ISBN: 8441520534 Páginas: 736 Primera edición: 2006 Idioma: Castellano Otra muestra del anterior acuerdo de colaboración de Anaya con editoriales extranjeras es esta interesante obra de Thearon Willis, centrada en el tratamiento de datos con Visual Basic 2005. Bien escrita y abundantemente decorada con ejemplos de todas clases, queremos destacar el énfasis que se hace en las operaciones críticas de mantenimiento de datos: selección, inserción, borrado y modificación. Se dedican a cada uno de esos apartados muchas páginas, explicando los problemas que pueden aparecer y sugiriendo un sinfín de soluciones a cuestiones del día a día. También se incluyen comparativas de utilización (SQL Server/Oracle), un par de útiles capítulos para el tratamiento de datos desde Access (que todavía sigue usándose en un porcentaje significativo de entornos), un adecuado tratamiento del acceso a datos desde ASP.NET y un análisis del uso de servicios Web que devuelven datos. Una obra muy completa. <<dotNetManía << Poco después de valorar una de las obras de Jesse Liberty, nos llega otra novedad –publicada junto a Dan Hurwitz– fruto de la colaboración de Anaya Multimedia con la editorial O’Reilly, que amplia así la oferta de obras de autores extranjeros. Bien traducida, no queremos dejar de mencionar entre sus valores –que son muchos–, los aspectos colaterales propios del desarrollo Web, a veces obviados por otros autores y que aquí tienen tanta importancia como el resto (configuraciones, memoria caché y rendimiento, funcionamiento del servidor IIS, instalaciones, creación de controles personalizados, etc.). 55 [ ] dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>> dnm.club > << dnm.desvan Marino Posadas noticias.noticias Vista está en RTM (Ready to Manufacture) desde el 20 de Octubre,pero el SP3 de XP se retrasa Microsoft presenta el futuro de las videoconferencias con RoundTable Los datos son ya oficiales. Para cuando estas líneas vean la luz, Vista habrá sido presentado oficialmente en SIMO de Madrid y Tech-Ed’06 de Barcelona, pero el producto está en plena fase de distribución final, para hacerle disponible al público en Enero/07 como estaba previsto. No obstante, el siguiente service pack de Windows XP (SP3) ha sufrido un retraso desde finales de 2007 hasta la primera mitad de 2008, en lo que parece la adición de un conjunto funcional de cierta envergadura. No hay que olvidar, además, que .NET Framework 3.0 promete estar plenamente operativo tanto para XP como para Windows Server 2003. Documentos en la Red Tour Visual sobre la nueva interfaz de usuario de Windows Vista. Un recorrido por las nuevas características visuales de Vista, que estará a punto de salir cuando el lector lea estas líneas. Publicado por ComputerWorld en http://www.computerworld.com/ action/article.do?command=viewArticleBasic&articleId=9003926. Y no es el único documento sobre el tema. Cabe destacar igualmente el publicado por CNET News, que hace un compendio (“Piecing together Vista”) de todas las novedades surgidas en torno a Vista desde primeros de año hasta el último momento (http://news.com.com/2009-1016_36050105.html?part=rss&tag=6050105&subj=news) El nuevo producto presentado oficialmente en la página de Microsoft con un artículo explicativo (http://www.microsoft.com/ presspass/features/2006/oct06/1020officeroundtable.mspx) está previsto que aparezca oficialmente para mediados de 2007. Combina las características de unos auriculares con micrófono, con las ofrecidas por el nuevo dispositivo, que la compañía espera comercializar a un precio aproximado de 3.000$. En la página antes citada, Gurdeep Singh Pall, vicepresidente del Grupo de Comunicaciones en Microsoft, explica con más detalle las capacidades de RoundTable. Utilidades del mes Media Coder: Simplemente, baste la siguiente lista de formatos soportados: MP3, Ogg Vorbis, AAC, AAC+, AAC+V2, MusePack, WMA, RealAudio FLAC, WavPack, Monkey's Audio, OptimFrog, AAC Lossless, WMA Lossless, WAV H.264, Xvid, DivX, MPEG 1/2/4, H.263, Flash Video, 3ivx*, RealVideo*, Windows Media AVI, MPEG/VOB, Matroska, MP4, RealMedia*, ASF/WMV, Quicktime*, OGM* CD, VCD, DVD, CUE Sheet. Con todos ellos es capaz de trabajar esta herramienta gratuita de conversión, disponible en http://www.rarewares.org/mediacoder. Blogs del mes <<dotNetManía El almacenamiento del mañana. Documento publicado 58 Blog de Internet Explorer. Es un blog más por Jack Germain en CIO Today, y disponible en http://www.cio-today.com/story.xhtml?story_title= Data_Storage_of_Tomorrow&story_id=1110078RANZX. Hace un recorrido por el camino previsible de las mejoras en el almacenamiento del software, coincidiendo en casi todo con lo que ya apuntara Jim Gray a esta revista, hace más de un año. o menos oficial, mantenido por ocho de los desarrolladores de IE7. Podemos encontrar desde soluciones a problemas de instalación, hasta trucos, atajos, mejoras funcionales, consejos, etc. Disponible en http://blogs.msdn.com/ie. LifeHacker: Recursos de enseñan- Blog de Robert Hurlbut. za gratuitos, que alguien se ha tomado la molestia de recopilar y publicar en http://lifehacker.com/software/education/technophilia-get-a-free-college-education-online-201979.php. Muy completo blog sobre noticias del desarrollo en .NET, conferencias, eventos y actividades en la red. Contiene un montón de artículos desde su puesta en marcha en 2003, y dispone de un listado de blogs recomendadas sobre seguridad que es una auténtica referencia del tema.