Integrándonos continuamente Integrándonos continuamente
Transcripción
Integrándonos continuamente Integrándonos continuamente
www.dotnetmania.com nº 50 julio-agosto 2008 6,50 € Visual Basic • C# • ASP.NET • ADO.NET • AJAX • Silverlight • .NET Framework dotNetManía dedicada a los profesionales de la plataforma .NET Integrándonos continuamente Opinión Factorías de software. Justificación y ventajas Laboratorio.NET Aspose.Total for .NET Dan Fernandez TodotNet@QA Plantillas ASP.NET e inferencia de tipos en C# Developer and Platform Evangelism Team Microsoft Corp. entrevista El Marco de trabajo de entidades de ADO.NET v3.5 (VII) • Paneles para el mundo 3D • Frameworks para Javascript • Componentes de uso general • Extender o no extender... Los métodos extensores en Visual Basic 2008 editorial dotNetManía Dedicada a los profesionales de la plataforma .NET Vol. III •Número 50 • Julio-agosto 2008 Precio: 6,50 € ¡Podemos! Editor Paco Marín ([email protected]) Redactor jefe Marino Posadas ([email protected]) Editor técnico Octavio Hernández ([email protected]) Redacción Dino Esposito, Guillermo 'Guille' Som, Luis Miguel Blanco y Miguel Katrib (Grupo Weboo) Empresas colaboradoras Alhambra-Eidos Krasis Plain Concepts Raona Solid Quality Mentors Además colaboran en este número Antonio Quirós, Daniel Seara, Iskander Sierra, Juan Carlos Viñas, Luis Fraile, Mario del Valle y Unai Zorrilla. Ilustraciones Portada: Javier Roldán Atención al suscriptor Pilar Pérez ([email protected]) Edición, suscripciones y publicidad .netalia c/ Robledal, 135 28522 - Rivas Vaciamadrid (Madrid) www.dotnetmania.com Tf. (34) 91 666 74 77 Fax (34) 91 499 13 64 Imprime Gráficas MARTE Bienvenido al número 50, de julio/agosto de 2008, de dotNetManía. ¡Podemos! Éste ha sido el lema para la selección española, campeona de Europa 2008. Es un lema simple, pero que dice más de lo que parece: dice que nos enfrentamos ante un reto difícil pero conseguible; que somos capaces, más capaces de lo que muchos creen; puede interpretarse como un mensaje de auto-convencimiento o auto-motivación; aunque también parece querer infundir tranquilidad a los nerviosos aficionados. Con este ejemplar, van 50 dotnetmanías, y no es que signifique nada en especial, pero cumplir números redondos parece que haya que celebrarlo de alguna forma, y qué mejor que hacer nuestro ese lema de la selección de española de fútbol y decir ese ¡podemos! para afrontar los próximos 50. Para ayudarnos en tarea tan motivante nos hemos aliado con Alhambra-Eidos para conformar, difundir y participar en planes formativos para desarrolladores .NET y también para profesionales TI, siempre en el entorno de las tecnologías de Microsoft. Empezamos con un laboratorio de dos días de Silverlight 2.0, impartido por nuestro redactor jefe Marino Posadas, del que puede ver más información en www.alhambra-eidos.es. Marino está actualmente trabajando en el primer libro de Silverlight 2.0 en castellano, que publicaremos como nuestro Cuaderno Técnico nº9 y que regalaremos con el patrocinio de Microsoft Ibérica en el número de octubre. Siverlight 2.0, que ya está en Beta 2 y con licencia Go Live, será –a mi entender– una auténtica revolución para los programadores de la plataforma .NET, en tanto que tendremos la posibilidad de programar con interfaces que hasta ahora eran impensables. Nosotros mismos ya estamos rediseñando nuestra página Web usando Silverlight 2.0. Espero que puedan ver el resultado entre septiembre y octubre de este año. Este mes entrevistamos a Dan Fernandez, Lead Product Manager para herramientas no profesionales en Microsoft y antiguo Product Manager de C#. Empezamos a hablar con él de las versiones Express y acabamos hablando de XNA, pasando por Silverlight y PopFly. El artículo de portada “Integrándonos continuamente” de Luis Fraile, a quien doy la bienvenida en su primera intervención, nos muestra como crear un entorno base de integración continua con Visual Studio 2008 Team System no es nada complicado. Por último, aunque no tenemos aún en WPF una organización jerárquica en el mundo 3D similar a la ya existente en 2D y mientras esperamos a que el equipo de desarrollo de WPF complete la jerarquía para futuras versiones, publicamos el artículo “Paneles para el mundo 3D” del Grupo Weboo de la Universidad de La Habana, que muestra cómo programar paneles tridimensionales y dotar a las aplicaciones de un aspecto similar a los paneles de Windows Vista. Y nada más. Como siempre, ¡dentro hay mucho más! Espero que nuestro trabajo de este mes sea de su agrado. Paco Marín ISSN 1698-5451 << dotNetManía Depósito Legal M-3.075-2004 3 sumario 50 Factorías de software. Justificación y ventajas 10-11 El momento de evolución tecnológica y económica en que nos encontramos está fomentando la creación de un nuevo modo de enfrentarse al problema de desarrollar software. Se trata de la organización de los equipos de desarrollo en factorías que, típicamente, están deslocalizadas respecto a los lugares en los que se generan las necesidades tecnológicas de los clientes.. Entrevista a Dan Fernandez 12-15 Otra de las entrevistas que pudimos “arañar” al programa oficial en el pasado Tech-Ed 2007 de Barcelona fue con Dan Fernandez, del Developer and Platform Evangelism Team en Microsoft (Redmond), quien nos atendió amablemente durante más de media hora en una de las salas eventualmente vacías, para charlar de “productos y proyectos” de desarrollo, y también de “planes vs. realidades”. El Marco de trabajo de entidades de ADO.NET v3.5 (VII) 18-21 Continuando con nuestra serie dedicada a presentar las posibilidades que ofrecerá el Marco de entidades de ADO.NET 3.5 para el modelado conceptual, en esta entrega mostraremos otros mecanismos disponibles para la implementación de vistas, presentando la vía para mapear las vistas definidas en el almacén relacional, así como las que tenemos a nuestra disposición para definir y operar con vistas personalizadas expresadas en Entity SQL. Paneles para el mundo 3D 22-27 Este artículo debe resultar un útil divertimento para la ya creciente familia de seguidores de WPF. Aquí se verá cómo programar paneles tridimensionales para facilitar la distribución de diferentes cuerpos en un Viewport3D. A la vez, el lector encontrará detalles de algunos elementos de la API 3D de WPF que le deberán resultar de utilidad. Integrándonos continuamente 28-35 Una de las prácticas más recomendadas a la hora de realizar proyectos y empezar a asegurar la calidad pronto es la de integrar todo el código lo más frecuentemente posible. Esto es especialmente importante a la hora del desarrollo iterativo, mediante el cual gestionaremos los cambios de requisitos de una forma más efectiva, entregando nuevas funcionalidades del software en cortos periodos de tiempo. Frameworks para Javascript 36-38 Las técnicas de desarrollo en Javascript, así como los usos que se le dan a esta tecnología, han cambiado notablemente en los últimos años. Hoy en día, nos es difícil pensar que una aplicación Web moderna pueda prescindir de esta tecnología para finalidades tan diversas como la comunicación asíncrona entre cliente y servidor, la aplicación de efectos visuales a nuestro código HTML o mantener nuestro propio sistema de caché en el lado del cliente. Componentes de uso general 40-44 Otro mes, y otro componente. Veamos cómo nuestros otros componentes pueden relacionarse con el sistema operativo, la seguridad, los usuarios… el Directorio activo. Extender o no extender... Los métodos extensores en Visual Basic 2008 45-49 La versión de Visual Basic que se incluye con .NET Framework 3.5 o Visual Studio 2008 permite que creemos métodos que extiendan la funcionalidad de clases existentes sin necesidad de tener acceso al código fuente de éstas. En este artículo veremos cómo crear este tipo de métodos y qué consideraciones debemos tener en cuenta para usarlos de la forma más adecuada. dnm.todotnet.qa 50-52 Plantillas ASP.NET e inferencia de tipos en C# Abordamos este mes un examen en profundidad de las propiedades de las plantillas de ASP.NET, y concluiremos explicando los pros y contras del uso de la nueva palabra reservada var en C#. dnm.laboratorio.net Aspose.Total for .NET 54-56 Este mes presentamos Aspose.Total for .NET, una potente suite de componentes reutilizables creados y comercializados por la empresa australiana Aspose, que pueden ser adquiridos conjuntamente o por separado para ser incorporados a todo tipo de aplicaciones .NET. dnm.biblioteca.net 57 Programming Microsoft LINQ Professional C# 2008 dnm.desvan 58 <<dotNetManía noticias noticias noticias noticias noticias 6 Visual Studio 2008 y .NET Framework 3.5 Service Pack 1 Durante los meses de verano, se pondrá a disposición del público la versión final del Service Pack 1 de Visual Studio 2008 y .NET Framework 3.5, de los que se liberaron recientemente versiones beta. Visual Studio 2008 y .NET Framework 3.5 Service Pack 1 dan continuidad a la inversión de Microsoft en herramientas de desarrollo líderes del mercado. El Service Pack 1 resuelve problemas encontrados tanto mediante pruebas internas como gracias a información recibida de clientes y partners. En general, el Service Pack 1 ofrece a sus usuarios tanto nuevas características como mejoras en la estabilidad y el rendimiento de Visual Studio 2008 y .NET Framework 3.5. Descripción general Con el Service Pack 1, Visual Studio 2008 introduce una gran cantidad de nuevas características para el desarrollo de aplicaciones para Windows, Office y la Web. Los desarrolladores que creen aplicaciones basadas en .NET disfrutarán de un rendimiento superior del diseñador de WPF, nuevos componentes para Visual Basic y Visual C++, así como un ribbon de Office 2007 para las MFC. Los desarrolladores de aplicaciones Web encontrarán múltiples mejoras en el soporte para la programación de scripts del lado del cliente, incluyendo el IntelliSense para Javascript. Adicionalmente, el soporte total para SQL Server 2008, la incorporación de ADO.NET Entity Framework y las mejoras de rendimiento del entorno hacen que el Service Pack 1 sea un producto sumamente atractivo. Por su parte, .NET Framework 3.5 Service Pack 1 ofrece más controles, una configuración más dirigida y mejoras en el rendimiento durante el arranque, así como potentes características gráficas para el desa- pleto de Javascript, herramientas mejoradas para AJAX y el acceso a datos, y mejoras en el despliegue de sitios Web. rrollo de aplicaciones cliente y nuevas posibilidades de acceso a datos, soporte mejorado para AJAX y otras mejoras para el desarrollo Web. Adicionalmente, introduce ADO.NET Entity Framework y ADO.NET Data Services, que permitirán simplificar aún más el código de acceso a datos en las aplicaciones ofreciendo un modelo conceptual extensible para representar datos provenientes de diversas fuentes y permitiendo que este modelo refleje de un modo más cercano los requisitos de negocio. Visual Studio 2008 Service Pack 1 incluye: • Diseñadores mejorados para el desarrollo de aplicaciones WPF. • Soporte completo para SQL Server 2008. • La introducción del Diseñador de entidades de ADO.NET. • Componentes y herramientas para Visual Basic y Visual C++ (incluyendo un ribbon de Office 2007 para MFC). • Mejoras en Team Foundation Server para responder al feedback de los clientes acerca de la usabilidad y rendimiento del control de versiones, y ofrecer una mejor integración del e-mail con el seguimiento de ítems de proyectos y soporte completo para la utilización de SQL Server 2008. • Mejoras para el desarrollo Web, incluyendo un soporte más com- .NET Framework 3.5 Service Pack 1 incluye: • Mejoras de rendimiento de entre un 20 y un 45% en las aplicaciones WPF –sin necesidad de hacer cambio alguno al código–. • Mejoras en WCF que ofrecen más control al desarrollador sobre el acceso a datos y servicios. • Experiencia de instalación mejorada para aplicaciones cliente. • Mejoras en la plataforma de acceso a datos, como ADO.NET Entity Framework, ADO.NET Data Services y soporte para las nuevas características de SQL Server 2008. Detalles adicionales Adicionalmente, el Service Pack 1 de .NET Framework y Visual Studio 2008 incluye otras varias nuevas características: Cambios en WPF y el diseñador visual • Mejoras en el rendimiento del “arranque en frío” de entre un 20 y un 45%, dependiendo del tamaño de la aplicación, sin modificación alguna al código. • Características adicionales de WPF para un mejor rendimiento del texto (especialmente cuando se utiliza en elementos Visual y DrawingBrush), los gráficos (efectos como DropShadow y Blur, antes implementados por software, ahora se << dnm.directo.noticias Cambios en WCF y WF • Nuevo Asistente de alojamiento para los proyectos de servicio WCF. • Mejoras en el Cliente de pruebas, tales como el soporte para contratos de mensajes y tipos anulables. • Expansión del alcance del serializador de contratos de datos, relajando la necesidad de aplicar los atributos DataContract y DataMember en los tipos y soportando un mecanismo interoperable para tratar las referencias a objetos. • Experiencia mejorada de depuración en entornos de confianza parcial, con soporte para el Registro de sucesos. • Soporte para entidades de ADO.NET Entity Framework en contratos WCF. • Múltiples mejoras para crear servicios REST, como el soporte para la publicación y consumo de ServiceDocument o un mayor control y usabilidad de UriTemplate. • Mejoras significativas en el trabajo con proyectos grandes basados en WF dentro de Visual Studio. • Mejora considerable en la escalabilidad de los servicios WCF alojados en el modo integrado en IIS7. .NET Framework 3.5 Optimized Client Runtime • .NET Framework 3.5 SP1 ofrece una versión de instalación de .NET Fra- mework optimizada para el desarrollo de aplicaciones cliente. El tamaño final de este runtime optimizado es menor de 20 Mb. Nuevos marcos de ADO.NET .NET Framework 3.5 SP1 incluye dos nuevos marcos de trabajo, ADO.NET Entity Framework y ADO.NET Data Services, para ofrecer a los desarrolladores una mayor flexibilidad y más opciones para el desarrollo de aplicaciones que acceden y utilizan datos. ADO.NET Entity Framework • El Marco de entidades de ADO.NET (tecnología sobre la que vienen escribiendo desde hace varios meses nuestros columnistas Unai Zorrilla y Octavio Hernández) permitirá elevar el nivel de abstracción en el manejo de datos, y haciendo posible que la estructura de la base de datos evolucione sin provocar un impacto significativo sobre el código de la aplicación. • En vez de programar contra filas y columnas, el Marco de entidades permite la definición de un modelo de datos de entidades sobre el almacén relacional, y entonces programar en términos de ese modelo. Los desarrolladores trabajarán con representaciones de los datos que tienen sentido para la aplicación, y que se expresan en un vocabulario más rico que incluye conceptos como la herencia, tipos complejos y relaciones explícitas. • Un nuevo “sabor” de LINQ, LINQ to Entities, permitirá definir consultas fáciles de mantener que recuperan objetos o entidades de negocio fuertemente tipados. ADO.NET Data Services • Los Servicios de datos de ADO.NET ofrecen una infraestructura de primera clase para desarrollar la siguiente ola de aplicaciones de Internet dinámicas, permitiendo exponer los datos como servicios REST que utilizan una sintaxis de URI uniforme y los verbos estándar de HTTP y que pueden ser consumidos por todo tipo de aplicaciones clientes (por ejemplo ASP.NET, AJAX y Silverlight). • Los Servicios de datos ofrecen un marco de trabajo para crear servicios de datos sobre almacenes relacionales como SQL Server, MySQL, DB2 u Oracle, utilizando el soporte del Marco de entidades, o para fuentes de datos no relacionales utilizando el modelo de proveedores suministrado. Mejoras en Team Foundation Server Varias mejoras y características adicionales han sido añadidas a Visual Studio Team System 2008 Team Foundation Server, incluyendo: Control de versiones • Mejoras en la experiencia de usuario a través de nuevos diálogos. • Mejoras en el Explorador de control de código fuente. • Soporte para ficheros no pertenecientes a una solución. Seguimiento de Work Items • Integración con Office 2007 mediante el ribbon estándar. • Integración del correo electrónico en el ciclo de desarrollo. Herramienta de migración de Visual SourceSafe • Numerosas mejoras en el rendimiento y fiabilidad de la herramienta. Rendimiento y escalabilidad • Múltiples mejoras en el rendimiento de diferentes tareas. • Un mismo servidor puede soportar muchos más proyectos; además, mejora sensiblemente la experiencia de usuario de un cliente que se conecta a un servidor con gran cantidad de proyectos. Características adicionales • Soporte para la utilización de SQL Server 2008. • Mejoras en Team System Web Access, que mejoran la experiencia de usuario de los clientes que no utilizan Team Explorer. • Soporte para la creación de proyectos mediante scripts. <<dotNetManía realizan mediante aceleración de hardware) y los multimedios. • WriteableBitmap muy mejorado, que hace posible las actualizaciones de mapas de bits en tiempo real desde una superficie de software. • Mejoras en la escalabilidad de los datos, como el reciclado de contenedores y la virtualización de TreeView, para ofrecer un mejor soporte para la edición de datos. • Múltiples novedades en el diseñador de WPF, como el soporte para los eventos en la ventana de propiedades, soporte del Cuadro de herramientas en el modo de código fuente, entre otras. 7 << dnm.directo.noticias Alhambra-Eidos llega a un acuerdo con dotNetManía para la difusión conjunta de su oferta formativa Alhambra-Eidos y dotNetManía ofrecerán conjuntamente cursos y libros especializados en la plataforma .NET y otras tecnologías Microsoft como Windows Server, SQL Server, SharePoint Server, BizTalk Server, Exchange Server, etc. La compañía Alhambra Eidos y la revista dotNetManía han alcanzado un acuerdo estratégico por el cual dicho medio, el más prestigioso entre la comunidad de desarrolladores de software en .NET en el mundo de habla hispana, se alía con la empresa de servicios, líder en formación para desarrolladores especializados en productos Microsoft y centro de formación autorizado por Microsoft (CPLS). Como consecuencia de este acuerdo, la revista difundirá la oferta formativa de Alhambra-Eidos y, a su vez, personal de dotNetManía asesorará y colaborará con el área de Formación de Alhambra-Eidos, optimizando y elaborando conjuntamente cursos y seminarios especializados en tecnologías .NET y otras tecnologías de Microsoft como Windows Server, SQL Server, SharePoint, BizTalk, Exchange Server, etc. Otro aspecto de este acuerdo es la colaboración de Netalia –la editorial de dotNetManía y de los Cuadernos Técnicos de dotNetManía– en la edición y distribución de los libros editados por Alhambra-Eidos. Además, Alhambra-Eidos ofrecerá a los lectores de dotNetManía ventajas exclusivas como descuentos permanentes en cursos y libros. Como comienzo de esta colaboración, Marino Posadas, redactor jefe de dotNetManía, impartirá el laboratorio “Silverlight 2.0” de diez horas de duración, durante los días 16 y 17 de julio. Los lectores de dotNetManía tendrán un 10% de descuento. Para más información sobre este laboratorio: http://www.alhambra-eidos.es/ES/Formacion. Liberada Beta 2 de Silverlight 2 <<dotNetManía En el marco del pasado Tech-Ed USA celebrado en Orlando, Microsoft liberó la Beta 2 de Silverlight 2, así como actualizaciones de las herramientas de Visual Studio 2008 y Expression Blend 2.5 que le dan soporte. 8 La Beta 2 añade una gran cantidad de nuevas características, no obstante a lo cual, es una descarga de solo 4.6 MB que tarda menos de 10 segundos en instalarse. No requiere la presencia de .NET Framework ni ningún otro software para funcionar, y todas sus características funcionan a través de diferentes navegadores en máquinas Windows y Mac. Estas características también estarán soportadas en Linux gracias a Moonlight 2. Silverlight 2 Beta 2 ofrece una licencia Go Live que permite utilizar y desplegar Silverlight 2 en aplicaciones comerciales, aunque se espera que se produzcan algunos cambios en las API entre la Beta 2 y el producto final, por lo que muy probablemente habrá que “retocar” esas aplicaciones cuando la versión final esté disponible. Las nuevas características incorporadas a la Beta 2 pueden agruparse en las siguientes categorías: • Mejoras en interfaz de usuario y controles. • Mejoras en el soporte multimedios. • Mejoras en el soporte de red. • Mejoras en el manejo de datos. Para más información y descargas, visite http://www.silverlight.net. Windows Server 2008 Hyper-V disponible Después del lanzamiento de Windows Server 2008 sin la tan esperada característica de virtualización, por fin Windows Server 2008 Hyper-V está disponible para su descarga desde http://www.microsoft.com/Hyper-V o vía Windows Update desde el 8 de julio. Hyper-V es la tecnología de virtualización basada en servidor de Microsoft, que viene como una característica totalmente integrada en Windows Server 2008, disponible para ciertas ediciones del sistema operativo. Hasta la fecha se han distribuido algo menos de 1,5 millones de copias de la beta de Hyper-V, lo que demuestra el gran interés suscitado por la tecnología de virtualización, que competirá con los productos de VMWare. Adicionalmente, System Center Virtual Machine Manager es la solución para la centralización de la gestión de la infraestructura de virtualización. Más información en: http://www.microsoft.com/systemcenter/virtualmachinemanager. opinión Antonio Quirós Factorías de software Justificación y ventajas El momento de evolución tecnológica y económica en que nos encontramos está fomentando la creación de un nuevo modo de enfrentarse al problema de desarrollar software. Se trata de la organización de los equipos de desarrollo en factorías que, típicamente, están deslocalizadas respecto a los lugares en los que se generan las necesidades tecnológicas de los clientes. Antonio Quirós es colaborador habitual de dotNetManía. Cofundador de las revistas clippeRManía, FOXManía y Algoritmo. Actualmente es director de operaciones en Alhambra-Eidos. << A la base de esta nueva situación se encuentran las siguientes consideraciones: • La mayor demanda de soluciones de software se ubica en los países con un alto desarrollo económico y un tejido empresarial fuerte. El personal especializado en estos países es escaso y de alto coste, por lo que frecuentemente no alcanza a satisfacerse la demanda con los recursos internos que se poseen. • Dentro de los propios países desarrollados existen áreas de muy fuerte desarrollo empresarial y otras que se caracterizan por un menor nivel del mismo. Sin embargo, en Europa al menos, la inversión pública lleva hacia todas las áreas prácticamente por igual el proceso de difusión de la enseñanza técnica especializada, existiendo, por tanto, exceso de capacidad productiva en ciertas áreas demográficas y falta de la misma en otras. • El desarrollo de software es un proceso altamente industrializable y, por tanto, sometido a reglas similares a las que se están dando en otras partes de la industria y la tecnología. Nos referimos al fenómeno de la deslocalización de la producción. Todo esto nos está llevando a una situación en la cual la parte de la producción que se encuentra cercana al cliente (planificación, diseño funcional, implantación y parte del mantenimiento) se realizan en ubicaciones cercanas a donde se encuentran los usuarios, mientras que la construcción o incluso el diseño técnico tienden a realizarse en ubicaciones remotas donde es más fácil cubrir la demanda de personal técnico especializado. Extremando esta argumentación, estaríamos en el proceso del off-shoring, es decir, la construcción de software en países con economías emergentes (típicamente India, Rusia o Latinoamérica). Sin embargo, incluso dentro de nuestro país está << dnm.opinión En esto se sigue el mismo esquema (o al menos uno similar) al que en la producción industrial ordinaria se establece entre la ingeniería y la producción o línea de montaje. Lo importante de este sistema es que permite deslindar y formalizar, por tanto, mejor, procesos que no siempre han estado bien separados. Es decir, que de la propia necesidad del mercado en recorrer este camino se sigue la necesidad para los informáticos de encapsular mejor cada uno de sus procedimientos a fin de que puedan ser realizados de forma separada por equipos diferentes y que pueden estar alejados por el espacio miles de kilómetros unos de otros y por el tiempo según la diferencia horaria que corresponda. La industria informática lleva años trabajando fuertemente en el planteamiento de modelos que mejoren la encapsulación de sus procedimientos y en metodologías que permitan protocolizar los distintos pasos que se dan De la propia necesidad del mercado en recorrer este camino se sigue la necesidad para los informáticos de encapsular mejor cada uno de sus procedimientos a fin de que puedan ser realizados de forma separada por equipos diferentes en todo el ciclo de vida de producción de software. Esto nos lleva a un escenario donde podemos decir que el estadio de desarrollo en que nos encontramos respecto a este proceso de (valga la redundancia) mejora de procesos es bastante alto. Prueba de esto son estándares comúnmente aceptados como UML (Lenguaje Unificado de Modelado) o MDA (Arquitectura Guiada por Modelos), ambos en el área de diseño, o metodologías como CMMI, ITIL, COBIT o las basadas en ISO 9001 respecto a la protocolización de la construcción de software, la prestación de servicios informáticos o el gobierno de las actividades TIC de las empresas. En nuestro país existe un fuerte desequilibrio interregional respecto al volumen de negocio que el mundo TIC mueve en cada una de las comunidades, de forma que éste se concentra mayoritariamente en Madrid y Cataluña donde existe más demanda de titulados de los que las facultades de informática pueden proveer, estando por otra lado el resto de las Comunidades donde lo normal es que la universidad genere más titulados de los que el mercado puede absorber. Este desequilibrio fomenta un fenómeno de inmigración tecnológica interna, donde los titulados de ciertas universidades han de verse forzados a emigrar a Madrid o Barcelona para poder abastecer la demanda de titulados de dichos mercados, así como para garantizar los niveles salariales adecuados al desempeño de dichos puestos. Este fenóme- no, desde luego, no contribuye al equilibro económico y demográfico del país sino que es una semilla continua que abona el crecimiento de los grandes polos de atracción económica española en el área TIC (Madrid y Barcelona), consiguiendo cada vez más que el talento que otras universidades regionales liberan no se quede “en casa”, fijando la población al territorio y equilibrando la demografía y la renta de las distintas áreas de población. Sin embargo, el mundo del software abre expectativas más que interesantes para atajar este problema. Desde hace algunos años en España se está dando la tendencia, entre las empresas más grandes del sector TIC, a abrir Factorías de Software para deslocalizar su producción y aprovecharse de las posibilidades de captar talento directamente en sus fuentes (las universidades de las comunidades donde se instalan). Este fenómeno va a contribuir muy positivamente al equilibrio económico y demográfico a nivel interregional, a la vez que auspicia que las empresas tengan que mejorar sus procesos para garantizar que esta producción deslocalizada se realice con los niveles de eficiencia y calidad que nuestro mundo demanda. Hay que ser conscientes también de que el desarrollo de esta mecánica nos ayudará como país a mejorar nuestro posicionamiento en cuanto a productividad y generación de valor añadido, epígrafes en los que nos encontramos no demasiado bien posicionados respecto a muchos de nuestros socios europeos. <<dotNetManía creciendo fuertemente la tendencia de que compañías que tienen que atender una importante demanda nacional e incluso internacional, y que se encuentran ubicadas en Madrid y/o Barcelona, están creando factorías de software en provincias donde no existe demanda empresarial para dar salida a los titulados de las facultades de Informática y donde les resulta mucho más fácil acceder a dicho mercado de personal técnico. De este modo, los equipos de desarrollo de software tienden a desdoblarse en dos áreas claramente diferenciadas: a) Aquella que atiende las necesidades de relación inmediata con el cliente y que por tanto se encarga de actividades normalizadas de diseño, tales como toma de requisitos, casos de uso, validación de actas con el cliente, planificación, etc., así como las de despliegue, implantación, formación, etc. b) La que se encarga de realizar los diseños técnicos, así como la construcción del software y las pruebas sobre el mismo. 11 entrevista Marino Posadas entrevista a Marino Posadas es consultor independiente y redactor jefe de dotNetManía. Puedes leer su blog en http://www. elavefenix.net. Dan Fernandez Otra de las entrevistas que pudimos “arañar” al programa oficial en el pasado Tech-Ed 2007 de Barcelona fue con Dan Fernandez, del Developer and Platform Evangelism Team en Microsoft (Redmond), quien nos atendió amablemente durante más de media hora en una de las salas eventualmente vacías, para charlar de “productos y proyectos” de desarrollo, y también de “planes vs. realidades”. << dnm.directo.entrevista ¿Cómo defines el propósito de Microsoft –lo que se tiene en mente– a la hora de crear este tipo de herramientas que, por definición, son gratuitas? Nuestro propósito es crear un conjunto de herramientas que faciliten la “democratización del desarrollo de software”. Con Visual Studio Express queríamos conseguir algo sencillo y fácil de utilizar, que estuviera disponible para principiantes y entusiastas del desarrollo no profesional. Y lo que hacemos ahora es la continuación lógica de ese esfuerzo inicial. Ahora disponemos de muchos más recursos como el sitio Web “Beginner Developer Learning Center” ( http://msdn.microsoft.com/ en-us/beginner/default.aspx) y otros recursos que suponen inversiones importantes en ese sentido, como los libros de programación para novatos, de forma que cualquiera que no Nuestro propósito es crear un conjunto de herramientas que faciliten la “democratización del desarrollo de software” Y antes de esto estabas relacionado directamente con el equipo de desarrollo de C#, si no recuerdo mal. Sí, antes de este trabajo fui Visual C# Product Manager, y tuve la oportunidad de trabajar con muchos de los creadores del producto como Anders Hejlsberg o Scott Nonnenberg, y otros. tenga experiencia pueda también acercarse al mundo del desarrollo y encontrar fácilmente un punto de partida. ¿Tiene esto que ver con el movimiento de introducción o presentación del entorno .NET en el mundo universitario, donde habitualmente se ignoran las herramientas de desarrollo de Microsoft? Sí. De hecho, podemos decir que los principales usuarios de estos productos son estudiantes, que lo obtienen de diversas formas, y al comenzar a trabajar se ven necesitados de los recursos adicionales que te comentaba hace un momento. Son elementos importantes para que puedan empezar enseguida a ver algunos resultados. Cambiando un poco “el tercio”, algunas empresas están empezando a requerir la figura del diseñador de aplicaciones, además del desarrollador clásico. ¿Apreciáis vosotros igualmente esa tendencia en vuestros análisis de mercado? Sí, eso es notable también en EE.UU. Ciertamente, muchas veces depende del volumen de la empresa de que se trate: cuanto más grande, más roles especializados te encuentras, porque eso permite no “repetir el conocimiento” de forma innecesaria y avanzar más en el concepto de “factoría de software”. Ése es el lugar exacto de la suite Expression, el de servir de enlace entre estos roles, ofreciéndoles un lugar común de conexión de sus trabajos. ¿Cuál piensas que es el período adecuado entre dos versiones de Visual Studio (ya sean profesionales o Express)? ¿Dos años, como afirman algunos analistas? Entiendo muy bien la pregunta y creo que también el porqué. Pero debo decir que para nosotros las fechas no son una prioridad. Nosotros establecemos los contenidos de una versión basándonos principalmente en el feedback de nuestros clientes, de foros de desarrollo, de nuestros partners, etc. Y cuando se decide cuáles van a ser los contenidos de la siguiente versión, en lo único que se piensa es en que, cuando salga al mercado, esté lo suficientemente probada, estable y productiva como para suponer un aliciente de actualización. <<dotNetManía Ya es tradicional que el entrevistado para dotNetManía se presente a sí mismo. De esa forma matamos dos pájaros de un tiro, porque más de una vez mi interlocutor ya no ocupaba la posición que aparecía en su sitio Web o en su blog… Así que, aunque me dijiste ayer que trabajabas con un antiguo entrevistado por mi revista (Arturo Toledo), prefiero que sigas con la tradición… Por supuesto, mi nombre es Dan Fernandez, y soy Lead Product Manager para herramientas no profesionales en Microsoft. Eso significa especialmente las herramientas que genéricamente conocemos como herramientas “Express”. En realidad, como sabes, es una suite completa de herramientas de desarrollo, cada una especializada en una tecnología (Web Developer o SQL Server) o un lenguaje (C#, VB.NET, C++). 13 << dnm.directo.entrevista Millones de programadores en VB.NET y C# podrán reutilizar su código para colocarlo en aplicaciones Silverlight, y eso sí que es totalmente novedoso en el mundo del desarrollo Web <<dotNetManía ¿Se espera un crecimiento paralelo de las capacidades de la suite Expression con respecto a Visual Studio? ¿O van a seguir una progresión independiente? Más que funcionar en paralelo, lo que pensamos es que deben tener un mismo objetivo común, y que aquellas cosas necesarias para el diseño de una aplicación (independientemente de la versión de Visual Studio de que se trate), siempre estén soportadas en la suite Expression. Y especialmente, que ambos productos siempre funcionen muy bien juntos. 14 El gran “boom” que se espera en el mundo del desarrollo Web (o al menos así nos lo están presentando los principales fabricantes) tiene que ver con las aplicaciones RIA (Rich Internet Applications). ¿Cuál es tu opinión acerca de la importancia de Silverlight en este contexto? Para mí, la palabra para definir Silverlight es “emocionante”. Y lo digo especialmente porque he estado implicado directamente en el desarrollo de PopFly, y he podido ver la demanda y la aceptación que esa herramienta de construcción de sitios sin necesidad de código fuente ha tenido desde el comienzo y sigue teniendo. Y eso ya llevaba algunos elementos que no eran sino la promesa de lo que empieza a ser Silverlight. Una increíble interfaz de usuario (por fin), pero desde el punto de vista de desarrollador que soy, hay dos cosas que me gustan especialmente: una es la posibilidad de que las aplicaciones se construyan (al menos en buena parte) en tiempo de ejecución, como algo dinámico, dependiendo de otros factores que tienen que ver con el uso que le da a la aplicación el navegante Web, y aprovechando las capacidades del lenguaje XAML. La otra cosa que resulta especialmente interesante es la posibilidad de tener VB.NET o C# en el cliente, sin que ello dependa de que se esté utilizando un navegador o una plataforma concreta, sino que podamos usarlo para cualquier navegador, o en Linux o Mac. Creo que esa riqueza y esa capacidad de cobertura es lo más importante. Esa posibilidad de utilizar C#, por ejemplo, puede producir ganancias, como la que demostró Scott Guthrie recientemente con un juego de ajedrez escrito en Javascript tradicional y su equivalente en C# casi ¡1000 veces! más rápido en la versión escrita en C#. Además, existen millones de programadores en VB.NET y C# que podrán reutilizar su código para colocarlo en aplicaciones Silverlight, y eso sí que es totalmente novedoso en el mundo del desarrollo Web. Ya que lo mencionas, dinos algo más acerca de PopFly… en los foros hay mucha gente comentando sus experiencias… PopFly es una aproximación distinta al mundo del desarrollo Web. Asumimos que todo el mundo tiene que tener el derecho a hacer su sitio Web sin necesidad de hacer una carrera, y suministramos las herramientas prefabricadas para que esto sea así. Se trata, fundamentalmente, de permitir que el creador utilice estos “elementos prefabricados” en una labor similar a la de un puzle, hasta conseguir en cada caso el efecto deseado. Lo que hemos hecho es analizar los distintos tipos de blogs que mantiene la gente, qué les gusta utilizar, cómo les gusta compartir su información, etc. Y a partir de todo eso se ha construido PopFly. Ya que estamos hablando de software que hace fácil la vida al desarrollador, es inevitable citar una herramienta por la que existe mucha expectación en el mundo de los aficionados a los videojuegos (que es enorme). Me refiero a XNA. ¿Cómo ves este producto y que expectativas de crecimiento y aceptación popular le concedes? XNA es sin duda una de mis herramientas favoritas. La meta es permitir que cualquiera se pueda adentrar en el mundo del desarrollo de juegos (y también de Marino Posadas y Dan Fernandez en un momento de la entrevista aplicaciones de multimedia y otros tipos) de una forma muy sencilla, y crear aplicaciones para la XBOX o para te siente la necesidad de verse expresado en la Web. Windows y distribuirlas con facilidad. El único Este movimiento va a continuar porque la gente lo requisito es tener conocimientos de programación demandará cada vez más y más. Y se producirá una en lenguaje C#, si bien, dependiendo del juego, segunda “explosión Web” asociada a esta demopueden requerirse conocimientos gráficos, aunque cratización. Explosión que ya está implícita de forXNA Studio hace que esa labor sea muchísimo más ma clara en lo que llamamos Web 2.0. Y esto no es fácil. solo para las típicas aplicaciones como blogs o sitios, De hecho, ahora puede incluirse como “add-in” sino también para otros tipos de aplicaciones Web, de Visual C# Express. Incluso te diré más: existen como programas de mensajería instantánea, redes universidades norteamericanas (y alguna extranjeP2P, etc. ra) que están preparando lo que se denomina El reto es construir software que permita que “Currículo XNA”, para capacitar en la construcese escenario sea del tipo “dos líneas de código” ción de este tipo de aplicaciones. Es otro concepsin perder (en la medida de lo posible) las posibito del aprendizaje que allí se denomina “Learning lidades de personalización que cualquier autor by having fun” (aprendizaje mediante el entreteninecesita. miento). Y está teniendo una repercusión que nosotros mismos no imaginábamos en principio. A la vista de tu apellido, hay una pregunta que tengo que hacerte para concluir esta entrevisSiempre tratamos de visualizar cuál será el ta: ¿es la primera vez que vienes a España? panorama del desarrollo dentro de unos pocos ¡Qué va! De hecho, tengo familia aquí. Un tío años, sobre todo para la toma de decisiones y un primo míos viven aquí, en Barcelona, y ya he empresariales que nos ayuden a no pasar por estado otras veces, especialmente en vacaciones de alto cosas importantes. ¿Cómo ves tú este panoAño Nuevo. Mis padres son originalmente colomrama? bianos, aunque mi abuelo era español. Pues creo que esta democratización del software va a continuar. La diferencia es que no todo el Pues nos alegramos. Muchas gracias en nommundo siente la necesidad de construir un puente, bre de todos los lectores por tu tiempo y tus pongamos por caso, pero, cada vez más, mucha geninteresantes propuestas. <<dotNetManía << dnm.directo.entrevista 15 eventos eventos Solid Quality SUMMIT Con enorme éxito de crítica y público, Solid Quality™ Iberoamérica (www.solidq.com/ib) organizó y llevó a buen fin en Madrid, España, el cuarto Solid Quality Summit, durante los días 23, 24 , 25, 26 y 27 de junio. Durante esos cinco días, los asistentes –entre los que se incluyeron representantes de empresas y organizaciones de reconocido renombre en España– tuvieron la oportunidad de asistir a más de 60 sesiones, distribuidas en los tres tracks ofrecidos en el evento (Inteligencia de Negocios, Motor Relacional y Tecnologías .NET). Este año, como novedad, los asistentes pudieron confeccionar de antemano sus propias agendas, lo que les permitió planificar mejor su tiempo y aprovecharlo al máximo. Asimismo, se puso a disposición de los participantes un portal exclusivo, repleto de contenidos como las presentaciones realizadas, vídeos y código de las demostraciones y libros electrónicos, entre otros. Alejandro Leguizamo, director de marketing, declaró: “Este cuarto año ha sido una experiencia muy positiva para nosotros. Hemos logrado nuestra consoli- dación como el punto de referencia en el mercado español alrededor de SQL Server y .NET. Hemos sido los primeros en la industria (aparte de Microsoft) en estar integrados desde fases muy tempranas en el proceso de desarrollo de SQL Server (tanto 2005 como 2008) con el grupo de producto en Redmond, y durante este evento hemos podido entregar ese conocimiento de primera mano a nuestros clientes, garantizando la mejor formación”. <<dotNetManía MAD.NUG reinicia sus actividades 16 El pasado jueves 26 de junio tuvo lugar, en las oficinas de Microsoft, el evento con el que MAD.NUG (el Grupo de usuarios .NET de Madrid) retomó sus actividades después de unos meses de pausa. Como complemento al evento, los asistentes pudimos disfrutar del emocionante segundo tiempo del partido de semifinales de la Eurocopa '08 entre España y Rusia, para lo que Microsoft gentilmente suministró la infraestructura y los aperitivos necesarios. El evento, bajo el título “Déjate engatusar por Visual Studio 2008”, tuvo como objetivo mostrar algunas de las posibilidades que pone esta nueva versión del entorno de desarrollo a disposición de los desarrolladores. Después de la introducción general a cargo de David Herráiz (cuya presentación de las novedades en ASP.NET 3.5 finalmente quedó para una próxima ocasión), David Carmona (Microsoft) nos mostró la nue- va versión de MSDN Vídeo, desarrollada desde cero con .NET 3.5 y VS 2008, haciendo énfasis en la arquitectura del sistema y en los momentos en los que se hace utilización de nuevas tecnologías como LINQ, WPF o WCF. Posteriormente entraron en acción Luis Fraile y Bruno Capuano para hablar sobre algunas de las nuevas posibilidades incluidas en VS Team System para el análisis y control de calidad del código. Y finamente, Jorge Serrano y Octavio Hernández hicieron un recorrido por las novedades de Visual Basic 9.0, incluyendo las relativas a LINQ. El próximo evento de MAD.NUG ya tiene fecha: será el jueves 24 de julio, y en él Roberto González, MVP de Biztalk, tendrá a su cargo la charla “Integración de WCF y WF en .NET 3.5”. Más información en http://info.madriddotnet.com. Octavio Hernández Unai Zorrilla Octavio Hernández plataforma.net El Marco de trabajo de entidades de ADO.NET v3.5 (VII) Continuando con nuestra serie dedicada a presentar las posibilidades que ofrecerá el Marco de entidades de ADO.NET 3.5 para el modelado conceptual [1], en esta entrega mostraremos otros mecanismos disponibles para la implementación de vistas, presentando la vía para mapear las vistas definidas en el almacén relacional, así como las que tenemos a nuestra disposición para definir y operar con vistas personalizadas expresadas en Entity SQL. Unai Zorrilla es Development Team Leader de Plain Concepts y tutor de campusMVP. MVP desde 2004, colabora activamente con Microsoft en eventos de arquitectura y desarrollo, así como en giras de productos. Autor del libro "Modelando procesos de negocio con Workflow Foundation". Octavio Hernández es Mentoring Team Leader de Plain Concepts, editor técnico de dotNetManía y tutor de campusMVP. Es MVP de C# desde 2004, MCSD y MCT. Autor del libro "C# 3.0 y LINQ". Como ya es habitual, basaremos los ejemplos de este artículo en la base de datos FUTBOL2006 del libro “C# 3.0 y LINQ” [2]. El código de ejemplo asociado a este artículo (que puede ser descargado desde www.dotnetmania.com) ha sido creado utilizando el Service Pack 1 de Visual Studio 2008, que incluye una versión cercana a la definitiva del Marco de Entidades. Mapeo de vistas de servidor Del mismo modo que el Marco de entidades ofrece una vía para mapear de manera declarativa los procedimientos almacenados y funciones definidas por el usuario que devuelven conjuntos de datos, como hemos descrito en el artículo anterior de la serie, ofrece asimismo una vía directa para “sacar a la superficie” de un modelo de entidades las vistas definidas directamente en el almacén de datos mediante el lenguaje del almacén (Transact-SQL, en el caso de SQL Server, PLSQL en el caso de Oracle, etc.). Por ejemplo, suponiendo que se ha definido sobre la base de datos FUTBOL2006 la vista RealMadrid que se presenta en el listado 1, ésta quedaría reflejada en el modelo del almacén generado por el asistente integrado en Visual Studio mediante el fragmento de docu- mento SSDL que se muestra en el listado 2. Observe cómo los atributos store:Type, store:Schema y store:Name y el elemento <DefiningQuery> reflejan en el modelo las propiedades básicas de la vista. A su vez, a nivel conceptual se modelaría la definición anterior mediante la creación de la entidad que se muestra en el fragmento de documento CSDL del listado 3. Y por último, la correspondencia entre las entidades lógica y física quedaría expresada mediante el mapeo que muestra el fragmento MSL del listado 4. El resultado final será que podremos acceder al conjunto de resultados que la vista produce utilizando la consulta LINQ que se muestra en el listado 5. CREATE VIEW [dbo].[RealMadrid] AS SELECT TOP (100) PERCENT dbo.Futbolista.Id, dbo.Futbolista.Nombre,dbo.Futbolista.Posicion, dbo.Pais.Nombre AS NombrePais FROM dbo.Futbolista INNER JOIN dbo.Pais ON dbo.Futbolista.CodigoPaisNacimiento = dbo.Pais.Codigo WHERE dbo.Futbolista.CodigoClub = ‘RMA’ ORDER BY dbo.Futbolista.Posicion, dbo.Futbolista.Nombre Listado 1.Vista de servidor definida en Transact-SQL. << dnm.plataforma.net Listado 2. Fragmento de documento SSDL. <edmx:ConceptualModels> <Schema Namespace=”FUTBOL2006” Alias=”Self” xmlns=”http://schemas.microsoft.com/ado/2006/04/edm”> <EntityContainer Name=”FUTBOL2006Context”> <!— ... —> <EntitySet Name=”RealMadrid” EntityType=”FUTBOL2006.RealMadrid” /> <!— ... —> </EntityContainer> <!— ... —> <EntityType Name=”RealMadrid”> <Key> <PropertyRef Name=”Id” /> <PropertyRef Name=”Nombre” /> <PropertyRef Name=”Posicion” /> <PropertyRef Name=”NombrePais” /> </Key> <Property Name=”Id” Type=”Int32” Nullable=”false” /> <Property Name=”Nombre” Type=”String” Nullable=”false” MaxLength=”75” Unicode=”false” FixedLength=”false” /> <Property Name=”Posicion” Type=”String” Nullable=”false” MaxLength=”1” Unicode=”false” FixedLength=”true” /> <Property Name=”NombrePais” Type=”String” Nullable=”false” MaxLength=”50” Unicode=”false” FixedLength=”false” /> </EntityType> <!— ... —> </Schema> </edmx:ConceptualModels> Listado 3. Fragmento de documento CSDL. El Marco de entidades ofrece una vía directa para “sacar a la superficie” de un modelo de entidades las vistas definidas directamente en el almacén de datos Vistas de consulta Además de permitir “sacar a la superficie” las vistas definidas directamente en la base de datos, el Marco de entidades ofrece una potente infraestructura basada en vistas de cliente, una de cuyas ventajas principales es la de hacer posible encapsular la complejidad asociada a la obtención de los datos, de forma que ésta no permee el código de las aplicaciones. Estas vistas funcionan totalmente en el lado del cliente, de modo que los desarrolladores pueden crear vistas adecuadas a las necesidades concretas de cada aplicación sin afectar a la base de datos u otras aplicaciones. El lenguaje en el que se expresan estas vistas es Entity SQL, un lenguaje muy similar en estructura al SQL tradicional, pero preparado para manejar los nuevos conceptos que introduce el Marco de entidades como la herencia, las relaciones, los tipos complejos, etc. Del análisis de las sentencias Entity SQL y su traducción al dialecto de SQL del almacén subyacente se encarga el Proveedor de Entidades (Entity Provider), un nuevo proveedor de ADO.NET que interactúa con el proveedor “nativo” correspondiente para ejecutar la sentencia traducida y recuperar los resultados (figura 1). <<dotNetManía <edmx:StorageModels> <Schema Namespace=”FUTBOL2006Model.Store” Alias=”Self” Provider=”System.Data.SqlClient” ProviderManifestToken=”2005” xmlns=”http://schemas.microsoft.com/ado/2006/04/edm/ssdl”> <EntityContainer Name=”dbo”> <!— ... —> <EntitySet Name=”RealMadrid” EntityType=”FUTBOL2006Model.Store.RealMadrid” store:Type=”Views” store:Schema=”dbo” store:Name=”RealMadrid”> <DefiningQuery>SELECT [RealMadrid].[Id] AS [Id], [RealMadrid].[Nombre] AS [Nombre], [RealMadrid].[Posicion] AS [Posicion], [RealMadrid].[NombrePais] AS [NombrePais] FROM [dbo].[RealMadrid] AS [RealMadrid]</DefiningQuery> </EntitySet> <!— ... —> </EntityContainer> <!— ... —> <EntityType Name=”RealMadrid”> <Key> <PropertyRef Name=”Id” /> <PropertyRef Name=”Nombre” /> <PropertyRef Name=”Posicion” /> <PropertyRef Name=”NombrePais” /> </Key> <Property Name=”Id” Type=”int” Nullable=”false” /> <Property Name=”Nombre” Type=”varchar” Nullable=”false” MaxLength=”75” /> <Property Name=”Posicion” Type=”char” Nullable=”false” MaxLength=”1” /> <Property Name=”NombrePais” Type=”varchar” Nullable=”false” MaxLength=”50” /> </EntityType> <!— ... —> </Schema> </edmx:StorageModels> 19 << dnm.plataforma.net <edmx:Mappings> <Mapping Space=”C-S” xmlns=”urn:schemas-microsoft-com:windows:storage:mapping:CS”> <EntityContainerMapping StorageEntityContainer=”dbo” CdmEntityContainer=”FUTBOL2006Context”> <!— ... —> <EntitySetMapping Name=”RealMadrid”> <EntityTypeMapping TypeName=”IsTypeOf(FUTBOL2006.RealMadrid)”> <MappingFragment StoreEntitySet=”RealMadrid”> <ScalarProperty Name=”Id” ColumnName=”Id” /> <ScalarProperty Name=”Nombre” ColumnName=”Nombre” /> <ScalarProperty Name=”Posicion” ColumnName=”Posicion” /> <ScalarProperty Name=”NombrePais” ColumnName=”NombrePais”/> </MappingFragment> </EntityTypeMapping> </EntitySetMapping> <!— ... —> </EntityContainerMapping> </Mapping> </edmx:Mappings> Listado 4. Fragmento de documento MSL. private void button1_Click(object sender, EventArgs e) { using (var ctx = new FUTBOL2006Context()) { var q = from f in ctx.RealMadrid where f.Posicion == “P” orderby f.Id select f.Nombre; foreach (var r in q) MessageBox.Show(r); } } <<dotNetManía Listado 5. Consulta LINQ que utiliza la vista de servidor mapeada. 20 La definición estática de vistas del lado cliente (conocidas como vistas de consulta) se realiza mediante el elemento <QueryView> del fichero de mapeo (MSL), que encapsula una sentencia Entity SQL definida sobre el modelo del almacén. Estas vistas luego se mapean igualmente en el CSDL como entidades de pleno derecho. El listado 6 muestra un fragmento del documento combinado EDMX en el que se define una vista de consulta que permite recuperar los porteros del Real Madrid. Por su parte, el listado 7 muestra cómo obtener esos datos utilizando una consulta LINQ, la vía más natural, que podríamos utilizar, por ejemplo, como fuente de enlace a datos. <?xml version=”1.0” encoding=”utf-8”?> <edmx:Edmx Version=”1.0” xmlns:edmx=”http://schemas.microsoft.com/ado/2007/06/edmx”> <edmx:Runtime> <!— SSDL content —> <edmx:StorageModels> <!— ... —> </edmx:StorageModels> <!— CSDL content —> <edmx:ConceptualModels> <Schema Namespace=”FUTBOL2006” Alias=”Self” xmlns=”http://schemas.microsoft.com/ado/2006/04/edm”> <EntityContainer Name=”FUTBOL2006Context”> <!— ... —> <EntitySet Name=”PorteroRealMadrid” EntityType=”FUTBOL2006.PorteroRealMadrid” /> <!— ... —> </EntityContainer> <!— ... —> <EntityType Name=”PorteroRealMadrid”> <Key> <PropertyRef Name=”Id” /> <PropertyRef Name=”Nombre” /> </Key> <Property Name=”Id” Type=”Int32” Nullable=”false” /> <Property Name=”Nombre” Type=”String” Nullable=”false” MaxLength=”75” Unicode=”false” FixedLength=”false” /> </EntityType> </Schema> </edmx:ConceptualModels> <!— C-S mapping content —> <edmx:Mappings> <Mapping Space=”C-S” xmlns=”urn:schemas-microsoft-com:windows:storage:mapping:CS”> <EntityContainerMapping StorageEntityContainer=”dbo” CdmEntityContainer=”FUTBOL2006Context”> <!— ... —> <EntitySetMapping Name=”PorteroRealMadrid”> <QueryView> SELECT VALUE FUTBOL2006.PorteroRealMadrid(F.Id, F.Nombre) FROM dbo.Futbolista AS F WHERE F.Posicion = ‘P’ AND F.CodigoClub = ‘RMA’ </QueryView> </EntitySetMapping> </EntityContainerMapping> </Mapping> </edmx:Mappings> </edmx:Runtime> <edmx:Designer xmlns=”http://schemas.microsoft.com/ado/2007/06/edmx”> <!— ... —> </edmx:Designer> </edmx:Edmx> Listado 6. Fragmentos relevantes en la definición de una vista de consulta. private void button2_Click(object sender, EventArgs e) { using (var ctx = new FUTBOL2006Context()) { var q = from f in ctx.PorteroRealMadrid select f; foreach (var r in q) MessageBox.Show(r.Nombre); dataGridView1.DataSource = q.ToList(); } } Listado 7. Consulta integrada contra la vista de consulta. << dnm.plataforma.net Aunque no lo mostraremos aquí para no repetirnos, es de destacar que a estas “entidades virtuales” (tanto las vistas de servidor mapeadas como las vistas de consulta) en principio también se les puede asociar en el modelo procedimientos almacenados para la inserción, modificación y borrado, de un modo similar a como lo hicimos en nuestro artículo anterior para las funciones. Consultas ad-hoc Figura 1. El Entity Provider traduce las sentencias Entity SQL al dialecto del almacén. private void button3_Click(object sender, EventArgs e) { using (var con = new EntityConnection(ConfigurationManager. ConnectionStrings[“FUTBOL2006Context”].ConnectionString)) { con.Open(); using (EntityCommand cmd = con.CreateCommand()) { cmd.CommandText = @”SELECT F.Id AS Id, F.Nombre AS Nombre, F.Posicion AS Posicion, F.Pais.Nombre AS NombrePais FROM Futbol2006Context.Futbolista AS F WHERE F.Club.Codigo = @Club AND F.Posicion = @Pos ORDER BY F.Posicion, F.Nombre”; cmd.Parameters.AddWithValue(“Club”, “RMA”); cmd.Parameters.AddWithValue(“Pos”, “P”); using (DbDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { while (rdr.Read()) { MessageBox.Show((string)rdr[“Nombre”]); } } } } Listado 8. Ejecución de una consulta parametrizada usando Entity Provider. La existencia de Entity SQL simplifica en gran medida la especificación no solo de las típicas vistas estáticas que acabamos de ver, sino también de consultas dinámicas (construidas en tiempo de ejecución) y parametrizadas. El listado 8 muestra un ejemplo de ejecución de una consulta parametrizada que produce un resultado similar al de los ejemplos anteriores. Observe cómo en este caso la sentencia Entity SQL se construye no sobre el modelo del almacén, sino sobre el modelo conceptual. Conclusiones En este artículo hemos mostrado los mecanismos que ofrecerá el Marco de entidades de ADO.NET para acceder a vistas del lado del servidor y definir vistas del lado del cliente, incidiendo en la importancia conceptual de éstas últimas. Después del verano (y ya con la versión definitiva del Marco de entidades a nuestra disposición), volveremos con más detalles relacionados con el lenguaje Entity SQL. ¡Que lo paséis bien! Bibliografía [ 1 ] Zorrilla, U. y Hernández, O. “El Marco de trabajo de entidades de ADO.NET 3.5” (partes I a VI), en dotNetManía nº [ 2 ] Hernández, O. “C# 3.0 y LINQ”, Segunda edición, Krasis Press, mayo de 2008. [ 3 ] "The ADO.NET Entity Framework Overview", en http://msdn.microsoft.com/en-us/library/aa697427(VS.80).aspx. [ 4 ] Blog del equipo de ADO.NET Entity Framework, en http://blogs.msdn.com/adonet/. <<dotNetManía 44-49, enero-junio de 2007. 21 Mario del Valle, Miguel Katrib, Iskander Sierra plataforma.net Paneles para el mundo 3D Este artículo debe resultar un útil divertimento para la ya creciente familia de seguidores de WPF. Aquí se verá cómo programar paneles tridimensionales para facilitar la distribución de diferentes cuerpos en un Viewport3D. A la vez, el lector encontrará detalles de algunos elementos de la API 3D de WPF que le deberán resultar de utilidad. Jerarquía de tipos del mundo bidimensional Miguel Katrib es doctor y profesor jefe de programación del departamento de Ciencia de la Computación de la Universidad de La Habana. Miguel es líder del grupo WEBOO, dedicado a la orientación a objetos y la programación en la Web. Es entusiasta de .NET y redactor de dotNetManía. Mario del Valle e Iskander Sierra son instructores de programación en C# de la cátedra de Programación e Ingeniería de Software del departamento de Ciencia de la Computación de la Universidad de La Habana. Son desarrolladores del grupo WEBOO dedicados a la tecnología .NET. visualmente a través de plantillas definidas a partir de todos los tipos de elementos de WPF. Finalmente, tenemos los paneles (herederos de Panel), que no tienen expresión visual propia sino que tienen la tarea de distribuir y mantener organizados a los elementos en el espacio bidimensional. El familiar espacio bidimensional, tal y como lo conocemos en WPF, está organizado fundamentalmente a partir de los tipos base que se muestran en la figura 1. Visual es la clase base de todos los elementos WPF que se pueden visualizar, mientras que su heredera UIElement es la base de ¿Está el mundo tridimensional igual de todos los elementos que permiten interacción con organizado? el usuario, o sea, que tienen eventos de teclado y ratón. FrameworkElement, por su parte, es la única La respuesta es: ¡aún no! Lamentablemente, en el implementación existente de UIElement y es a su mundo 3D todavía no se cuenta con tipos equivavez la clase base de casi todos los elementos de lentes a los de la figura 1. Por ejemplo, al igual que interacción. Los herederos de Shape representan a las figuras geométricas más utilizadas en la ornamentación de las ventanas y en la definición de las plantillas de controles. Los decoradores (herederos de Decorator) se utilizan con el propósito de decorar elementos, aprovechando la característica de los decoradores de poder contener otro elemento en su interior. Los controles (herederos de Control) son los protagonistas de la inteFigura 1. Síntesis de la jerarquía de los principales elementos 2D de WPF. racción, que se expresan << dnm.plataforma.net Figura 2. Planos mostrados en forma de stack en Windows Vista. Situando la clase Panel3D La figura 3 muestra la jerarquía de clases 3D que se tiene actualmente con .NET Framework 3.5. El tipo Visual3D representa a todos los elementos que se Figura 3. Jerarquía de elementos tridimensionales de WPF. muestren en un espacio tridimensional (Viewport3D). ModelVisual3D es un contenedor que permite agrupar elementos de todos los tipos en el espacio 3D. UIElement3D es la base de todos los elementos tridimensionales que permiten interacción con el usuario, mientras que Viewport2DVisual3D permite envolver un cuerpo 3D con un elemento 2D, de ¿Qué es un Panel? En [1] y [2] se describen las características que definen a un Panel bidimensional en WPF. Hagamos una abstracción de este concepto para ayudarnos a determinar cuáles son los problemas principales que se pretende que un Panel3D resuelva. 1 En la versión 3.5 de .NET Framework introdujeron un tipo UIElement3D, cuyo parecido con UIElement no es pura coincidencia, y se amenaza con más para la versión 4.0. 2 En un artículo anterior en dotNetManía [1], describimos un panel circular que nos permitía ubicar los elementos circularmente con perspectiva, pero se desplegaban de forma plana. <<dotNetManía existen figuras geométricas básicas que forman parte de la jerarquía de Shape, sería deseable poder contar con algo similar para las tres dimensiones, es decir, disponer de tipos para esferas, cubos, conos, planos, etc. Tampoco hay aún alguna suerte de Control3D (imagine un botón en forma de esfera), ni tampoco un Panel3D. La buena noticia es que el entusiasta equipo de desarrollo de MS WPF ya ha dado señales de sus intenciones de completar la jerarquía para futuras versiones1. Pero mientras esperamos por ello, con este artículo queremos presentarle un acercamiento a lo que podría ser un Panel3D que permita darle a su aplicación una visualización tan familiar como la que ofrece Vista (figura 2)2. modo que la interacción se haga con el elemento bidimensional. Como herederos de UIElement3D se tiene a ContainerUIElement3D, que permite agrupar a varios elementos de tipo UIElement3D, y a ModelUIElement3D, que facilita la incorporación de las cualidades interactivas en los elementos primitivos (elementos de tipo Model3D). La propuesta y definición de un Panel3D podría basarse en aquellos tipos que permiten agregar más de un elemento en su interior, a saber ContainerUIElement3D y ModelVisual3D. Para ser consecuentes con el modelo seguido en el mundo 2D (figura 1), el más indicado sería ContainerUIElement3D; sin embargo, la mala noticia es que esta clase por ahora está sellada (sealed en C#), así que, por decantación, es ModelVisual3D el ganador del sorteo. 23 << dnm.plataforma.net Posicionamiento Imagine que en el mundo bidimensional solo se pudiera contar con un Canvas. En ese caso, ubicar varios controles uno debajo del otro se traduciría en hacer y rehacer una secuencia de cálculos matemáticos basados en el tamaño de los controles involucrados para lograr el efecto. Cuando hubiera tenido que repetir un código similar, seguro que intentaría encapsularlo en algún tipo al que se le podría llamar StackPanel; luego haría lo mismo para la ubicación o posicionamiento de los controles en forma de tabla y entonces le llamaría Grid, y así sucesivamente. Todos estos tipos tienen, después de todo, un factor común, y es que se ocupan de determinar en qué posición deben aparecer los elementos que ellos contienen. Esta es precisamente una de las funciones principales de los paneles en WPF. Dimensionamiento Al igual que el posicionamiento, los paneles también pueden ayudar para determinar qué tamaño es el más apropiado para cada control según la distribución que el panel esté aplicando. public abstract class Panel3D : ModelVisual3D, INotifyPropertyChanged { protected Rect3D bounds; protected virtual void Move(Visual3D visual, Vector3D offset) { Transform3D transform = visual.Transform; if (object.Equals(transform, MatrixTransform3D.Identity)) visual.Transform = new TranslateTransform3D(offset); else { Transform3DGroup group = new Transform3DGroup(); group.Children.Add(new TranslateTransform3D(offset)); group.Children.Add(transform); visual.Transform = group; } } protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved) { base.OnVisualChildrenChanged(visualAdded, visualRemoved); Arrange((Visual3D) visualAdded, bounds); } protected abstract void Arrange(Visual3D visual, Rect3D rect); } Listado 1. Definición de Panel3D. public partial class StackPanel3D : Panel3D { protected override void Arrange(Visual3D visual, Rect3D rect) { int index = this.Children.IndexOf(visual); if (index >= 0) { Vector3D offset = new Vector3D(0, 0, index * Gap); Move(visual, offset); } } public double Gap { get { return (double)GetValue(GapProperty); } set { SetValue(GapProperty, value); } } public static readonly DependencyProperty GapProperty = DependencyProperty.Register(“Gap”, typeof(double), typeof(StackPanel3D), new UIPropertyMetadata(0.1)); Arrange y Measure <<dotNetManía La clase Panel que encapsula el sistema de distribución (posicionamiento y dimensionamiento) de WPF resuelve ambos problemas a partir del empleo de los métodos Arrange y Measure que contiene UIElement. Measure se ocupa de indicar cuál es el tamaño recomendable para un elemento (a partir, claro está, de información que el propio elemento debe ofrecer) y Arrange se ocupa de ubicarlo y redimensionarlo si fuera necesario, tomando en consideración el tamaño recomendado por Measure. Pero UIElement3D no tiene tales métodos y aparentemente no hay intenciones de que los tenga (figura 4). Aunque lamentablemente no se puede contar entonces con tan esenciales métodos para 3D, se puede utilizar un 24 } Listado 2. Definición de StackPanel3D. recurso de WPF que aliviará el problema. Si bien no se podrá redimensionar, al menos sí se podrán posicionar los elementos de una manera más asequible que calculando las posiciones a base de pura matemática. Transformaciones tridimensionales Al igual que en el mundo bidimensional, para 3D existen varios tipos de transformaciones lineales que se pue- Figura 4. Recorte tomado de la documentación MSDN de UIElement3D. den aplicar a todos los elementos de tipo Visual3D, Model3D y Camera. Todos estos elementos pueden ser rotados, escalados y trasladados a través de su propiedad Transform, a la que se le puede dar como valor cualquier transformación heredera de Transform3D. Las más relevantes a los efectos del StackPanel3D que queremos desarrollar son TransformGroup, que permite agrupar varias transformaciones de modo que una se aplica sobre los efectos de la anterior, y TranslateTransform, que permite trasladar en un desplazamiento por los ejes X, Y y Z. Además, usted puede utilizar RotateTransform3D y ScaleTransform3D para rotar y escalar objetos tridimensionales. << dnm.plataforma.net Definición de un Panel3D Definición de un StackPanel3D Un StackPanel3D lo definimos como heredero de Panel3D y redefiniendo el método Arrange, como se muestra en el listado 2. Obsérvese que en el listado 2 se ha agregado además la definición de la propiedad de dependencia Gap, que establece la separación entre un cuerpo y otro en el panel. Organizando el espacio 3D en un stack El listado 3 muestra una definición XAML de un espacio 3D en el que se utiliza el StackPanel3D para distribuir seis planos y una esfera como se muestra en la figura 5. El tipo SphereBuilder que se usa en este listado el lector lo puede encontrar en [3], y por economía de espacio no lo hemos repetido aquí. El tipo PlaneBuilder, al igual que SphereBuilder, se utiliza para construir una malla (MeshGeometry3D) que represente un plano. Figura 5.Visualización de un StackPanel3D. <Window x:Class=”Panel3DApp.Window1” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” xmlns:this=”clr-namespace:Panel3DApp” Title=”Window1”> <Window.Resources> <MaterialGroup x:Key=”material1”> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource=”Images/No41.png”> <ImageBrush.RelativeTransform> <ScaleTransform ScaleY=”-1” CenterY=”0.5”/> </ImageBrush.RelativeTransform> </ImageBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> <SpecularMaterial Brush=”ForestGreen” SpecularPower=”85”/> </MaterialGroup> <MaterialGroup x:Key=”material2”> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource=”Images/No42.png”> <ImageBrush.RelativeTransform> <ScaleTransform ScaleY=”-1” CenterY=”0.5”/> </ImageBrush.RelativeTransform> </ImageBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> <SpecularMaterial Brush=”RoyalBlue” SpecularPower=”85”/> </MaterialGroup> <MaterialGroup x:Key=”material”> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource=”Images/vsnet_green1.jpg”> <ImageBrush.RelativeTransform> <ScaleTransform ScaleY=”-1” ScaleX=”-1” CenterX=”0.5” CenterY=”0.5”/> </ImageBrush.RelativeTransform> </ImageBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> <SpecularMaterial Brush=”RoyalBlue” SpecularPower=”85”/> </MaterialGroup> <MaterialGroup x:Key=”material3”> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource=”Images/No43.png”> <<dotNetManía El listado 1 muestra una variante de lo que sería la clase base Panel3D. El valor por defecto de la propiedad Transform de un Visual3D es MatrixTransform3D.Identity, por ello en el método Move del listado 1 se pregunta si la propiedad Transform del Visual3D que recibe como parámetro es igual a este valor por defecto para determinar si aún no se la ha asignado ningún valor. Por lo demás, la definición de Panel3D sólo se ocupa de invocar al método Arrange en los herederos cuando se agregue un nuevo elemento al panel (código de OnVisualChildrenChanged), y de definir un método Move que puede resultar muy útil en la mayoría de los controles; su función es precisamente desplazar (mover) el cuerpo según el desplazamiento indicado por el parámetro offset. 25 << dnm.plataforma.net <ImageBrush.RelativeTransform> <ScaleTransform ScaleY=”-1” CenterY=”0.5”/> </ImageBrush.RelativeTransform> </ImageBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> <SpecularMaterial Brush=”#bFA8” SpecularPower=”85”/> </MaterialGroup> <MaterialGroup x:Key=”material4”> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource=”Images/No44.png”> <ImageBrush.RelativeTransform> <ScaleTransform ScaleY=”-1” CenterY=”0.5”/> </ImageBrush.RelativeTransform> </ImageBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> <SpecularMaterial Brush=”#bFA8” SpecularPower=”85”/> </MaterialGroup> <MaterialGroup x:Key=”material5”> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource=”Images/No45.png”> <ImageBrush.RelativeTransform> <ScaleTransform ScaleY=”-1” CenterY=”0.5”/> </ImageBrush.RelativeTransform> </ImageBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> <SpecularMaterial Brush=”#bFA8” SpecularPower=”85”/> </MaterialGroup> <MaterialGroup x:Key=”material6”> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource=”Images/No46.png”> <ImageBrush.RelativeTransform> <ScaleTransform ScaleY=”-1” CenterY=”0.5”/> </ImageBrush.RelativeTransform> </ImageBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> <SpecularMaterial Brush=”#bFA8” SpecularPower=”85”/> </MaterialGroup> <this:SphereBuilder x:Key=”sphere1” Radius=”0.6” WidthSegments=”40” HeightSegments=”40”/> <this:PlaneBuilder x:Key=”plane” WidthSegments=”20” HeightSegments=”20” Width=”3” Height=”3”/> </Window.Resources> <<dotNetManía <Grid> <Viewport3D> <Viewport3D.Camera> <PerspectiveCamera Position=”-8,4,8” LookDirection=”8,-4,-8” UpDirection=”0,1,0” FieldOfView=”45”/> </Viewport3D.Camera> <ModelVisual3D> <ModelVisual3D.Content> <Model3DGroup> <AmbientLight Color=”#8FFF”/> <DirectionalLight Color=”White” Direction=”1,0,-1”/> </Model3DGroup> </ModelVisual3D.Content> <ModelVisual3D.Children> <this:StackPanel3D <this:StackPanel3D x:Name=”cube” x:Name=”cube” Gap=”1.5”> Gap=”1.5”> <this:Panel3D.Children> 26 <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D Geometry=”{Binding Geometry, Source={StaticResource plane}}” Material=”{StaticResource material1}”/> </ModelVisual3D.Content> </ModelVisual3D> << dnm.plataforma.net <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D Geometry=”{Binding Geometry, Source={StaticResource plane}}” Material=”{StaticResource material2}”/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D Geometry=”{Binding Geometry, Source={StaticResource plane}}” Material=”{StaticResource material3}”/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D Geometry=”{Binding Geometry, Source={StaticResource plane}}” Material=”{StaticResource material4}”/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D Geometry=”{Binding Geometry, Source={StaticResource plane}}” Material=”{StaticResource material5}”/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D Geometry=”{Binding Geometry, Source={StaticResource plane}}” Material=”{StaticResource material6}”/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D Geometry=”{Binding Geometry, Source={StaticResource sphere1}}” Material=”{StaticResource material}”/> </ModelVisual3D.Content> </ModelVisual3D> </this:Panel3D.Children> </this:StackPanel3D> </this:StackPanel3D> </ModelVisual3D.Children> </ModelVisual3D> </Viewport3D> </Grid> </Window> Listado 3. Empleo de un StackPanel3D en un espacio tridimensional. Conclusiones El equipo de WPF trabaja para ampliar las capacidades y primitivas 3D a incluir en WPF. Mientras tanto, los lectores pueden descargar este código e ir dando sus primeros pasos en este terreno, apoyándose en el concepto de panel que hemos desarrollado aquí. Un tema interesante a desarrollar en el futuro es cómo sería un Grid3D. Bibliografía [ 2] [ 3] pios paneles personalizados en WPF”, dotNetManía No. 35, marzo de 2007. Katrib Miguel, Del Valle Mario, Sierra Iskander, Hernández Yamil, Windows Presentation Foundation. dotNetManía Cuaderno Técnico No. 7, Netalia 2007. Del Valle Mario, Sierra Iskander, Hernández Yamil, Katrib Miguel. “Entrando en la tercera dimensión”, dotNetManía No. 37, mayo de 2007. <<dotNetManía [ 1 ] Del Valle Mario, Sierra Iskander, Hernández Yamil, Katrib Miguel. “Cómo definir nuestros pro- 27 metodologías Luis Fraile Integrándonos continuamente Una de las prácticas más recomendadas a la hora de realizar proyectos y empezar a asegurar la calidad pronto es la de integrar todo el código lo más frecuentemente posible. Esto es especialmente importante a la hora del desarrollo iterativo, mediante el cual gestionaremos los cambios de requisitos de una forma más efectiva, entregando nuevas funcionalidades del software en cortos periodos de tiempo. Luis Fraile es MVP de Team System y colabora activamente en MAD.NUG (grupo de usuarios de .NET de Madrid). Actualmente es director técnico en Multidomo Networks, donde desarrollan un producto de software para la gestión de dispositivos domóticos y cámaras de vigilancia a través de Internet mediante interfaces web, teléfonos móviles, Media Center, etc. Puede consultar su blog en http://ww.lfraile.net. Seguro que muchos de nosotros nos hemos encontrado con la siguiente situación: el equipo de desarrollo lleva generando código un tiempo “razonable”; en el mejor de los casos, si estamos siendo “iterativos”, puede que ese tiempo no exceda de las 2 ó 3 semanas. Tenemos nuestro repositorio de código fuente, donde los desarrolladores actualizan y obtienen la última versión, y en el entorno ideal, los desarrolladores obtienen con frecuencia la última versión, antes de subir código, para compilarla y probarla. ¡Incluso tenemos pruebas unitarias que prueban el código! Sin embargo, el final de la iteración (o proyecto) se acerca, los tiempos se aprietan por otras muchas razones, el entorno ideal empieza a desmontarse, y los desarrolladores, más concentrados en sacar la funcionalidad, olvidan buenas prácticas como obtener la última versión para comprobar al menos que compila. ¿Qué ocurre entonces? Que puede llegar, y casi seguro llegará, un momento en el que alguien obtendrá la compilación (cuanto más cerca del día de entrega más posibilidades hay, según el algoritmo del Dr. Stono Compilani Decoña), y se comprobará que todo el conjunto de código ni siquiera compila: han cambiado interfaces, se ha cambiado código al que se hacen referencias, y como resultado el código de nuestro repositorio no compila. ¿Qué hemos hecho mal en este caso? Simplemente, olvidarnos de una de las buenas prácticas de los equipos de desarrollo: la integración continua. Pero, ¿qué es la integración? La integración del código consta en varios pasos: 1. Obtener la última versión de todo el código. 2. Compilar esta última versión. 3. Ejecutar el set de pruebas unitarias junto con la cobertura de código. 4. Dejar al alcance de todo el equipo esta última versión integrada de los ejecutables, así como los informes de la compilación y ejecución de las pruebas. Siguiendo esta práctica, podremos comprobar en cualquier momento el estado de nuestro código. No hay que olvidar que uno de los principales problemas que se nos presenta en los últimos momentos de la entrega es precisamente esta integración, cuando surgen problemas de código que puesto todo junto no compila correctamente por cambios en interfaces durante el desarrollo, o fallos en la ejecución del software. Esta integración nos va a dar el “latido” del proceso, ya que se convertirá el indicador del progreso de nuestro equipo, permitiéndonos comprobar, durante la iteración, que las tareas se están realizando, promocionando entre el equipo de << dnm.plataforma.net Repositorio de código fuente Lo primero que necesitamos es un repositorio de código fuente, donde los desarrolladores ponen en común su código, exponiéndolo al resto del equipo, y de donde pueden obtener asimismo el código fuente creado por los otros desarrolladores del equipo. En los entornos Microsoft, tradicionalmente se ha venido usando Visual Source Safe como repositorio. Sin embargo, desde la aparición de Visual Studio Team System, cada vez más equipos usan la nueva herramienta de control de código fuente integrada en Team Foundation Server y que se llama Team Foundation Server Version Control; ésta es en la que nos vamos a basar para este artículo, sin entrar no obstante a explicar en detalle todas sus funcionalidades y herramientas, ya que ello no es objeto de este artículo. Herramienta de compilación automatizada La siguiente herramienta que necesitaremos es la encargada de realizar la integración. Esta herramienta será la encargada, de modo automático, de obtener la última versión de las soluciones de Visual Studio que deseemos compilar, realizar la compilación de las soluciones, ejecutar el conjunto de pruebas unitarias que configuremos, y dejar los resultados del proceso en un recurso compartido accesible por el equipo de desarrollo. La herramienta que vamos a utilizar para esta tarea es la que viene integrada en Team System, y que se integra con Team Foundation Server; esta herramienta es Team Build. Tipos de integración También hay que definir los dos tipos de integración que podremos llevar a cabo, y entre los que, en función de nuestra experiencia, equipo y tipo de proyecto, podemos escoger una para nuestro proyecto. Desde la aparición de Visual Studio Team System, cada vez más equipos usan la nueva herramienta de control de código fuente integrada en Team Foundation Server y que se llama Team Foundation Server Version Control Integración continua La integración continua es el tipo de integración que se ejecuta automáticamente cada vez que un desarrollador actualiza el código fuente de nuestro repositorio (lo que solemos llamar “hacer un check-in”). En este tipo de integración, cada vez que un desarrollador realiza esta acción, se lanza la integración configurada en la herramienta, con todos sus pasos. Como se puede ver, este tipo de integración es la ideal, ya que en todo momento y en cada actualización de código, que se tiene que realizar con bastante frecuencia (varias veces al día) obtenemos una versión de los ejecutables completamente integrada. Aún siendo la ideal, tenemos que tener cuidado a la hora de ponerla en práctica, ya que en soluciones muy grandes puede generarnos bastante sobrecarga en la máquina dedicada a la ejecución del proceso. Por esta razón, la solución o soluciones para esta integración, así como la ejecución de pruebas, deben ser configuradas cuidadosamente para que no se produzcan problemas a la hora de la integración. Integración frecuente Por otra parte, la integración frecuente, a diferencia de la integración continua, solo se ejecuta con una frecuencia determinada por nosotros en la herramienta; por ejemplo, a mitad del día y al final de la tarde. Este tipo de integración nos proporciona menos resultados y menos “latidos”, pero también nos genera menos sobrecarga en las máquinas de compilación. Por tanto, la integración frecuente es ideal cuando <<dotNetManía desarrollo la cultura de subir código fuente que compile y funcione con frecuencia, favoreciendo así el desarrollo iterativo. Sin embargo, para que esta práctica sea realmente efectiva y no genere una sobrecarga de trabajo, necesitamos herramientas que nos ayuden a la hora de integrar. 29 <<dotNetManía << dnm.metodologías 30 tenemos procesos muy pesados de compilación o pruebas unitarias; pero, aún así, deberemos procurar compilar un mínimo de una o dos veces diarias, para que podamos tener la certeza de que el código se está integrando correctamente y no tener problemas a la hora de finalizar la iteración; normalmente, deberemos fijar una periodicidad de, al menos, una compilación diaria. El decidir qué tipo de integración queremos usar también nos hace pensar en algo que es muy importante a la hora de trabajar con Visual Studio, que es el decidir cuántas soluciones vamos a utilizar en nuestro proyecto y qué proyectos de Visual Studio queremos tener en cada una de esas soluciones. Pudiendo disponer así de una única solución, si nuestro proyecto no es muy grande, o varias soluciones con un conjunto pequeño de proyectos cada una, que nos ayuden a manejar de un modo más cómodo nuestro código. Es muy importante recordar además que siempre debemos llevar a cabo una planificación de entregas iterativa, ya que junto con la integración continua, éste es un modo de generar nueva funcionalidad que minimiza la posibilidad de fallos a la hora de entregar funcionalidad a nuestros clientes. Estas compilaciones se tienen que convertir en el “latido” del corazón de nuestro proyecto; algo que nos indica que diariamente estamos incrementando nuestras funcionalidades, con la adición de nuevo código con sus pruebas unitarias funcionando correctamente, y ayudándonos a detectar los fallos tan pronto como éstos surjan. Por último, hay que recordar también que cuanto más complicado sea el proyecto, más complicada y costosa será su compilación y ejecución de pruebas, de modo que la automatización de la integración nos salvará de muchos disgustos y nos ahorrará mucho tiempo, especialmente en las fases más delicadas del proyecto: el final de las iteraciones. Configuración de la integración en TFS Ahora que ya conocemos los beneficios que nos ofrece la integración y los dos tipos de integración posibles, aprenderemos a configurar la herramienta para la realización de compilaciones automatizadas. Solo recordar que, para hacer esto, necesitaremos un Team Foundation Server (TFS) como repositorio de código fuente para la realización de compilaciones con Team Build. TFS es la herramienta de servidor que pertenece al conjunto de herramientas para la gestión del ciclo de vida del software de Microsoft, y que nos sirve como repositorio de código fuente, tareas (Work Items), documentación (en SharePoint) y que nos proporciona métricas a nivel de proyectos. Instalación del agente de compilaciones Para la realización de compilaciones con TFS, lo primero que necesitamos es un agente de compilaciones. Este agente lo podemos instalar en cualquier ordenador con conexión a nuestro TFS. Puede ser incluso un ordenador del equipo de desarrollo, si bien se recomienda que se instale en un ordenador independiente, en equipos pequeños, con pocos proyectos y por tanto pocas compilaciones automatizadas. Podemos instalar el agente en el mismo servidor TFS, pero para equipos grandes o con muchos proyectos se recomienda un servidor aparte para las compilaciones. En ese equipo, necesitaremos además una versión de Visual Studio Team System para la compilación y ejecución de las prue- bas. Ésta debería ser al menos Visual Studio Team System Tester Edition, para permitirnos ejecutar pruebas de todo tipo, o mejor aún Visual Studio Team System Team Suite. Hay que señalar que para el agente de compilaciones no necesitamos una licencia extra de Visual Studio, sino que podemos utilizar una misma licencia ya usada en otra de nuestras máquinas de desarrollo. La instalación del agente de compilaciones se realiza desde el CD/DVD de TFS. Una vez insertemos el CD/DVD de TFS en la máquina elegida, se nos mostrará la pantalla inicial de instalación, y deberemos seleccionar la opción “Team Foundation Build”. Aquí se nos mostrará un asistente (wizard) de instalación, en el que podremos seleccionar el directorio de instalación, y lo más importante, la cuenta de ejecución del servicio del agente, que será la cuenta con la que éste se conectará al TFS. Esta cuenta deberá tener permisos de acceso al TFS, y en caso de existir un dominio, debe pertenecer a éste. Puede ser la misma cuenta que utilizamos para la instalación de los servicios de TFS: TFSService (asegurar antes que habéis configurado esta cuenta en la instalación), si bien esta cuenta hay que tenerla controlada, ya que Figura 1 << dnm.metodologías tiene acceso completo a TFS, algo que puede no ser adecuado en muchos entornos (ver figura 1). Con esto, ya podemos completar la instalación de nuestro agente de compilaciones. Tampoco vamos a detenernos más en este punto; si necesitáis más información al respecto, en el CD/DVD de TFS disponéis de las guías completas de administración y configuración, accesibles desde la primera pantalla. Configuración de la compilación Una vez tengamos el agente instalado, ya estamos listos para configurar nuestra primera compilación automatizada. El primer paso es abrir nuestro Visual Studio 2008 y, en la ventana de Team Explorer, seleccionar la rama “Builds” y obtener su menú contextual. Configurando el agente El primer paso es agregar el agente de compilaciones que hemos instalado anteriormente, para esto, seleccionamos la opción “Manage Build Agents” del menú. En la ventana de gestión “Build Agents” tenemos el listado de agentes configurados; para añadir uno nuevo, pulsamos “New…”. Simplemente le pondremos un nombre significativo para referirnos a él, una descripción (opcional), e indicaremos el nombre de máquina dónde hemos instalado previamente el componente de Team Foundation Build y el puerto (dejaremos el por defecto). Adicionalmente, podemos seleccionar si queremos que se use comunicación HTTPS, y el estado inicial (dejaremos el por defecto también). Un punto importante a configurar en esta pantalla es el directorio de trabajo: “Working directory”. Por defecto, .NET no admite rutas de disco mayores de 256 caracteres, por lo que os recomiendo crear un directorio con nombre corto, por ejemplo C:\B, y utilizar ese directorio en sustitución del directorio temporal, quedando así: C:\B\$(BuildDefinitionPath). <<dotNetManía Configuración de la definición de la compilación 32 El siguiente paso es crear la definición de nuestra compilación automatizada. Para ello, seleccionamos la opción “New Build Definition” en el menú contextual de “Builds”. En la pantalla inicial de configuración de una compilación, debemos prestar especial atención a los puntos marcados con el icono de advertencia, que son los principales. Vamos a ver punto por punto. • General En este punto debemos de introducir el nombre con el que vamos a referirnos a esta compilación, así como, opcionalmente, una descripción. También disponemos de una casilla para desactivar la definición de esta compilación. • Workspace El workspace es el espacio de trabajo que usará el agente de compilaciones. Aquí podemos definir qué ramas del repositorio de control de fuentes obtendrá el agente a la hora de realizar una compilación; al ser éste un ejemplo básico, lo dejaremos con los valores por defecto. Esto se usaría también para separar en distintas compilaciones de integración continua las distintas partes de nuestro proyecto, para evitar así compilar siempre todo al completo en caso de proyectos muy grandes. Para ello, definiríamos aquí qué espacios de trabajo queremos que lancen la compilación a la hora de un check-in. • Project File En este punto vamos a generar el fichero que se encargará de definir qué soluciones y qué pruebas queremos ejecutar. Lo primero es indicar en qué rama del repositorio de fuentes vamos a crear el fichero de definición. Este fichero se llamará TFSBuild.proj, y es un documento XML que podremos editar para personalizar los pasos de nuestras compilaciones. Para crear uno nuevo, pulsamos el botón “Create…”. El primer paso es seleccionar qué solución o soluciones vamos a compilar. Por defecto, no podemos seleccionar proyectos por separado; solo lo podemos hacer a nivel de solución. Una vez seleccionadas las soluciones que queremos compilar, podremos pasar al siguiente paso (figura 2), en el que deberemos especificar qué configuraciones queremos compilar. Una misma solución la podemos compilar con diferentes configuraciones (Debug, Release o configuraciones personalizadas), así como para diferentes plataformas (x86, x64, Any CPU). Pero estas configuraciones tienen que ser configuraciones existentes en nuestras soluciones, ya que si no la compilación no funcionará correctamente; estas configuraciones las podemos comprobar abriendo la solución en Visual Studio y comprobando el gestor de configuraciones (Configuration Manager). El siguiente paso es decidir qué pruebas vamos a ejecutar, lo que se hace en la ventana de opciones. Para decidir qué pruebas ejecutar, seleccionaremos la opción “Run tests”, y del listado de ficheros de listas << dnm.metodologías recomiendo hacerlo antes, fuera de las compilaciones automatizadas. Una vez que pulsemos “Finish”, se nos creará el fichero TFSBuild.proj con las configuraciones elegidas, volviendo a la pantalla de configuración de la compilación. De estas configuraciones no disponemos a posteriori de un editor gráfico integrado, aunque sí existen herramientas de terceros, como los sidekicks de Attrice (http://www.attrice.info). de pruebas unitarias (ficheros con extensión .vsmdi) seleccionamos el que tiene la lista de pruebas que queremos ejecutar; entonces en la ventana de listas de pruebas podremos seleccionar las que queremos ejecutar. Si no estamos trabajando con listas de pruebas, podemos seleccionar ejecutar automáticamente todas las pruebas que estén en una DLL que cumpla con un determinado patrón; ésta es la segunda opción que se nos muestra, y como patrón se nos propone que la DLL de pruebas comience con la palabra “Test”. Es importante tener en cuenta que el sistema detectará y ejecutará todas las pruebas de esa DLL; por tanto, es importante mantener aisladas en ella únicamente las pruebas que deseemos ejecutar, siendo preferible que sean únicamente pruebas unitarias o de ejecución muy simple. En esta última pantalla también podemos especificar si queremos que se ejecute el analizador de código estático para cada proyecto según la configuración detallada en cada proyecto. Este analizador comprobará que nues- tro código cumple los conjuntos de reglas de diseño y codificación, como si de un revisor de código se tratase. Si no estáis familiarizados con esto, os Figura 3 <<dotNetManía Figura 2 • Políticas de retención Volviendo a la pantalla principal de configuración de la compilación, tenemos el apartado de políticas de retención. Como podemos suponer, el compilar diariamente una o varias veces y dejar compartidos los binarios, resultados de pruebas unitarias, etc. genera muchos ficheros que pueden llegar a crear un problema de almacenamiento en la máquina de compilación. Para evitar que esto suceda, podemos especificar qué resultados queremos guardar mediante políticas de retención (figura 3). 33 << dnm.metodologías Los posibles resultados de la compilación son: • Failed: la solución no se ha compilado correctamente. • Stopped: hemos detenido la compilación durante su ejecución. • Partially succeeded: cuando una compilación da este resultado, alguna o todas las pruebas unitarias han fallado. • Succeeded: la compilación y sus pruebas unitarias han funcionado correctamente. Y lo que podemos especificar en la figura 3 es qué número de resultados de compilación queremos conservar. Es recomendable especificar cuántas queremos guardar para cada uno de los resultados, ya que si bien podremos eliminar los resultados manualmente, lo más cómodo es que TFS lo haga por nosotros. <<dotNetManía • Build defaults En la figura 4 podemos ver la pantalla de selección del agente de compilación, y el recurso compartido (en este caso \\tfsdemos\deploy) en el que se almacenarán los resultados de esta generación. En el listado de agentes de compilación, seleccionaremos el que hemos configurado previamente. Es importante tener en cuenta que en ese recurso compartido de red, el usuario que configuramos durante la instalación del agente de compilación (TFSService) debe tener acceso de lectura y escritura para dejar los binarios. En ese recurso compartido se creará una carpeta con el nombre de la compilación y un número de identificación (basado en la fecha y orden de compilación) que contendrá los resultados de cada compilación, manteniendo así un histórico de compilaciones. Estos directorios se borrarán dependiendo de las políticas de retención. 34 • Triggers (disparadores) Por último, podemos configurar la periodicidad de nuestra compilación. Figura 4 Las opciones que tenemos a nuestra disposición son: • Check-ins do not trigger a new build: si seleccionamos esta configuración, la compilación solo se lanzará cuando la lancemos manualmente desde el menú “Builds” de Team Explorer, seleccionando la compilación y en su menú contextual, la opción “Queue Build”. • Build each check-in: con esta opción, cada vez que un usuario haga check-in de código fuente se lanzará esta compilación. Ésta es la opción que nos proporciona una compilación de integración continua. • Accumulate check-ins…: con esta opción, también tendremos un entorno parecido al de integración continua, pero para evitar un número excesivo de compilaciones, especialmente en equipos grandes, podemos acumular check-ins, hasta que la compilación previa acabe, y además especificar que no se lance la compilación más de una vez cada X minutos, para, por ejemplo, no compilar más de una vez cada hora. • Build every week on…: con esta configuración, especificaremos una periodicidad para nuestras compilaciones. Podemos especificar qué días de la semana queremos compilar, a qué hora, y especificar si queremos compilar independientemente de que haya cambios o no en el repositorio de código. Esto nos daría un entorno de integración frecuente. Una vez configuradas todas las opciones, pulsando el botón “Ok”, se creará nuestro nuevo tipo de compilación, que aparecerá en el listado “Builds” de nuestro Team Explorer. Con esto ya tendremos nuestro entorno listo, y la compilación se ejecutará según la periodicidad elegida, o bien manualmente mediante la opción “Queue build” del menú contextual de cada tipo de compilación. << dnm.metodologías Para comprobar los resultados de una compilación, haremos doble clic en el listado de tipos de compilación de Team Explorer. La ventana que obtendremos nos mostrará si hay alguna compilación realizándose actualmente, en cuyo caso podremos hacer doble clic en ella y ver los pasos que se están ejecutando, como obtención de fuentes, compilación, ejecución de pruebas… En esta ventana también podemos seleccionar, mediante los filtros de la parte superior, otros agentes de compilación u otros tipos de compilación para ver el estado de compilaciones encoladas. Para ver los resultados de compilaciones pasadas, en esta misma pantalla, en la parte inferior, tenemos la pestaña “Completed”, que nos mostrará la ventana de la figura 5, en la que vemos el listado de las compilaciones finalizadas. Por defecto, los filtros muestran solo las compilaciones finalizadas en un día; si queremos ver más resultados, podemos cambiar el filtro de fecha. En ese listado se nos muestra además el resultado de cada compilación mediante el icono de la izquierda, siendo éste Crear un entorno base de integración continua con Visual Studio 2008 Team System no es nada complicado 1 Nota del Editor: ¡Por supuesto que sí! Conclusiones Como veis, crear un entorno base de integración continua con Visual Studio 2008 Team System no es nada complicado, y lo podemos lograr mediante unos sencillos pasos basados en asistentes. Si bien hemos mostrado solo los fundamentos, y dependiendo de nuestro proyecto, podemos extenderlo para conseguir una mayor funcionalidad de nuestro entorno de integración continua. Muchas de estas funcionalidades se comentan en diferentes blogs, e iré presentando algunas de ellas en el futuro, tanto a través de artículos en esta revista (si me dejan ☺ ) 1 como a través de mi blog en http://www.lfraile.net. El lector también puede encontrar más información en otros blogs (en inglés) relacionados con Team System: http://msdn2.microsoft.com/en-us/teamsystem/aa718761.aspx. Y esto es todo por ahora. Os animo a todos los que ya estéis usando TFS a sacar un poco más de partido a vuestro servidor, utilizando los entornos de integración continua/integración frecuente. <<dotNetManía Resultados de compilación una “pelotita” verde para indicar que todo ha sido correcto, o roja, para indicar que no se ha podido realizar la compilación. Si tenemos una pelotita roja y una verde, es que el resultado ha sido parcialmente Figura 5 correcto (fallo en pruebas unitarias). También podremos ver los detalles de cualquier compilación haciendo doble clic sobre ella. En la ventana emergente obtendremos los resultados detallados de esa compilación, así como un enlace directo al recurso compartido donde están los binarios resultantes y los logs de la compilación, para que todo el equipo del proyecto tenga disponible la última versión. Otra de las funcionalidades que obtenemos directamente de Team System es la alerta de compilaciones completadas, que nos permite disponer de datos al momento de la finalización de la compilación. Para ello, en el menú contextual del proyecto en el Team Explorer debemos seleccionar la opción “Project Alerts”. Podemos configurar distintos tipos de alertas, introduciendo nuestra dirección de correo electrónico; la que nos interesa para estar al tanto de las compilaciones es la opción “A build completes”. 35 plataforma.net Juan Carlos Viñas Frameworks para Javascript Las técnicas de desarrollo en Javascript, así como los usos que se le dan a esta tecnología, han cambiado notablemente en los últimos años. Hoy en día, nos es difícil pensar que una aplicación Web moderna pueda prescindir de esta tecnología para finalidades tan diversas como la comunicación asíncrona entre cliente y servidor, la aplicación de efectos visuales a nuestro código HTML o mantener nuestro propio sistema de caché en el lado del cliente. Cuando implementamos una aplicación Web, a menudo necesitamos escribir partes de código que han de ser ejecutadas en el navegador. Este código debe ser escrito en Javascript, y es aquí cuando nos puede ser útil la ayuda de una librería de código en este lenguaje. Es por esto que en los últimos años han comenzado a aparecer librerías que han cambiado la forma de incorporar código Javascript a una aplicación Web: ya no necesitamos escribir todo el código nosotros mismos, porque existen multitud de recursos que nos ayudarán a programar más rápida y fácilmente de lo que nunca antes había sido posible. Estas librerías son recursos que podremos conectar a nuestros frameworks de desarrollo y que ofrecen soluciones a los problemas más comunes con los que se encuentra un programador Web a la hora de escribir código Javascript. Eligiendo la librería que más nos conviene Juan Carlos Viñas Custom Development Manager de Raona. Juan Carlos es MCSD .NET La mayoría de las librerías Javascript más populares comparten muchas de sus funcionalidades. Es por eso que elegir qué librería es la que mejor se adapta a nuestras necesidades no siempre es fácil. Estos son algunos de los criterios que no podemos dejar de tener en cuenta a la hora de elegir nuestra librería: • ¿Dispone de todas las funcionalidades que necesitamos? Es importante que la librería que elijamos tenga todas las funcionalidades que queramos utilizar. Muchas de las librerías de Javascript comparten el mismo espacio de nombres (como $()), lo que hace que no sea fácil combinar sus funcionalidades. Además, al combinar librerías nos arriesgamos a tener código redundante en nuestra aplicación. • ¿Dispone de más funcionalidades de las que realmente necesitamos? Cuantas más funcionalidades tenga una librería, es de esperar que ésta contenga más líneas de código y por tanto sea más costosa de descargar. Muchas de las librerías actuales disponen de versiones “ligeras” e incluso algunas están divididas en módulos, lo que nos permite incluir en nuestra aplicación solo aquellas funcionalidades en las que estemos realmente interesados. • ¿Es compatible con todos los navegadores? Las librerías Javascript suelen funcionar independientemente del navegador en que se ejecuten. Esto es una gran ventaja, ya que permi- << dnm.plataforma.net • ¿Dispone de un buen soporte por parte de la comunidad? Una comunidad de usuarios y desarrolladores activa se traduce en menos errores y un código de mayor calidad, además de constituir un valioso recurso al que recurrir en caso de necesitar ayuda. • ¿Dispone de documentación? Una buena documentación y un lugar donde encontrar ejemplos de uso resulta fundamental para entender, y por tanto utilizar correctamente, cualquier librería. Selección de elementos de una página Una de las características más útiles de las librerías multipropósito son los selectores de elementos. Estos selectores son una potente herramienta que nos permite seleccionar elementos de una página de forma simple y eficiente. Realizar selecciones complejas utilizando las funciones nativas que Javascript nos ofrece puede ser una tarea realmente tediosa. Por ejemplo, si quisiéramos obtener todos los controles RadioButton seleccionados en una página, primero tendríamos que obtener todos los elementos de tipo <input> utilizando la función getElementByTagName, y luego iterar sobre estos elementos, seleccionando los que sean de tipo radio y que tengan el atributo checked. En cambio, utilizando una librería como jQuery (http://www.jquery.com), el código necesario se simplificaría a: • ¿Tiene la licencia que nos interesa? $(“input[@type=radio][@checked]”) Que dispongamos del código fuente de una librería no significa que podamos hacer con él lo que nosotros queramos. La mayoría de estas librerías son libres, pero otras exigen que cualquier código que se escriba usando alguna de sus funcionalidades se libere bajo la misma licencia que ellas. ¿Qué tipo de funcionalidades me pueden aportar? Existen muchas librerías, y cada una de ellas tiene sus propias particularidades. Existen librerías con funcionalidades muy específicas, y otras que pretenden proporcionar herramientas para facilitar las tareas más cotidianas de un programador Web. A las librerías de este último tipo se les llama librerías multipropósito, y en el siguiente apartado vamos a ver cuáles son las funcionalidades más comunes que éstas suelen incorporar. Otro ejemplo: supongamos que queremos seleccionar todos elementos de tipo párrafo que tengan en su atributo class el valor class1 y que además contengan un elemento de tipo hiperenlace. En Javascript tradicional, tendríamos que seleccionar todos los elementos de tipo <p> mediante la función getElementByTagName, iterar sobre éstos para seleccionar los que tengan el valor class1 en su atributo class, y por último recorrer todos los nodos hijos de estos últimos para comprobar que tengan un hijo de tipo <a>. Utilizando jQuery, nos bastaría con escribir la siguiente línea: La combinación del lenguaje XPath y los selectores CSS nos permiten realizar selecciones mediante prácticamente cualquier criterio que se nos ocurra, y esto es algo que también nos ofrecen librerías como jQuery. Comunicación asíncrona entre cliente-servidor (AJAX) Resulta casi imposible hablar sobre tecnología Web sin hablar sobre AJAX. AJAX es una combinación de tecnologías ya existentes, y éstas, como no, tienen los mismos problemas de incompatibilidad entre navegadores que siempre tuvieron. Las librerías Javascript nos ayudan a solucionar estos problemas, además de simplificar nuestras llamadas desde cliente hacia el servidor. Probablemente el objeto AJAX más popular de entre todas las librerías Javascript es el que nos ofrece Prototype (http://www.prototypejs.org). Prototype.Ajax funciona en todos los navegadores modernos y nos ofrece métodos que nos permiten trabajar con AJAX de una forma simple: • El método Ajax.Request realiza una petición simple al servidor: new Ajax.Request(‘/some_url’, { method:’get’, onSuccess: function(){ alert(“It works!”); } }); • Con el método Ajax.Updater podemos incrustar directamente el contenido devuelto por la petición AJAX a un nodo de nuestra página. La siguiente llamada insertaría el resultado de la petición en el nodo “node”: $(“p.class1[a]”); Estos dos ejemplos son una pequeña muestra de lo que los selectores de las librerías multipropósito pueden simplificar nuestro código, pero éstas todavía pueden ofrecernos mucho más. new Ajax.Updater(‘node’, ‘/some_url’, { method: ‘get’, insertion: Insertion.Top }); <<dotNetManía te al programador olvidarse de las diferencias entre navegadores y escribir el código con la certeza de que funcionará correctamente en todos los navegadores que la librería soporte. 37 << dnm.plataforma.net • Ajax.PeriodicalUpdater realiza peticiones periódicas al servidor, e inserta el contenido que obtiene en el nodo de nuestra página que indiquemos: new Ajax.PeriodicalUpdater(node, ‘/some_url’, { method: ‘get’, insertion: Insertion.Top, frequency: 1, decay: 2 }); El parámetro frecuency hace referencia al intervalo de tiempo entre llamadas, mientras que el parámetro decay es el factor por el cual se multiplica la frecuencia cada vez que el contenido de la respuesta sea el mismo. De esta forma evitamos sobrecargar al servidor con un número excesivo de peticiones. Gestión de eventos <<dotNetManía La gestión de eventos es otra de las tareas que puede resultar complicada debido a las incompatibilidades entre navegadores: mientras que Internet Explorer utiliza su propio método attachEvent para asociar eventos a elementos de una página, el resto de navegadores utiliza el método addEventListener. Las librerías Javascript nos ahorran este tipo de problemas y nos permiten tratar eventos de forma más intuitiva. Como ejemplo, podemos ver cómo añadir eventos a un elemento <textarea> utilizando la librería mootools (http://www.mootools.net). 38 La selección de elementos, AJAX y la gestión de eventos en cliente son solo una parte de lo que las librerías Javascript nos pueden ofrecer En el ejemplo anterior vemos cómo asociar múltiples eventos a un elemento mediante el método addEvents, cómo crear eventos propios, y cómo lanzar eventos mediante fireEvent. Si escribimos la palabra “hello” en el cuadro de texto se lanzará nuestro evento propio, al que hemos llamado “burn”, mientras que si escribimos la palabra “delayed” obtendremos el mismo resultado, con la diferencia que el evento se lanzará al cabo de 1000 ms. Y mucho más… La selección de elementos, AJAX y la gestión de eventos en cliente son solo una parte de lo que las librerías Javascript nos pueden ofrecer. Tareas tan complejas como añadir efectos visuales a nuestra página o implementar un sistema de arrastrar y soltar se simplifican enormemente utilizando librerías como jQuery, Prototype o mootools. Es por esto que resulta altamente recomendable conocer las posibilidades de estas librerías antes de embarcarse en cualquier proyecto Web. $(‘myTextarea’).addEvents({ ‘focus’: function() { if ($(‘myTextarea’).value.contains(‘Type here’)) $(‘myTextarea’).value = ‘’; }, ‘keyup’: function() { if ($(‘myTextarea’).value.contains(‘hello’)) $(‘myTextarea’).fireEvent(‘burn’, ‘hello world!’); else if ($(‘myTextarea’).value.contains(‘delayed’)) $(‘myTextarea’).fireEvent(‘burn’, “I’m a bit late!”, 1000); }, ‘burn’: function(text) { $(‘myTextarea’).value = ‘burn! ‘ + text; } }); plataforma.net Daniel Seara Componentes de uso general Otro mes, y otro componente. Veamos cómo nuestros otros componentes pueden relacionarse con el sistema operativo, la seguridad, los usuarios… el Directorio activo. De la identificación de usuarios y su relación con la red Imports AD = System.DirectoryServices En muchas ocasiones, identificar al usuario que realiza una acción es requerido en las aplicaciones. Y más que eso, reflejar en la interfaz del usuario dicha información, e inclusive las opciones y comportamiento de la misma pueden depender de esta información. Es por ello que nos resultará útil contar con un componente que encapsule métodos que nos faciliten la relación con el Directorio activo. ¿Qué necesitamos? Listado 1 Dominio actual. Para una funcionalidad básica, es suficiente con utilizar los tipos que se encuentran en System.DirectoryServices. Dentro de ese espacio de nombres, la clase DirectorySearcher nos permite encontrar información en el Directorio activo. Pero antes de esto, necesitamos saber en qué entorno nos encontramos. Daniel Seara es mentor de Solid Quality Mentors y director del área de desarrollo .NET. Es MVP desde 2003 y ponente habitual de y Microsoft. [ NOTA Nueva idea, nuevo ensamblado: en mi caso Solid.Servers.ActiveDirectory Public Class Environment Private Shared mDomainName As String Public Shared Function DomainName() As String If mDomainName = “” Then mDomainName = _ AD.ActiveDirectory.Domain.GetCurrentDomain.Name End If Return mDomainName End Function ] Agreguemos a este ensamblado una clase que nos defina el entorno: Environment. En ella, podremos agregar un método que nos retorne cuál es el nombre del dominio actual, como se ve en el lis- Private Shared mActualUser As String Public Shared Function ActualUserName() As String If mActualUser = “” Then mActualUser = _ System.Threading.Thread.CurrentPrincipal.Identity.Name End If Return mActualUser End Function Listado 2. Usuario actual. tado 1. Además, podríamos agregar otro método para obtener la identificación del usuario actual, como muestra el listado 2. Internamente, esa clase siempre podría necesitar acceder al dominio para obtener otros objetos y referencias. Entonces sería conveniente disponer de la función privada cuyo código encontramos en el listado 3. << dnm.plataforma.net cosa que los servicios de directorio son capaces de brindarnos si hacemos una búsqueda con DirectorySearcher, como vemos en el listado 4. Ahora bien, una vez se obtiene un SearchResult (uno de los miembros de la variable r), éste contiene un DirectoryEntry y a través de él podemos obtener qué propiedades expone. Pero, por otra parte, hay algunos grupos que expo- Private Shared mDomainEntry As AD.DirectoryEntry Private Shared ReadOnly Property DomainEntry() As AD.DirectoryEntry Get If mDomainEntry Is Nothing Then mDomainEntry = _ AD.ActiveDirectory.Domain.GetCurrentDomain.GetDirectoryEntry End If Return mDomainEntry End Get End Property Listado 3. Información del dominio. En muchas ocasiones, solo necesitaremos información específica de cualquiera de los elementos del directorio. Y eso significa que resulta inútil, además de algo más inseguro, requerir referencias al espacio de nombres de servicios de directorio. Siempre que sea posible, es preferible enmascarar los objetos y usar los propios para tener un control adecuado de la información brindada. Por otra parte, los servicios de directorio de Windows tienen un inconveniente, y es que a ellos se accede a través de ADSI (Active Directory Service Interfaces), un conjunto de interfaces COM modeladas a partir del protocolo LDAP (Lightweight Directory Access Protocol), diseñado en la era pre-nética ☺. Por lo tanto, no son precisamente la perfección respecto al diseño orientado a objetos. Cada objeto expone propiedades diferentes, hay propiedades que retornan más de un valor, no están adecuadamente identificados los tipos de datos. Conceptualmente, además, se trata de implementaciones genéricas que se expresan usando identificadores de clase (que no son clases específicas). Podemos, sin embargo, convertirlas en algo más “nético”, aprovechando cosas como la generación de código y los mecanismos de reflexión. [ Dim ms As DirectoryServices.DirectorySearcher = Searcher() With ms .Filter = “(objectClass=group)” .SearchScope = DirectoryServices.SearchScope.Subtree Dim r As DirectoryServices.SearchResultCollection = .FindAll End With Listado 4. Búsqueda de grupos. Dim colElements As New Dictionary(Of String, MyPropertyInfo) Sub GetPropertyInfo(ByVal en As DirectoryServices.DirectoryEntry) For Each v As PropertyValueCollection In en.Properties If v.Value.GetType.ToString <> “System.__ComObject” Then With colElements If .ContainsKey(v.PropertyName) Then If .Item(v.PropertyName).Count < v.Count Then .Item(v.PropertyName).Count = v.Count End If Else Dim p As New MyPropertyInfo With _ {.Count = v.Count, _ .DataTypeName = v.Value.GetType.ToString, _ .Name = v.PropertyName} .Add(v.PropertyName, p) End If End With End If Next End Sub Listado 5. Diccionario de propiedades. Consideremos, para comenzar, que posiblemente nos interese administrar permisos de nuestras aplicaciones en base a grupos de seguridad. Para ello necesitaríamos la lista de los grupos, NOTA La sintaxis de filtrado en LDAP puede ser compleja. Por ejemplo, los argumentos encerrados entre paréntesis, los nombres y valores de los filtrados, etc. suelen no ser simples. El primer punto de referencia está en http://msdn.microsoft.com/es-es/library/system.directoryservices.aspx ] nen distintas propiedades (o distinta cantidad de valores para una propiedad). Por ello, recorreremos todas ellas y obtendremos una lista de las propiedades existentes. Una vez las tengamos, podremos generar el código correspondiente a cada una. En el listado 5 se ve cómo se van coleccionando las propiedades en un diccionario donde guardamos una clase MyPropertyInfo (listado 6), que nos permite almacenar: <<dotNetManía Enmascarando los objetos de directorio 41 << dnm.plataforma.net Friend Class MyPropertyInfo Private mName As String Public Property Name() As String Get Return mName End Get Set(ByVal value As String) mName = value End Set End Property Private mCount As Integer Public Property Count() As Integer Get Return mCount End Get Set(ByVal value As Integer) mCount = value End Set End Property Private mDataTypeName As String Public Property DataTypeName() _ As String Get Return mDataTypeName End Get Set(ByVal value As String) mDataTypeName = value End Set End Property End Class Listado 6. Clase MyPropertyInfo. <<dotNetManía • El nombre de la propiedad. • La cantidad de valores que contiene. • El tipo de dato que almacena. 42 En la búsqueda de propiedades, se excluyen aquellas que son de tipo ComObject, que son las que internamente ADSI utiliza para la manipulación de información. Una vez que se obtiene la colección completa de propiedades (y asumiendo que la muestra es lo suficientemente significativa), podemos generar código para exponer dichas propiedades un la clase Group que pretendemos definir. Utilizamos una plantilla para generar el código correspondiente a cada propiedad. Considerando que habrá propiedades con más de un valor, tendremos en realidad dos plantillas: una para propiedades simples (listado 7) y otra para propiedades indexadas (listado 8). Private m{0} As {1} Public Property {0}() As {1} Get Return m{0} End Get Set(ByVal value As {1}) m{0} = value End Set End Property Listado 7. Plantilla para propiedad simple. Private m{0} As New Dictionary(Of String, {1}) Public Property {0}(ByVal key As String) As {1} Get Return m{0}(key) End Get Set(ByVal value As {1}) If m{0}.ContainsKey(key) Then m{0}(key) = value Else m{0}.Add(key, value) End If m{0}(key) = value End Set End Property Listado 8. Plantilla para propiedad Indexada. Como se ve, en ambos casos se utiliza una sintaxis acorde a los marcadores posicionales de formatos. Ambos códigos se agregan como recursos en el Sub GenProperties() Dim st As New StringBuilder For Each p As MyPropertyInfo _ In colElements.Values Dim sFormat As String = “” If p.Count = 1 Then sFormat = My.Resources.PropertyDef Else sFormat = My.Resources.IndexedPropDef End If Dim sDT As String=p.DataTypeName.Replace(_ “[“, “(“).Replace(“]”, “)”) If p.Count > 1 Then sDT = sDT.Replace(“(“, “”).Replace(“)”,“”) End If st.AppendFormat(sFormat, p.Name, sDT) Next Using fi As New IO.StreamWriter(“c:\Props.vb”) fi.Write(st.ToString) fi.Close() End Using End Sub Listado 9. Generador de propiedades. Friend Sub New(ByVal de As DirectoryServices.DirectoryEntry) For Each v As PropertyValueCollection In de.Properties If v.Value.GetType.ToString <> “System.__ComObject” Then Dim sFormat As String = “” If Me.GetType.GetProperty(v.PropertyName) .GetIndexParameters.Count = 0 Then CallByName(Me, v.PropertyName, CallType.Let, v.Value) Else For i As Integer = 0 To v.Count - 1 Dim arr As New ArrayList If v.Value.GetType.IsArray Then arr.AddRange( _ CType(v.Value, Collections.ICollection)) Else arr.Add(v.Value) End If CallByName(Me, v.PropertyName, _ CallType.Let, i, arr(i)) Next End If End If Next End Sub Listado 10. Constructor de la clase Group. << dnm.plataforma.net proyecto de generación (una aplicación auxiliar que solo sirve para generar este código). Entonces, el procedimiento del listado 9 crea una cadena de caracteres que contiene las definiciones de todas las propiedades y genera con ellas un archivo en disco. Los métodos Replace en el listado 9 permiten quitar la declaración de valor de tipo array en las propiedades múltiples, ya que eso lo re-implementamos usando nuestra propia metodología para la manipulación de dichas propiedades multi-valor. Usando el código generado en el archivo props.vb, podemos definir ahora la clase Group, que exponga y sea capaz de cargar las propiedades a partir de una entrada de directorio. Para ello, implementamos un constructor (listado 10) que recibe una variable de tipo DirectoryEntry para obtener los valores y utiliza reflexión para cargar los valores de las propiedades. Siguiendo procedimientos similares, pero utilizando otros filtros LDAP, podemos definir clases de usuario, unidad organizativa, servidor, etc. For Each el In Solid.Servers.ActiveDirectory.Environment.Groups ‘agrega un ítem en la lista With ListView1.Items.Add(el.name) ‘recorre las propiedades de la clase Group For Each p As System.Reflection.PropertyInfo In _ el.GetType.GetProperties ‘si aún no está definida la columna, la agrega If Not ListView1.Columns.ContainsKey(p.Name) Then ListView1.Columns.Add(p.Name, p.Name) End If ‘pos es el índice de la columna Dim pos As Integer = ListView1.Columns(p.Name).Index ‘si el ítem agregado tiene menos subítems, ‘agrega hasta alcanzar la posición While pos > .SubItems.Count - 1 .SubItems.Add(“”) End While ‘intenta agregar el valor Try .SubItems(pos).Text = _ CallByName(el, p.Name, CallType.Get).ToString Catch ex As Exception ‘(puede haber errores, que se ignoran) End Try Next End With Next Listado 12. Cargando una lista con todos los grupos. Mejorando los resultados obtenidos Figura 1. Lista parcial de grupos. que nos permita discriminar dichos elementos accesibles por los usuarios. Public Shared Function Groups() As List(Of Group) Dim ms As DirectoryServices.DirectorySearcher = Searcher() Dim g As New List(Of Group) With ms .Filter = “(objectClass=group)” .SearchScope = DirectoryServices.SearchScope.Subtree Dim r As DirectoryServices.SearchResultCollection = .FindAll For Each rr As DirectoryServices.SearchResult In r g.Add(New Group(rr.GetDirectoryEntry)) Next End With Return g End Function Listado 11. Lista de grupos. Comencemos por mostrar en un ListView de una aplicación Windows Forms todas y cada una de las propiedades de los objetos de tipo Group que obtenemos de nuestro directorio. Definamos en nuestra clase de entorno un método que nos devuelva una lista de los grupos presentes en el directorio (listado 11). Podemos obtener el conjunto de grupos del Directorio activo y presentar en columnas cada una de sus propiedades como se muestra en el listado 12. Ejecutando esta operación, se cargará una lista con todos los grupos, como muestra la figura 1. En ella podemos ver <<dotNetManía El Directorio activo define muchos elementos que normalmente no se encuentran disponibles para los usuarios y que, sin embargo, aparecen cuando consultamos por código utilizando LDAP. Por ello, siempre es bueno tener claro (y utilizar adecuadamente) la información 43 << dnm.plataforma.net Los servicios de directorio de Windows tienen un inconveniente, y es que a ellos se accede a través de ADSI (Active Directory Service Interfaces), un conjunto de interfaces COM modeladas a partir del protocolo LDAP (Lightweight Directory Access Protocol), diseñado en la era pre-nética que la propiedad groupType nos permite agruparlos, para así entender cuáles son los más útiles a nuestros fines. Si creamos grupos (aprovechando las características propias del control ListView), veremos claramente a qué me refiero. El listado 13 modifica el anterior, agregando grupos. Podemos ver entonces en la figura 2 cómo groupType nos muestra los grupos de administración, los que permiten reunir y dar permisos a usuarios, los que contienen servidores, etc. For Each el In _ Solid.Servers.ActiveDirectory.Environment.Groups ‘agrega un ítem en la lista Dim it As String = “G” & el.groupType With ListView1.Items.Add(el.name) Dim g As ListViewGroup = ListView1.Groups(it) If g Is Nothing Then g = ListView1.Groups.Add(it, it) End If .Group = g ‘recorre las propiedades de la clase Group ‘... Listado 13. Agrupando por groupType. <<dotNetManía Conclusión 44 Este es otro caso donde establecer algo de código nos permite personalizar funcionalidades y acceder a información de bajo nivel o de alta seguridad, en un marco controlado. A partir de aquí, se podrá agregar Figura 2. Tipos de grupos. métodos que permitan saber si un usuario pertenece o no a un grupo, quiénes son miembros de un grupo, de una unidad organizativa, etc. Un comentario final: es necesario ser muy detallista en esto de las pertenencias. Una unidad organizativa puede contener usuarios y grupos… grupos que a su vez pueden incluir usuarios de ésa o de otra unidad organizativa. Y un grupo puede contener subgrupos, que a su vez pueden contener subgrupos… Saludos cordiales. Isla VB Guillermo «Guille» Som Extender o no extender... Los métodos extensores en Visual Basic 2008 La versión de Visual Basic que se incluye con .NET Framework 3.5 o Visual Studio 2008 permite que creemos métodos que extiendan la funcionalidad de clases existentes sin necesidad de tener acceso al código fuente de éstas. En este artículo veremos cómo crear este tipo de métodos y qué consideraciones debemos tener en cuenta para usarlos de la forma más adecuada. ¿Qué es un método extensor? Guillermo Som ingresará los derechos de autor de este artículo en la cuenta de Ayuda a Juanma a vivir. Desde aquí, invita a los lectores de esta isla solidaria para que hagan sus aportaciones o participen en las subastas que se realizan desde la Web de Juanma para recaudar fondos con el fin de ayudar en la investigación de una cura para la enfermedad de Alexander. http://www.ayudajuanma.es. Los métodos extensores son métodos que podemos definir en nuestro proyecto para extender la funcionalidad de cualquier clase, ya sea de las que tenemos definidas en el propio proyecto o bien clases definidas en el propio .NET o por cualquier otro desarrollador. La ventaja es que esa definición de métodos no requiere que tengamos acceso al código fuente de la clase original, y es especialmente útil para aquellas clases que están “selladas”, es decir, de las que no podemos crear nuevas clases derivadas. Los métodos extensores La mayoría de las novedades incluidas en los lenguajes de .NET Framework 3.5, y particularmente todo lo relacionado con las expresiones de consulta (LINQ), es posible gracias a los métodos extensores (o métodos de extensión, que es como se traduce esta característica en la documentación de Visual Studio 2008), ya que mucha de esa nueva funcionalidad se implementa mediante métodos agregados a las clases e interfaces del propio .NET Framework, particularmente en extensiones agregadas a la interfaz IEnumerable(Of T). Pero, lo primero es lo primero, y es explicar qué es un método extensor. ¿Cómo definir un método extensor en Visual Basic? Para crear métodos de extensión en Visual Basic, tenemos que definir esos métodos en un módulo, ya que los métodos extensores deben estar siempre disponibles y no depender de ninguna instancia en particular. Además, tenemos que indicarle al compilador que el método en cuestión está extendiendo la funcionalidad de una clase; para ello tendremos que indicar qué clase queremos extender, y esa clase la indicaremos como el primer parámetro del método. Pero además también tenemos que indicarle al compilador que estamos ampliando la funcionalidad de dicha clase, y para ello tenemos que aplicar el atri- <<dotNetManía Guillermo “Guille” Som Es Microsoft MVP de Visual Basic desde 1997. Es redactor de dotNetManía, mentor de Solid Quality Mentors, orador de INETA Latam, y autor de los libros “Manual Imprescindible de Visual Basic .NET” y “Visual Basic 2005” y “Novedades de Visual Basic 9.0” y próximamente “Aprenda C# 3.0 desde 0.0 – Parte 3: Lo nuevo” . http://www.elguille.info. Isla solidaria 45 << dnm.isla.vb buto Extension a la definición del método extensor. El atributo Extension está definido en el espacio de nombres System.Runtime.CompilerServices. Para comprender mejor cómo definir un método extensor, veámoslo con un ejemplo. En el listado 1 tenemos un método llamado TrimMid que extiende la funcionalidad de la clase String añadiendo un nuevo método, que en este caso concreto elimina todos los caracteres “blancos” que tenga una cadena (incluso los que no están al principio o al final). Module Extensiones <Extension()> _ Public Function TrimMid(ByVal str As String) _ As String Dim q = From c In str _ Where Not Char.IsWhiteSpace(c) _ Select c Return q.ToArray End Function End Module Listado 1. Un método que extiende la funcionalidad de la clase String En el código del listado 1 estamos usando expresiones de consulta para hacer el trabajo de recuperar solo los caracteres que no son considerados como caracteres blancos, para lo que he usado la función IsWhiteSpace de la clase Char, y debido a que el resultado de esta expresión de consulta es una colección del tipo IEnumerable(Of Char), he tenido que usar el método extensor ToArray (definido por el propio .NET Framework) para convertir esa colección en un array de tipo Char, que como sabemos, el propio Visual Basic convierte en una cadena de caracteres, que es lo que finalmente se devuelve en esta función. <<dotNetManía Utilizar los métodos extensores 46 Para usar los métodos extensores no tenemos que hacer nada en especial, salvo indicar el método que queremos usar, pero esto es algo que siempre tendremos que hacer para usar un método cualquiera, sea propio de la clase o porque se haya definido como método extensor. Si estamos usando Visual Studio 2008 para escribir nuestro código, al mostrar los métodos extensores por medio de Intellisense, éstos se mostrarán con una flechita azul; de esta forma nos resultará fácil identificar cuáles son los métodos propios y cuáles los métodos de extensión. En la figura 1 vemos cómo se muestra el método extensor que tenemos definido en el listado 1. Figura 1. Intellisense muestra los métodos extensores con una flecha Como vemos en la figura 1, para usar el método extensor que hemos definido en el listado 1 solo tenemos que indicarlo en una variable (o constante) del tipo que estamos extendiendo, y la forma de usarlo es la habitual, es decir, que no tenemos que hacerlo de ninguna forma extraña. Otra cosa es que queramos usar ese método extensor como un método compartido normal y corriente. Si es esa la forma en que queremos usarlo, lo haremos indicando el nombre de la clase (módulo en nuestro caso) en el que está definido, pero como lo estamos usando como un método “normal”, y no de extensión, tal como vemos en el listado 2, tendremos que pasarle como argumento la cadena a la que queremos quitarle todos los espacios que tenga. res = Extensiones.TrimMid(s) Listado 2. Los métodos extensores se pueden usar como métodos de clase Pero debido a que ese método está definido en un módulo, Visual Basic también nos permitiría usarlo sin necesidad de indicar el nombre del módulo en el que está definido, ya que Visual Basic siempre hace una importación del módulo (tipo); por tanto, todos los métodos y demás elementos que contenga estarán siempre accesibles. Pero esto es un tema diferente, y si el lector quiere saber más sobre los módulos y cómo se comportan, puede leer el artículo publicado en esta misma sección del número 46 de dotNetManía. ¿Qué podemos extender? Ya hemos visto cómo crear y usar un método extensor, y también sabemos que podemos agregar nueva funcionalidad a cualquier tipo de datos, incluso los tipos por valor. Por ejemplo, podemos agregar << dnm.isla.vb nueva funcionalidad a los tipos enteros, etc. Pero para un buen uso de todos los métodos extensores que decidamos crear, debemos saber qué podemos extender y qué problemas (o inconvenientes) nos podemos encontrar al crear esas extensiones. Lo primero que debemos saber es que solo podemos crear extensiones en métodos, es decir, elementos Function o Sub. Lo habitual es que los métodos extensores siempre devuelvan algo, pero tal como Visual Basic funciona, es muy fácil crear un método extensor de tipo Sub (no devuelve un valor); pero en ese caso, tendremos que definir el parámetro del tipo a extender por referencia. Por ejemplo, si tenemos el código del listado 3, estamos agregando un método a la clase String que permite modificar la cadena a la que se aplica ese método de extensión, y por tanto, lo podremos usar tal como vemos en el listado 4. Pero esto no es lo habitual, además de que es mejor no modificar directamente el objeto al que se aplica el método por la sencilla razón de que si usamos una constante no hará nada, y por tanto, no tendrá ninguna utilidad. [ NOTA Comentar que solo Visual Basic permite crear métodos extensores que reciban el primer parámetro por referencia (el tipo a extender), ya que en C# no podemos definir ese primer parámetro usando los modificadores out o ref. Y aunque ese método lo podamos usar desde C# (agregando una referencia al proyecto de VB), esa extensión no aparecerá en la lista de métodos disponibles. ] Sobrecargas en los métodos extensores Ya sabemos que solo podemos extender métodos, la siguiente pregunta es: ¿podemos crear sobrecargas de métodos existentes? La respuesta es: sí. Incluso podemos definir métodos que tengan la misma firma que uno existente en la clase que queremos extender, aunque en este caso, simplemente se ignorará esa definición, ya que las sobrecargas definidas en las clases <Extension()> _ Public Sub TrimAll(ByRef str As String) str = str.TrimMid End Sub s.TrimAll() Listado 4. Los métodos extensores de tipo Sub deben aplicarse a la variable En cualquier caso, si es ésta la funcionalidad que queremos en nuestro método extensor, lo recomendable es definirlo como una función, que además de modificarla, devuelva el contenido de esa variable. De esa forma, el método servirá tanto para variables como para constantes. En el listado 5 vemos una modificación del método TrimAll para que haga lo que acabo de comentar. <Extension()> _ Public Function TrimAll(ByRef str As String) _ As String str = str.TrimMid Return str End Function Listado 5. Los métodos extensores admiten parámetros por referencia Las definiciones “nativas” del tipo de datos siempre tienen preferencia, y los métodos extensores solo se usarán si no existe una sobrecarga adecuada en el tipo que estamos extendiendo tienen preferencia sobre las extensiones que definamos. Y si eso ocurre, el compilador no nos avisará de ninguna forma de que esa extensión no se usará. Esto no hay que tomarlo con un error, ya que es conveniente saber que siempre tienen preferencia las definiciones “nativas” del tipo de datos, y que los métodos extensores solo se usarán si no existe una sobrecarga en el tipo que estamos extendiendo. Dicho esto, queda claro que podemos crear sobrecargas de métodos existentes en el tipo que queremos extender e incluso entre diferentes métodos extensores. <<dotNetManía Listado 3. Un método extensor que no devuelve un valor 47 << dnm.isla.vb Métodos extensores en tipos genéricos Los tipos de datos que indiquemos para un método extensor también pueden ser genéricos. Por ejemplo, si quisiéramos crear un método extensor para los tipos por valor (estructuras), podemos hacer algo como vemos en el listado 6. <Extension()> _ Public Function ToHex(Of T As Structure)( _ ByVal num As T) As String Return Microsoft.VisualBasic.Hex(num) End Function Listado 6. Los métodos extensores los podemos aplicar también a tipos genéricos Aunque no es necesario que hagamos ninguna restricción, en este ejemplo la he hecho para que quede claro que podemos restringir los tipos a los que queramos aplicar ese método. <<dotNetManía Distribuir un proyecto con métodos extensores 48 Los métodos extensores los podemos usar en proyectos en los que hayamos definido el módulo con los métodos; pero si queremos que otros programadores también puedan usarlos, debemos compilarlo en un ensamblado y distribuirlo. De esta forma pondremos a disposición de otros programadores los métodos de extensión que hemos definido, pero si queremos hacer esto, tenemos que tener en cuenta que los módulos tienen un ámbito predeterminado del tipo Friend, y por tanto solo estarán disponibles dentro del mismo proyecto en el que estén definidos. Sabiendo esto, debemos tener la precaución de definir el módulo con el modificador Public. Y para evitar conflictos de nombres, ese módulo debería estar en un espacio de nombres, aunque esto último no es necesario hacerlo expresamente, ya que al crear un proyecto de Visual Basic siempre se crea un espacio de nombres para dicho proyecto, pero es conveniente tenerlo en cuenta. Si nuestro ensamblado con los métodos extensores se usará desde C#, debemos tener en cuenta que ese lenguaje no permite usar métodos en los que haya parámetros opcionales. Por tanto, la forma de usar un método extensor que defina parámetros opcionales será diferente en Visual Basic que en C#. Por ejemplo, si tenemos el método definido en el listado 7, desde Visual Basic lo podemos usar de las dos formas mostradas en el listado 8. Sin embargo, en C# siempre tendremos que indicar el valor de ese parámetro opcional, y por tanto tendremos que usarlo tal como vemos en el listado 9. <Extension()> _ Public Function TrimOpcional( _ ByVal str As String, _ Optional ByVal quitarCifras As _ Boolean = False) As String Dim sb As New StringBuilder For Each c In str If Char.IsWhiteSpace(c) _ Then Continue For If quitarCifras AndAlso Char.IsNumber(c) _ Then Continue For sb.Append(c) Next Return sb.ToString End Function Listado 7. Definición de un método extensor con parámetros opcionales s = “ Prueba con cifras 123 y letras” res = s.TrimOpcional Console.WriteLine(res) Console.WriteLine() res = s.TrimOpcional(True) Console.WriteLine(res) Listado 8. En Visual Basic podemos usar los métodos extensores con parámetros opcionales de la forma habitual s = “ Prueba con cifras 123 y letras”; // En C# hay que indicar siempre los parámetros opcionales res = s.TrimOpcional(false); Console.WriteLine(res); Console.WriteLine(); res = s.TrimOpcional(true); Console.WriteLine(res); Listado 9. En C# siempre tenemos que indicar el parámetro opcional ¿Cuándo usar los métodos extensores? Ésta seguramente es una pregunta que algunos se harán para decidir si tienen que usar los métodos << dnm.isla.vb extensores o buscar otra forma de conseguir lo misgo fuente de esos tipos que queremos extender. En la mo. La respuesta, como siempre, dependerá de lo que Web de la revista puede descargar el código de ejemnosotros decidamos. plo, en el que también se incluye un proyecto de C# Si somos los autores del tipo de datos que queremos para que pueda probar todo lo comentado. Y como extender, nos tendremos que plantear si ese método es en esta isla también llega el verano, nos tomamos un necesario en la mayoría de ocasiones que se utilice el tipo pequeño descanso, pero en septiembre volveremos de datos. Si la respuesta es no, ya que es posible que sólo con más cosas interesantes sobre Visual Basic. lo necesitemos en contadas ocasiones, es obvio que la ¡Feliz verano! mejor opción es crear un método extensor. Otra razón para que nos decantemos por el método extensor en TODAS LAS lugar de modificar la definición del NOVEDADES DE tipo de datos es para mantener la VISUAL BASIC 9.0 misma versión de ese tipo, ya que si AL DETALLE modificamos los métodos expuestos, lo lógico es pensar que estamos creando una nueva versión, y si ese tipo INCLUSO LO QUE de datos lo tenemos compilado en OTROS NO TE un ensamblado, deberíamos increHAN CONTADO mentar la versión de dicho ensamNUNCA blado, y esto es posible que no nos interese hacerlo. También debemos tener en cuenY TODO DE UNA ta que los métodos definidos en el FORMA “CASI” propio tipo siempre tienen prefeFÁCIL DE rencia sobre los definidos como ENTENDER métodos extensores. Por tanto, si queremos ofrecer esa funcionalidad y no dejar que sea el usuario que utiliza nuestro tipo el que defina un método con ese nombre, la opción más efectiva es definirlo en el propio tipo. Por otro lado, si no tenemos acceso al código de ese tipo que queremos extender, solo nos queda la opción de definirlo como un método extensor. Pero como he comentado antes, la decisión final la tenemos que tomar nosotros, y esa decisión la tenEL PRIMER E-BOOK EN CASTELLANO EDITADO POR dremos que tomar evaluando cual será la opción que mejor se adapta a SOLID QUALITYTM PRESS SOBRE VISUAL BASIC 9.0 nuestras necesidades. Conclusiones En este artículo hemos visto cómo utilizar los métodos extensores, de forma que podamos agregar nueva funcionalidad a las clases existentes sin necesidad de tener acceso al códi- COMO EL MISMO TÍTULO SUGIERE: "NOVEDADES DE VISUAL BASIC 9.0", ESTE LIBRO CONTIENE TODA LA INFORMACIÓN SOBRE LA NUEVA VERSIÓN DEL COMPILADOR DE VISUAL BASIC QUE SE INCLUYE EN VISUAL STUDIO 2008. http://www.solidq.com/ib/eBookDetail.aspx?Id=1 todonet@qa [email protected] Dino Esposito Arquitecto en IDesign, Dino Esposito es una de las autoridades mundiales reconocidas en tecnologías Web y arquitectura de software. Sus libros más recientes son "Programming ASP.NET 3.5-Core Reference" e "Introducing Microsoft ASP.NET AJAX" (Microsoft Press). Es ponente regular en eventos de la industria de ámbito mundial, como TechEd o DevConnections, y europeos, como DevWeek y Basta. Plantillas ASP.NET e inferencia de tipos en C# Abordamos este mes un examen en profundidad de las propiedades de las plantillas de ASP.NET, y concluiremos explicando los pros y contras del uso de la nueva palabra reservada var en C#. Soy suscriptor de dotNetManía a través de la empresa, y he leído en el número 44, pág. 52, un artículo tuyo sobre cómo cargar en tiempo de ejecución el ContentTemplate de un control UpdatePanel. Es muy interesante, y quiero hacer algo similar con los ItemTemplate de un ListView, pero me encuentro con una duda. En tiempo de ejecución, voy creando los literales y los controles que necesito para hacer container.Controls.Add, y funciona bien, pero mi intención es poder tener plantillas guardadas en la base de datos para que el usuario en tiempo de ejecución seleccione la que quiera. Entonces no sé cómo puedo "traducir" un trozo de código que contenga etiquetas HTML del tipo <TR>, pero que también incluya etiquetas ASP.NET del tipo <asp:label> para poderlo cargar de una forma directa en una plantilla. ¿Tienes algún ejemplo al respecto? Me da la impresión de que te has propuesto construir la perfecta interfaz Web que resulte totalmente configurable. Si es así, resulta un reto más que interesante. Tu pregunta puede desdoblarse en dos. Una es cómo añadir en la práctica algún contenido a la propiedad ItemTemplate de un control ListView. La otra es cómo transformar un texto leído de una base de datos en una colección de controles ASP.NET que puedan ser añadidos a la plantilla de un control enlazado a datos. Vamos a responder primero a estos dos aspectos, y después añadiré alguna recomendación sobre cómo construir la aplicación ASP.NET “perfecta”, o sea, totalmente contenida en una base de datos. La propiedad ItemTemplate, al igual que cualquier otra propiedad de las plantillas de los controles ASP.NET, se define mediante la interfaz ITemplate. ITemplate se define de la siguiente forma: public interface ITemplate { void InstantiateIn(Control container); } Casi siempre, las propiedades de las plantillas se establecen de forma declarativa mediante código de marcas ASP.NET, ya sea de forma manual, o mediante código autogenerado por algún diseñador de Visual Studio. Y establecer una propiedad de plantilla de forma manual es interesante muchas veces y más sencillo de lo que se piensa. Basta con disponer de un objeto que exponga la interfaz ITemplate. También se puede crear un tipo personalizado y hacer que implemente dicha interfaz. Supongamos que ese tipo se llamase MyTemplateFromDb . El siguiente código muestra cómo usarlo en código real: Lo que sucede cuando el control ListView utiliza la plantilla depende esencialmente de la implementación del método InstantiateIn Internamente, cuando el control ListView necesita el contenido de la plantilla, llama al método InstantiateIn del objeto ITemplate que le hemos suministrado. Y este comportamiento no es específico del control ListView ; es típico de cualquier control ASP.NET que soporte plantillas con propiedades. De forma que lo que sucede cuando el control ListView utiliza la plantilla depende esencialmente de la implementación del método InstantiateIn. ¿Cómo podría ser una implementación de este tipo en una clase MyTemplateFromDb? Si deseamos cargar código de marcas a partir de una base de datos, ejecutamos una consulta sobre la tabla apropiada y asociamos la información leída a una variable de tipo string, como en el código siguiente: public class MyTemplateFromDb : ITemplate { public void InstantiateIn(Control container) { string markup = ReadFromDb(...); // ... } // ... } El siguiente problema es encontrar una forma de transformar el código de marcas en una colección de controles. Sin más rodeos, necesitas un parser de ASPX. ¿Construimos uno o nos compramos alguno de la oferta existente? Afortunadamente, ASP.NET viene con un método no muy conocido que invoca al parser propio de ASPX. En particular, se puede sustituir el parser estándar por uno personalizado modificando una zona del fichero Web.config. El método al que me refiero averigua cuál es el parser adecuado para la página activa y le utiliza para llevar a cabo la operación. El método es ParseControl y se define en la clase TemplateControl, que a su vez hereda de Control y es el antecesor jerárquico de la clase Page. Este método se define de la siguiente forma: public Control ParseControl(string content); Este método acepta una cadena de marcado ASP.NET y la analiza para producir un objeto Control. Este objeto puede entonces añadirse a cualquier formulario Web, control de usuario o propiedad Template. Si el código de marcado contiene más de un control, se devuelve un grafo cuya raíz es el objeto padre y podemos averiguar cuántos controles individuales posee mediante el siguiente código: Control root = this.ParseControl(markup); int numOfControls = root.Controls.Count; En este punto, en el cuerpo del método InstantiateIn añadimos simplemente este grafo de controles al contenedor suministrado, tal y como se muestra aquí: public class MyTemplateFromDb : ITemplate { public void InstantiateIn(Control container) { string markup = ReadFromDb(...); Control root = this.ParseControl(markup); container.Controls.Add(root); // ... } // ... } En ASP.NET, existen dos sobrecargas del método ParseControl. La segunda sobrecarga tiene la siguiente definición: public Control ParseControl(string content, bool ignoreParserFilter); El segundo parámetro booleano indica si el parser debe tener en cuenta cualquier filtro indicado para establecer qué etiquetas se ignoran (este es otro aspecto de ASP.NET sutilmente configurable). Tal y como hemos dicho, el método ParseControl emplea el parser activo de ASP.NET. Así que, cuando el mecanismo se activa, el proceso es exactamente igual al proceso predeterminado directamente por ASP.NET. Esto significa, por ejemplo, que bloques consecutivos de literales HTML son asociados al mismo control. <<dotNetManía MyTemplateFromDb template = new MyTemplateFromDb(...); ListView1.ItemTemplate = template; [email protected] [email protected] << dnm.todonet@qa 51 <<dotNetManía T o d o t N e t . q a @ d o t n e t m a n i a . c o m T o d o t N e t . q a @ d o t n e t m a n i a . c o m << dnm.todonet@qa 52 Otro enfoque, quizás más sencillo, supone el uso del método LoadTemplate del control TemplateControl. Este método toma una URL de un control de usuario como entrada y devuelve un objeto creado dinámicamente que contiene el control de usuario más la implementación de ITemplate. El tipo real de ese objeto devuelto es SimpleTemplate . Para usarlo, sin embargo, se necesita tener un UserControl, o sea que la cuestión aquí es cómo obtener un control desde una base de datos. Hay dos formas. Una supone que se cree un control de usuario con toda la interfaz de usuario necesaria y se almacene la URL del control en la base de datos. La otra supone leer el código de marcado de la base de datos y crear un fichero temporal con la extensión ASCX para cargarlo en la plantilla del control ListView. Sin embargo, crear ficheros temporales puede ser problemático en ASP.NET, más que por problemas de codificación por aspectos relacionados con la seguridad. Y para concluir con la respuesta a esta pregunta, permíteme echar un breve vistazo a una tecnología ASP.NET que puede utilizarse para almacenar un sitio Web entero en una base de datos. Se basa en unos componentes especiales conocidos como proveedores virtuales de rutas (virtual path providers), y se trata de una clase que suministra un conjunto de métodos para habilitar la posibilidad de que una aplicación Web recupere sus recursos de un sistema virtual de ficheros. Con este sistema se puede almacenar esos datos donde se desee, incluyendo por supuesto una tabla de base de datos. DbPathProvider provider = new DbPathProvider(); HostingEnvironment. RegisterVirtualPathProvider(provider); El código precedente muestra cómo registrar un proveedor personalizado en una aplicación ASP.NET. Este código debería ejecutarse cuando se lanza la aplicación. ASP.NET interroga al proveedor virtual registrado y lee el contenido indicado por éste. Se puede crear un proveedor personalizado que recupere el contenido de cada página lógica ASPX a partir de cualquiera de los almacenes de datos soportados, incluyendo la tabla de la base de datos que nos ocupa. Para más información sobre los proveedores virtuales de rutas, visita la página: http://msdn.microsoft.com/ en-us/library/system.web.hosting. virtualpathprovider.aspx. En mi empresa estamos discutiendo acerca de la utilización de la nueva palabra reservada var, introducida con LINQ, y nos gustaría saber si se debería usar también en otras situaciones. Esto es, ¿si se utiliza en contextos diferentes de las consultas LINQ, afectaría a la legibilidad, el rendimiento u otros aspectos del sistema? La palabra reservada var en C# 3.0 tiene que ver con la inferencia de tipos, pero no con LINQ como mecanismo de consultas. Simplemente, o el desarrollador es demasiado perezoso para declarar el tipo exacto de objeto que está definiendo, o no lo conoce en absoluto, de modo que le indica al compilador que utilice el tipo determinado por la expresión de inicialización de la sentencia. Puede que el desarrollador realmente no conozca el tipo que devuelve esa expresión. ¿Cómo puede ser que no conozcamos el tipo de variable que queremos usar? Solo hay una posibilidad razonable: que se estén manejando tipos anónimos. Un tipo anónimo es un tipo sin nombre que se define en C# al utilizar inicializadores, como por ejemplo en: var person = new { FirstName="Nancy", LastName="Davolio", Age=28 }; Para el CLR, los tipos anónimos y no anónimos son exactamente lo mismo. Los tipos anónimos se pueden utilizar en escenarios muy variados, pero se introduje- ron principalmente para el soporte de las consultas integradas de LINQ. De forma que aquí está el “quid” de la cuestión. La palabra reservada var se usa principalmente para recoger los resultados de consultas LINQ. var data = from c in db.Customers select new {c.CompanyName, c.ContactName}; En C# 3.0, var no indica una referencia tardía (late binding), ya que se resuelve estáticamente. Debido a esto, se requiere siempre una expresión de asignación en la sentencia para evitar un error del compilador. De forma que, al usarla, siempre se obtiene un elemento fuertemente tipado. El compilador realiza todo el trabajo, así que no hay sobrecarga extra alguna en tiempo de ejecución. En general, la utilización de la palabra reservada var con tipos no anónimos es posible, pero no recomendable. Sin dudas, permite teclear menos código. Pero, ¿cuánto se gana en productividad al evitar escribir un nombre de tipo? A mí me parece una cuestión de pereza más que de rapidez. Traducido al castellano por Marino Posadas …We make sure your application rocks! Advantage Database Server es un sistema de base de datos cliente/servidor de alto rendimiento y totalmente equipada, especialmente diseñado para dar respuesta a las necesidades de los desarrolladores de aplicaciones • Proporciona tanto acceso a tablas de datos ISAM como SQL • Acceso nativo a archivos dbf a través de Cliente/Servidor, sin necesidad de importar datos. • Multi Plataforma (Windows, Linux, Netware) • Bajo Coste Total de Propiedad: fácil instalación, administración cero, Requisitos mínimos de hardware. Mejoras y nuevas Funcionalidades en la version 9: • Mejoras en el soporte de FoxPro: Advantage 9 soporta la versión de Visual FoxPro 9. • SQL Debugger ha sido añadido a la versión 9 de ADS Architect. • Notificaciones de Eventos. • 64-bit en servidores Windows y Linux: Advantage ha sido adaptado para funcionar como aplicación nativa de 64-bit en las versiones de x64 de Windows y Linux. www.Abox.com A que espera! Consiga ya 2 usuarios gratuitos (solo para desarrollo) enviando un Email a [email protected] C/ Manso, 26-28, 2ª planta 08015 Barcelona Teléfono: 93 426 22 57 E-mail: [email protected] Laboratorio.net Octavio Hernández Aspose.Total for .NET Este mes presentamos Aspose.Total for .NET, una potente suite de componentes reutilizables creados y comercializados por la empresa australiana Aspose, que pueden ser adquiridos conjuntamente o por separado para ser incorporados a todo tipo de aplicaciones .NET. Ficha técnica Nombre: Aspose.Total for .NET Versión: 1.4 Fabricante: Aspose Sitio Web: http://www.aspose.com Categoría: Componentes reutilizables Precio: • Suscripción a suite completa: 1.999 USD • Paquetes individuales: desde 249 USD • Descuentos por compra de múltiples productos y licencias. • Todas las compras incluyen actualizaciones y parches, más soporte técnico gratuito durante un año. Octavio Hernández es Mentoring Team Leader de Plain Concepts, editor técnico de dotNetManía y tutor de campusMVP. Es MVP de C# desde 2004, MCSD y MCT. Como podrá confirmar el lector al consultar la tabla 1, Aspose.Total for .NET va más allá de lo que ofrecen otras suites de similares propósitos disponibles en el mercado, incluyendo no solo los clásicos controles destinados a potenciar la interfaz de usuarios de nuestras aplicaciones (rejilla, gráficos comerciales, etc.), sino además toda una serie de componentes utilitarios para llevar a cabo de una manera cómoda y eficiente diferentes tareas que se presentan con bastante frecuencia durante el desarrollo de aplicaciones. Es de destacar que la empresa ofrece también una versión paralela en Java de la suite, Aspose.Total for Java, hecho que puede ser muy interesante para las empresas que desarrollen tanto para .NET como para la plataforma Java. Componentes para formatos de ficheros Uno de los principales grupos de componentes que incorpora Aspose.Total es el de los componentes que permiten el tratamiento de diferentes formatos de ficheros muy comunes en la informática de hoy, como son todo tipo de documentos de la suite Office (Word, Excel, PowerPoint) u otros como Adobe PDF o Adobe Flash. Se trata de clases que han sido desarrolladas en C# al 100% y no dependen de manera alguna de la disponibilidad en el equipo de destino de ningún prerrequisito, lo que se traduce en una máxima economía y facilidad de despliegue, además de un excelente rendimiento. La amplitud y naturalidad de los modelos de objetos de documento (DOM) que los diferentes componentes ofrecen los hacen ideales para todo tipo de tareas de automatización. En lo relativo a los formatos de Office, cabe destacar el soporte completo para Open XML, ya un estándar internacional. Componentes visuales Por supuesto, no podía faltar en una suite como ésta un conjunto de controles destinados a potenciar las interfaces de usuario de las aplicaciones Windows y ASP.NET. Además de las tradicionales rejillas y visores de gráficos comerciales, cabe destacar en esta categoría un potente editor de textos (tanto para Windows como para la Web) que pone a disposición de sus usuarios muchas de las posibilidades de Word, y un completo control de código de barras (figura 1). Componentes utilitarios Por último, la otra categoría en la que se puede agrupar a varios de los componentes que integran Aspo- << dnm.laboratorio.net se.Total es la de utilitarios. Se trata de componentes no visuales que facilitan la implementación de diversas tareas, que van desde la programación de aplicaciones conectadas a la comprobación ortográfica. Puede ver un resumen de lo que hacen esos componentes en la tabla 1. Un pequeño ejemplo Difícilmente pueda ofrecer algo novedoso para el lector versado en el desarrollo .NET un ejemplo básico en el que se muestre cómo utilizar una librería de clases. Por Librerías que componen Aspose.Total for .NET Componentes para formatos de ficheros Aspose.Words Permite leer, crear y modificar documentos de Word sin utilizar Microsoft Word. Ofrece soporte completo para todas las funcionalidades que ofrece Word, y para el tratamiento de documentos en los formatos DOC, DOCX, RTF, HTML y TXT. Aspose.Cells Permite leer, crear y modificar documentos de Excel sin utilizar Microsoft Excel. Ofrece soporte completo para todas las funcionalidades que ofrece Excel, y para el tratamiento de documentos en los formatos XLS y XLSX, además de la importación y exportación a otros diversos formatos. Aspose.Slides Permite leer, crear y modificar documentos de PowerPoint sin utilizar Microsoft PowerPoint. Ofrece soporte completo para todas las funcionalidades que ofrece PowerPoint, y para el tratamiento de documentos en los formatos PPT y PPTX. Aspose.Pdf Permite a las aplicaciones .NET generar documentos PDF (tanto mediante código como a partir de plantillas XML y ficheros XSL-FO) sin utilizar Adobe Acrobat. Incluye soporte para numerosas características avanzadas, como compresión, utilización de tablas, gráficos, imágenes, hiperenlaces o fuentes personalizadas. Aspose.Pdf.Kit Permite a las aplicaciones .NET gestionar y actualizar documentos PDF sin utilizar Adobe Acrobat. Orientado a tareas de tratamiento de información, como la combinación de datos en documentos existentes y la gestión de formularios embebidos en ficheros PDF. Aspose.Tasks Permite a las aplicaciones .NET generar y manipular documentos de Project (MPX, MPP, MPD y XML) sin utilizar Microsoft Project, ofreciendo un amplio conjunto de funcionalidades relacionadas con la gestión de especificaciones de proyectos. Aspose.Flash Permite generar y manipular dinámicamente documentos de Flash desde las aplicaciones .NET, una posibilidad muy interesante de cara al desarrollo de sitios Web impactantes. Aspose.Form Ofrece un conjunto de controles Web que permiten trabajar con plantillas de InfoPath a través de un navegador. Aspose.Grid Conjunto de dos potentes componentes de rejilla, uno para aplicaciones Windows y otro para aplicaciones Web, que ofrecen potentes API para dar un control total sobre la apariencia y comportamiento de las rejillas. Aspose.Chart Componente que hace posible la incorporación de gráficos comerciales y científicos a las aplicaciones .NET. Soporta 21 tipos de gráficos diferentes, así como innumerables variaciones de los mismos, y diversos efectos avanzados como la renderización 3D, transparencias, gradientes o dibujo personalizado. Aspose.Editor Control que posibilita la edición de documentos DOC, RTF y HTML dentro de las aplicaciones Windows Forms y ASP.NET. Nos permite visualizar, editar e imprimir documentos de manera muy similar a Microsoft Word, pero desde nuestra aplicación y de manera autónoma. Aspose.BarCode Componentes robustos y fiables que permiten de una manera sencilla la incorporación de funcionalidad relacionada con códigos de barras en las aplicaciones .NET. Soporta las principales especificaciones y estándares del mercado, y permite la exportación a múltiples formatos de imagen. Aspose.AdHoc Generador de consultas SQL para aplicaciones ASP.NET, potente y fácil de usar, que puede ser utilizado para la generación directa de informes o la implementación de pantallas de búsqueda. <<dotNetManía Componentes visuales 55 << dnm.laboratorio.net Librerías que componen Aspose.Total for .NET Componentes utilitarios Aspose.Network Paquete de componentes .NET flexibles y fáciles de usar para la programación de todo tipo de aplicaciones de comunicaciones. Incluye no solo implementaciones de la gran mayoría de los protocolos de red actualmente en uso, sino también numerosas clases auxiliares que simplifican el desarrollo. Excelente complemento para las clases del espacio System.Net de .NET. Aspose.Workflow Componente que ofrece un potente motor de flujos de trabajo, conjuntamente con un conjunto de objetos de flujo construidos alrededor del estándar WFMC. Aspose.iCalendar Librería .NET que ofrece numerosas clases y algoritmos para la generación de patrones temporales de recurrencia y la planificación de tareas, cuya implementación es coherente con la especificación iCalendar (RFC 2445). Aspose.Spell Componente para la verificación ortográfica en más de 20 idiomas. Soporta diccionarios personalizados y puede ser utilizado tanto en aplicaciones para Windows como para la Web. Aspose.ASPXpand Componente para aplicaciones ASP.NET que ofrece implementaciones de más de 60 funciones comunes en las aplicaciones Windows pero difíciles de programar en aplicaciones Web: asignación de foco, edición con máscaras, completamiento automático, gestión de la tecla Intro, entre otras. Tabla 1 lo tanto, nos limitaremos aquí a presentar la apariencia del Cuadro de herramientas de Visual Studio 2008 después de instalar uno de los paquetes integrantes de la suite, en este caso el de códigos de barras (figura 1), y a mostrar un fragmento de código que utiliza el componente Aspose.Words (listado 1), para que el lector pueda hacerse una idea del modelo de programación que la librería ofrece. El sitio Web del fabricante ofrece mucha más información general, ejemplos de código y de documentación, además de la posibilidad de descargar versiones de evaluación de 30 días. using System; using System.Windows.Forms; using Aspose.Words; // espacio de nombres de la librería namespace WinApp4 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { // abrir documento Document doc = new Document(@”D:\DNM\49\Lab49_Aspose.docx”); // clase que encapsula los métodos // de manipulación de documentos Word DocumentBuilder builder = new DocumentBuilder(doc); // establecer formato builder.Font.Color = System.Drawing.Color.Blue; builder.Font.Underline = Underline.Single; // localizar un marcador builder.MoveToBookmark(“FIRMA”); // insertar hiperenlace builder.InsertHyperlink(“Octavio Hernandez”, “http://geeks.ms/blogs/ohernandez/”, false); // guardar documento modificado doc.Save(@”D:\DNM\49\Lab49_Aspose_Firmado.docx”); } } } Listado 1. Programa que procesa el documento de Word que contiene este artículo mediante Aspose.Words <<dotNetManía Conclusiones 56 Figura 1. Componentes de Aspose.BarCode Aspose.Total for .NET ofrece un amplio surtido de excelentes componentes, que permiten potenciar de múltiples formas el desarrollo de nuestras aplicaciones. Su adquisición, conjuntamente o de manera independiente, constituye indudablemente una buena inversión, que se amortizará casi inmediatamente. biblioteca.net Programming Microsoft LINQ Paolo Pialorsi y Marco Russo Editorial: Microsoft Press Páginas: 660 Publicado: mayo de 2008 ISBN: 978-0735624009 Idioma: inglés Aunque no muy conocidos previamente como autores, Pialorsi y Russo (consultores, formadores y fundadores de www.DevLeap.com) han obtenido con esta obra el reconocimiento internacional y una excelente aceptación por parte de los lectores, si bien ya se habían estrenado con alguna obra anterior centrada en XML y los servicios Web. La atención al material incluido, el esmero en el detalle, la selección cuidadosa de los contenidos y su interés para los lectores, los ejemplos (que funcionan, y realmente sirven de explicación a los contenidos del texto), hacen del texto un material más que recomendable. A eso hay que unir los nuevos diseños editoriales de Microsoft Press: más concisos y organizados, con mejor tipografía y organización del material expuesto y una edición más moderna. Todo ello se enmarca en la fase de renovación que se ha impuesto la editorial y que, probablemente, el lector asiduo de MSDN Magazine ya ha podido comprobar en el último número de esa revista. Professional C# 2008 Christian Nagel, Bill Evjen, Jay Glynn, Morgan Skinner y Karli Watson Editorial: Wrox Press Páginas: 1.782 Publicado: marzo de 2008 ISBN: 978-0470191378 Idioma: inglés Nagel y compañía atacan de nuevo. Y muy bien. Se trata de una obra de consulta y referencia. Todos los autores, excepto Evjen, ya son viejos conocidos, y varios de ellos lo han sido de las primeras ediciones de esta obra para versiones previas del lenguaje, así como habituales de la editorial. Y esa experiencia en el lenguaje y en el oficio de escribir se aprecia en esta obra que cubre “todo lo que uno pueda necesitar hacer con el lenguaje C#”, según uno de sus lectores. No afirmaré yo tanto, pero lo cierto es que una larguísima parte de lo que es posible se encuentra aquí, debidamente organizado por contextos de trabajo y utilización. novedades Es una obra un tanto monumental, sin duda exhaustiva (la más extensa publicada hasta ahora sobre el tema; baste indicar que el número de capítulos es de 48, y todos con bastante contenido), y que consigue lo que pretende: que el lector la vea inmediatamente como la referencia a consultar cuando se plantea la pregunta típica: ¿y cómo se haría en C# 3.0…? Se trata, probablemente, de lo más completo publicado hasta la fecha sobre este lenguaje (y nada cara, considerando lo anterior). Silverlight 2.0 Bible Brad Dayley. Editorial: Wiley. Páginas: 552. ISBN: 978-0470375006. Fecha de publicación: octubre de 2008. Idioma: inglés. Pro Silverlight 2 in C# 2008 Matthew MacDonald. Editorial: APress. Páginas: 400. ISBN: 978-1590599495. Fecha de publicación: octubre de 2008. Idioma: inglés. TEXTO: MARINO POSADAS desván Marino Posadas <<dotNetManía Tiempo de cambios en Microsoft 58 El verano invita a la reflexión. Para la compañía de Redmond, además, el inicio del verano es también el inicio de un nuevo período económico, que este año está marcado inexorablemente por la retirada del CEO y alma mater de la compañía, William Henry Gates III (el primero de la fila inferior de la foto, en 1978, el año de su fundación). Gates, atenderá un día a la semana asuntos relacionados con la empresa, dedicando la mayor parte de su tiempo a la Fundación Bill y Melinda Gates, cuyas principales actividades son la mejora de las condiciones de salud en zonas desfavorecidas (como Mozambique, donde trabaja el doctor español Pedro Alonso, en campañas de lucha contra la malaria y otras enfermedades), y la expansión de las oportunidades educativas y el acceso a las tecnologías de la información. Si, como dice el sabio, “se conoce el corazón del hombre por lo que hace, y su sabiduría, por lo que dice”, Gates ha hecho mucho, quizá más que nadie, por cambiar el panorama de lo que hoy día es la informática y el acceso del gran público a este valioso recurso. Y ha sabido crear un imperio alrededor de esa idea. También ha dicho y anticipado mucho sobre lo que tendría que ser la informática del futuro, comenzando por su obra “The Road Ahead”, donde ya se refería como PC monedero a lo que hoy conocemos como PDA, subrayando la importancia de la informática móvil, y donde se hablaba de interconectividad, librerías de software y muchas cosas que forman parte de la computación de hoy. Sin embargo, los comienzos fueron complicados. La aparición del primer ordenador personal que podría recibir tal nombre (el Altair 8800) dio la oportunidad a Gates y Paul Allen de introducirse en el mercado. Gates les llamó para decirles que tenían una versión del lenguaje BASIC para su nueva máquina (falso, ni siquiera tenían la máquina). Allen consiguió crear un simulador del Altair que funcionaba en el PDP-10 de Digital disponible en su escuela, mientras Gates se centraba en el código del intérprete de BASIC. Ocho semanas más tarde, Allen introducía el código por primera vez en un Altair real. Si cualquier parte del código (del programa o del simulador) hubiera fallado, todo se habría ido al traste. Pero no fue así. El programa funcionó perfectamente la primera vez y se llamaba 4k BASIC en referencia a la memoria necesaria para su ejecución. A esto le siguió un contrato con los creadores de Altair (MITS). Un año más tarde, Gates se salía de la Universidad de Harvard y fundaba Microsoft. El reto que deja a sus sucesores es grande. Como decía Juan Luis Cebrián (exdirector del diario “El País” y académico) en su obra “La red”: “será necesario invertir de forma continuada, y hasta terca, en la formación de los ciudadanos acerca no solo de la utilización de las nuevas tecnologías, sino en las consecuencias de su implantación”. noticias.noticias.noticias documentos en la red Warning: This Secret CSS Technique Will Surprise You! Se trata de un artículo de Alex Walker que explica cómo conseguir mediante técnicas puras de Hojas de Estilo en Cascada efectos de animación a partir de imágenes estáticas secuenciales. Se trata nuevamente de una aportación interesante de este sitio (SitePoint), disponible en http://www.sitepoint.com/article/css-animation-technique. “Regular Expressions: Now You Have Two Problems” es una interesante reflexión para programadores sobre las ventajas –y también alguna desventaja– de la utilización de expresiones regulares. Jeff Atwood (Coding Horror) es el autor de este artículo disponible en su sitio: http://www.codinghorror.com/blog/archives/001016.html, donde el lector encontrará seguramente otros materiales de interés. sitios del mes Pixel Girl es un sitio dedicado a ofrecer archivos (iconos, fondos de pantalla, etc.), artículos y tutoriales sobre cómo mejorar la experiencia visual del usuario de una plataforma o programa mediante el uso de efectos atractivos e iconografía adecuada. Todo ello original de la autora, cuya Web ha sido incluida como una de las 50 mejores del año 2008, que premia anualmente la revista Time. (http://www.pixelgirlpresents.com). COLOURlovers. Otro sitio recomendado que parece más util que nunca con las necesidades de diseño de aplicaciones que se dan hoy en día es COLOURlovers, donde podemos encontrar todo lo que necesitemos a la hora de escoger un tema de color para un sitio Web, una aplicación impactante o un juego. De especial utilidad para webmasters innovadores (http://www.colourlovers.com). utilidades del mes Installed Codecs V 1.02 es una pequeña utilidad gratuita que permite comprobar cuáles son (y de qué versión) los códec de audio y vídeo instalados en nuestro sistema, así como los filtros DirectShow activos. Se encuentra disponible en http://nirsoft.net/utils/ installed_codec.html. Varun Kashyap, de www.ma keuseof.com, propone un conjunto de herramientas gratuitas alternativas a la suite de creación de contenidos de Adobe. Desde programas de creación de documentos PDF o contenidos gráficos, hasta editores de sonido. Para descargas y explicación de cada una, visitar http://www.makeuseof.com/tag/say-goodbye-to-adobecreative-suite.