Page 1

nº33 Enero 2007 • 6,50 € (España)

Visual Basic • C# • ASP.NET • ADO.NET • .NET Framework • Windows Server System

dotNetManía www.dotnetmania.com

Dedicada a los profesionales de la plataforma .NET

C++/CLI: un nuevo enfoque al desarrollo en C++ para .NET• Trabajo con DataSet y ReportViewer • Parámetros personalizados en los eventos • Una mirada a WPF/E

TodotNet QA Mi meta es el rendimiento Laboratorio Ribbon.NET, PowUpload y PowerWEB Zoom for ASP.NET

Entrevista David Chappell Principal de Chappell & Associates

Comunidad BcN DEV .NET developers community of Barcelona Opinión Planificación de la calidad


dnm.editorial

dotNetManía Dedicada a los profesionales de la plataforma .NET Vol. III •Número 33 • Enero 2007 Precio: 6,50€

...y van 3

Redactor Jefe Marino Posadas (marino.posadas@dotnetmania.com) Editor técnico Octavio Hernández (octavio@dotnetmania.com) Consejo de Redacción Dino Esposito, Guillermo 'Guille' Som, José Manuel Alarcón, Lorenzo Ponte, Luis Miguel Blanco y Miguel Katrib (Grupo Weboo). Colaboradores habituales Antonio Quirós, Braulio Díez, Carlos Quintero, Eladio Rincón, Javier Aragonés, Jorge Serrano, José Miguel Torres, Iván González, Pepe Hevia, Salvador Ramos y Sergio Vázquez Además colaboran en este número Carlos Salazar, José Luis Latorre, José Luis Quintero, Rafael Ontivero “RFOG” y Yamil Hernández Atención al suscriptor Pilar Pérez (pilar.perez@dotnetmania.com) Ilustraciones Yamil Hernández

Edición, suscripciones y publicidad

.netalia c/ Robledal, 135 28529 Rivas-Vaciamadrid (Madrid) www.dotnetmania.com

Tf. (34) 91 666 74 77 Fax (34) 91 499 13 64 Imprime GRUPO MARTE ISSN 1698-5451 Depósito Legal M-3.075-2004

>>

<<

Bienvenido al número 33, de enero de 2007, de dotNetManía. Con el presente número cerramos nuestro tercer volumen, nuestro tercer año aportando documentación mensualmente a los desarrolladores de la plataforma .NET. A lo mejor no ha sido fácil, pero desde luego ha sido un auténtico placer. Gracias, amable lector, por confiar en nosotros. Este mes también publicamos nuestro quinto cuaderno técnico “Optimización de ASP.NET 2.0” de Braulio Díez y Reyes García, gratuito para los lectores que estén suscritos. De los cinco, tres los hemos podido regalar con la suscripción, aunque no por esto valen menos. Como puede ver, no es un regalo ni de Navidad ni por nuestro tercer aniversario, sino un esfuerzo continuado para darle el mayor valor a su suscripción. El mérito no es solo nuestro; tenemos que agradecer el indispensable apoyo de MSDN España, que patrocina la edición que tiene en sus manos, así como a los autores por su esfuerzo. En cuanto a los contenidos de este mes, le recomiendo la entrevista que Carlos Salazar, de Raona, al que doy la bienvenida por su primera colaboración, realizó a David Chappell a su paso por Madrid. También se estrena José Luis Quintero (www.elquintero.net) quien lo hace con el artículo “Una mirada a WPF/E”, precisamente en el mismo mes que ha aparecido la primera CTP de WPF/E, producto del que hablamos ya el mes pasado en la entre-

vista a Forest Key, director of developer tools product management en Microsoft. Vamos a tener experiencia de usuario hasta en la sopa ☺, y la verdad es que es muy divertido. Y seguimos con las presentaciones. Rafael Ontivero, más conocido por RFOG, escribe un magnífico artículo titulado “C++/CLI: un nuevo enfoque al desarrollo en C++ para .NET”, el primer artículo que en estos tres años le dedicamos a C++. !Ya iba siendo hora! Tres años presentando nuevos autores y ¡los que nos quedan! Como puede ver, hay bastante buena gente –en todos los sentidos– que puede enseñarnos mucho en nuestro castellano natal. El artículo central de este mes es “Atributos, aspectos y cómo entretejer código desde Visual Studio para hacer AOP en .NET (I)” del grupo Weboo de la Universidad de La Habana, en el que participa, junto al profesor Katrib, Yamil Hernández, genial ilustrador y creador de nuestra mascota. Espero que le guste. Como siempre, dentro hay más.

Paco Marín

<<dotNetManía

Editor Paco Marín (paco.marin@dotnetmania.com)

3


33

dnm.sumario

Planificación de la calidad

10-11

Hace ya algún tiempo escribí en este mismo medio un artículo cuyo título era “Aseguramiento de la Calidad. Normas versus personas”. En aquel momento me preguntaba si la mayor eficacia en la persecución del error la logramos activando políticas de recursos humanos que nos ayuden a contratar a los mejores profesionales o si, por el contrario, basta con desarrollar sistemas de control de calidad que nos ayuden a lograrlo.

Entrevista a David Chappell

12-14

Con ocasión de la conferencia de SOA y Business Process celebrada recientemente en Madrid, tuvimos la ocasión de charlar con David Chappell, Principal de Chappell & Associates (www.davidchappell.com) en San Francisco. David es además autor de libros sobre software empresarial que se han publicado en diez idiomas y se han utilizado en ciertas carreras del MIT, la ETH de Zurich y docenas de otras universidades. Es ponente habitual en eventos y conferencias en Estados Unidos, Europa, Asia y Latinoamérica.

C++/CLI: un nuevo enfoque al desarrollo en C++ para .NET

15-21

C++/CLI es el lenguaje de bajo nivel dentro del mundo .NET, puesto que permite realizar tareas que son prácticamente imposibles con otros lenguajes; aparte de ello, permite ir incorporando paulatinamente facetas de .NET a proyectos ya existentes, tanto Win32 como MFC. Otros aspectos importantes son el rendimiento (tanto dentro del propio .NET Framework como en los cambios de contexto entre manejado/nativo) y la facilidad para mezclar ambos tipos de código.

dnm.sumario

Trabajo con DataSet y ReportViewer

22-24

Cuando se trabaja con asiduidad con SQL Server 2000 Reporting Services, en muchas ocasiones se tiene la necesidad de operar con conjuntos de datos (DataSet). Sin embargo, SQL Server 2000 Reporting Services no nos ayuda mucho cuando se trata de trabajar con conjuntos de datos, y para usarlos estamos obligados a hacer algún pequeño enredo.

Atributos,aspectos y cómo entretejer código desde Visual Studio para hacer AOP en .NET (I)

26-34

Con la Programación Orientada a Aspectos (Aspect Oriented Programming – AOP) se pretende que la funcionalidad del código principal de una aplicación y la funcionalidad adicional indicada en forma de “aspectos” puedan ser reusadas, modificadas y extendidas sin afectarse entre sí.

Parámetros personalizados en los eventos

35-40

En este cuarto artículo dedicado a los delegados y eventos nos centraremos en cómo comunicarnos entre la clase que define los eventos y la que los intercepta. Veremos esa comunicación de dos formas diferentes, usando parámetros por referencia y de la forma recomendada, que es definiendo nuestra propia clase para usar como parámetro de los eventos. También abordaremos una característica exclusiva de C#, que es la posibilidad de usar clases base como parámetros de los métodos que reciben los eventos.

Una mirada a WPF/E

42-46

WPF/E (Windows Presentation Fundation Everywhere) se nos presenta como un subconjunto de WPF. Este subconjunto ha sido seleccionado con la intención de proporcionarnos diversas funcionalidades que permitirán la creación de entornos visuales ricos en nuestras páginas; tales entornos eran impensables hasta el momento, mediante la utilización únicamente de HTML.

dnm.todotnet.qa Mi meta es el rendimiento

47-49

dnm.laboratorio.net Ribbon.NET, PowUpload y PowerWEB Zoom for ASP.NET

50-51

dnm.comunidad.net

52-53

BcN DEV .NET developers community of Barcelona

dnm.biblioteca

55

Microsoft SQL Server 2005: Applied Techniques Step by Step. Solid Quality Learning CLR via C#, Second Edition. Jeffrey Richter

dnm.desvan

58


dnm.noticias

6

noticias.noticias.noticias.noticias.noticias.noticias

<< dotNetManía

<<

dnm.noticias

ASP.NET AJAX RC 1 disponible Es la última versión preliminar de ASP.NET AJAX (antes Atlas), cuya versión final está prevista para este mismo mes de enero ASP.NET AJAX RC está compuesta por varias descargas interrelacionadas: • Por un lado, ASP.NET AJAX 1.0 RC, que es lo primero que habrá de instalar. Entre las nuevas características incluye soporte de parsing en el cliente para globalización, invocación dinámica de proxies de servicios Web y sustitución lógica, compresión y soporte de caching para el manejador Script Resource y cambios en los espacios de nombres y ensamblados de ASP.NET AJAX (han cambiado el espacio de nombres Microsoft.* por System.*) para asegurar la compatibilidad entre ASP.NET AJAX 1.0 y ASP.NET AJAX en la próxima versión de .NET Framework. • ASP.NET AJAX Control Toolkit. Para esta versión hay tres nuevos controles dentro del ASP.NET AJAX Control Toolkit: DropDown, MutuallyExclusive CheckBox y ValidatorCallout.

• CTP de diciembre de ASP.NET 2.0 AJAX Futures, que aporta características que extienden el núcleo de la plataforma ASP.NET AJAX 1.0 con funcionalidades adicionales que permanecen bajo desarrollo. • Aplicaciones de ejemplo. El equipo de desarrollo de ASP.NET AJAX ha reunido unas cuantas aplicaciones de ejemplo que le mostrarán las nuevas características y le ayudarán a desarrollar sus propias aplicaciones. • Microsoft AJAX Library RC. Está también disponible como un paquete para una instalación sencilla independiente para desarrollos en sistemas noWindows.

Visual Studio 2005 SP1

Disponibles también...

Visual Studio 2005 SP1 ya está disponible para su descarga en http://msdn.microsoft.com/vstudio/support/ vs2005sp1. Este service pack es fruto del feedback recibido por Microsoft de sus clientes y socios (a través de MSDN Product Feedback Center y Microsoft Connect), así como del propio chequeo interno de la compañía, además de incluir nuevas funcionalidades y mejoras en toda la línea de producto de Visual Studio 2005. Visual Studio 2005 aporta alrededor de 70 mejoras en distintos escenarios de desarrollo: • Soporte para la generación de código para nuevos procesadores (por ejemplo Core Duo). • Mejoras de rendimiento y escalabilidad en Team Foundation Server. • Integración de Team Foundation Server con Excel 2007 y Project 2007. • Herramienta de soporte para dispositivos conectados ocasionalmente y SQL Server Compact Edition. • Soporte adicional para aplicaciones Web basadas en ficheros de proyecto. • Soporte de Windows Embedded 6.0. Para los desarrolladores que usen Visual Studio 2005 bajo Windows Vista, Microsoft está desarrollando una actualización a este SP1 que se llamará Visual Studio 2005 SP1 Vista Refresh. Actualmente está en fase beta, y se espera que esté disponible junto con Windows Vista para clientes finales en el primer trimestre de 2007.

Más información y descargas en: http://ajax.asp.net/ default.aspx?tabid=47&subtabid=471.

Microsoft Robotics Studio 1.0. Microsoft ha anunciado la versión 1.0 de Microsoft Robotics Studio, un entorno de desarrollo gratuito para crear aplicaciones de robótica. Podrá desarrollar este tipo de aplicaciones usando Visual Studio, incluyendo las ediciones Express (Visual C# y Visual Basic). Más información: http://msdn.microsoft.com/robotics.

Microsoft XNA Game Studio Express 1.0. Es un nuevo conjunto de herramientas y tecnologías gratuitas basadas en .NET, las cuales permiten la creación de fantásticos videojuegos para PC basados en Windows XP (para Vista aún no está disponible) y la consola Xbox 360. Además está disponible Microsoft XNA Framework Redistributable 1.0, que aporta a los desarrolladores de juegos las librerías runtime que deben ser incluidas con sus productos para ser distribuidos con Windows XP. Información y descargas en: http://msdn.microsoft.com/directx/xna/gse.

Visual Studio 2005 Team Edition for Database Professionals RTM. Microsoft ha liberado la versión RTM de Visual Studio 2005 Team Edition for Database Professionals, un producto diseñado para gestionar cambios en bases de datos que mejora la calidad del software a través del database testing y que trae los beneficios de Visual Studio Team System y el ciclo de vida del desarrollo a las bases de datos profesionales. Está disponible para su descarga para suscriptores a MSDN desde el 7 de diciembre y para su compra desde el 1 de enero. Más información en http://msdn2.microsoft.com/en-gb/teamsystem/aa718807.aspx.


<< dnm.noticias

Microsoft presenta Expression Studio y WPF/E Expression Web entregada y Expression Media anunciada. Éstos comparten producto y nuevos avances de plataforma con la primera CTP de WPF/E Microsoft ha anunciado importantes mejoras en la línea de productos, junto con el precio y disponibilidad de Microsoft Expression Studio para profesionales creativos. Expression Studio es un componente clave en la estrategia de Microsoft para mejorar la experiencia de usuario, equipando a los diseñadores con una plataforma de herramientas end-to-end que impulsará la colaboración con los desarrolladores en la entrega de aplicaciones con experiencias de usuario de próxima generación para la Web, para Windows Vista y otros sistemas. Comprende Expression Web para la creación de sitios Web, Expression Blend (antes Interactive Designer) para diseñar experiencias interactivas ricas para Windows y Expression Design (antes Graphic Designer) para el diseño de elementos visuales tanto para experiencias Web como Windows, y una nueva herramienta llamada Expression Media, la cual

aporta gestión de los activos digitales y unifica el flujo de trabajo del equipo a través de la suite. Expression Media -basado en iView MediaPro, producto comprado recientemente por Microsoft- soporta más de 100 formatos multimedia y aporta acceso fuera de línea a los catálogos visuales, haciendo más fácil que los profesionales creativos gestionen y usen sus activos digitales. Expression Media incluye Expression Media Encoder, una solución completa para la preparación, codificación y despliegue de vídeo y audio rico para experiencias Web y Windows. La primera CTP de Expression Media se espera para 2007. Hay un nuevo recurso para la comunidad de diseñadores en http://www.microsoft.com/design. Éste incluye foros, demos en vídeo y blogs de los equipos. El sitio Web hace especial hincapié en el diseño creativo y la experiencia de usuario, ofreciendo una visión entre bastidores del pro-

ceso de diseño para los principales productos, como por ejemplo Xbox 360, Windows Vista y 2007 Microsoft Office System. Expression Web ya está listo, mientras que el resto del Expression Studio está planificado para entregarse en el segundo trimestre de 2007. Expression Blend Beta 1 y la CTP de diciembre de Expression Design ya están disponibles para su desacarga. Más información y descargas en: http://www.microsoft.com/expression, donde se incluye una versión de evaluación de 60 días de Expression Web. Hasta la aparición de la primera beta de Expression Media en 2007, puede descargarse el iView MediaPro en http://www.iview-multimedia.com.

El pasado mes de diciembre se presentó la primera CTP de WPF/E(verywhere), de la que precisamente hablábamos el mes pasado en una entrevista con Forest Key, director of developer tools product management en Microsoft. Según él “WPF/E es una combinación de dos partes muy importantes: por un lado, un subconjunto de XAML, que permitirá renderizar texto, imágenes, vídeo, etc.; por otro, una versión del CLR más pequeña y especializada, que permite ejecutar una aplicación dentro de un explorador como un plug-in, y por tanto puede ejecutarse en cualquier plataforma”. Scott Guthrie, general manager del equipo que es responsable de la arquitectura .NET y WPF/E, la presentaba desde su blog en http://weblogs.asp.net/scottgu. Según Guthrie “lo que hace a WPF/E realmente atractivo desde la perspectiva del desarrollador es que es fácil de integrar con las páginas y sitios HTML existentes.

Los desarrolladores pueden escribir Javascript estándar en una página HTML para manipular directamente y programarlo contra cualquier elemento XAML DOM, animación de tramas o vídeo dentro de WPF/E. Esto permite a los desarrolladores añadir fácilmente sus activos WPF/E a sus soluciones HTML AJAX de hoy y ser capaces de usar un código base simple con un framework AJAX consistente para trabajar contra HTML y XAML DOM sobre la página al mismo tiempo”. WPF/E es un pequeño runtime que nos permitirá crear páginas y aplicaciones Web que incluyan contenido rico como gráficos vectoriales, animación 2D, texto, audio y vídeo de alta fidelidad (sin necesidad de Windows Media Player) y usar AJAX para interactuar entre el contenido de la página y el servidor. Estas páginas y aplicaciones Web podrán ejecutarse en cualquier lugar, dentro de navegadores y bajo múltiples dispositivos y sistemas ope-

rativos de escritorio, como por ejemplo, Apple Macintosh. Esta primera CTP puede ejecutarse en sistemas Windows y Macintosh (tanto x86 como PowerPC) y soporta los navegadores IE, Firefox y Safari. Para poder ejecutar las aplicaciones, el explorador del usuario necesita tener instalado el paquete WPF/E que puede bajarse desde http://www.microsoft.com/wpfe, donde podrá encontrar toda la información actualizada sobre WPF/E. dnm.noticias

<< dotNetManía

WPF/E es el nombre en clave para la nueva tecnología de presentación Web que ha sido creada para ejecutarse en un entorno multiplataforma

7


<< dnm.noticias

expo:QA 2006, III Jornadas profesionales de ingeniería, calidad y testing de software Los días 27, 28, 29 y 30 de noviembre se celebró en el Hotel Meliá Barajas de Madrid la tercera edición de expo:QA. Las jornadas, organizadas por inQA.labs, se consolidan en el sector de la calidad y el testing de software, donde los profesionales cuentan con un área común en la que exponer ideas e iniciativas en torno a la mejora de procesos de prueba o el incremento de la calidad en sus productos. Además, los principales proveedores muestran sus últimas aportaciones a este sector. En esta edición, con una asistencia de más de 150 personas, participaron empresas de la talla de Microsoft, IBM, inQA.labs, Telelogic, PRQA, IRqA, Compuware, Borland, Mercury y Gesein para disfrute de directores de desarrollo, responsables de proyectos, directores de calidad y, en general, profesionales de TI. La feria se distribuyó en diferentes módulos y días: • Cursos especializados para profesionales y centrados en las áreas de testing (mejora de eficiencia), gestión de proyectos (riesgos, PMI), gestión de requisitos (estándares IEEE, MDA) y unit testing. Entre ellos, cabe destacar la presencia de Michel Bolton, con el curso de Rapid Software Testing. En España, es la primera vez que se realiza este curso escrito por James Bach, uno de los fundadores de Context-driven School of Software Testing. La filosofía de Rapid Testing, al contrario que los métodos tradicionales de test, aboga por la simplicidad, dado que hoy en día los productos son demasiado complejos y los testeadores resultan demasiado caros. Rapid Testing utiliza un método cíclico, así como métodos heurísticos

para optimizar constantemente el test y adecuarlo a los requisitos de sus clientes. Rapid Testing es un test rápido, centrado en una misión que elimina el trabajo innecesario a favor de lo necesario y constantemente pregunta qué puede hacer el test para acelerar el proyecto. • Taller sobre la calidad en entornos colaborativos, donde los asistentes pudieron experimentar directamente con las herramientas de Mercury para el testing de software. • Presentaciones y exposición de las empresas patrocinadoras. En el último día de la feria tuvimos ocasión de asistir a diferentes e interesantes presentaciones sobre VSTF, DOORS, ClearQuest, IRqA con TestDirector y Quality Center y diferentes casos de éxito basados en SQA, métricas, Mercury’s Business Technology Optimization, estandarización de código, continuous integrated testing, automatización de tests y test coverage. El contenido de las ponencias estará disponible próximamente en el portal de inQA.labs: www.inqalabs.com.

Microsoft y la escuela de negocios IDE-CESEM se unen para fomentar la creación de empresas

<< dotNetManía

Ambas entidades proporcionarán los recursos necesarios, tanto a nivel tecnológico como empresarial, para que los emprendedores españoles hagan realidad sus proyectos.

8

Microsoft, a través de su Plan Emprendia, y la escuela de negocios IDE-CESEM han firmado un acuerdo de colaboración para ayudar a todas aquellas compañías de base tecnológica y nueva creación que precisen de asesoramiento en materia de administración de empresas. Gracias a este proyecto conjunto entre ambas entidades, los desarrolladores de software españoles que quieran aumentar la competitividad de sus proyectos empresariales en un mercado puntero como el de las Tecnologías de la Información, tendrán la oportunidad de acceder gratuitamente, como parte de las innovadoras iniciativas del Plan Emprendia,

a las sesiones de negocio impartidas en las instalaciones del centro de estudios empresariales. El acuerdo alcanzado entre ambas entidades contempla que Microsoft ofrecerá su apoyo en materia de consultoría técnica y de desarrollo de software, a través del Microsoft Technology Center que la compañía comparte con el Gobierno de Aragón. Por su parte, IDE-CESEM, como Escuela de Negocios, impartirá unas jornadas formativas de dos días de duración (14 horas lectivas), con el fin de dotar a los participantes del Plan Emprendia de los conocimientos básicos sobre la impor-

tancia de contar con una fórmula jurídica que avale sus proyectos empresariales. Entre los temas que se tratarán a lo largo de 2007 en estos Seminarios Multidisciplinares de Creación de Empresas se encuentran la concienciación de la creación de empresas, la determinación jurídica de la empresa, cómo elaborar un bussines plan y su desarrollo con una estructura de marketing y comunicación, así como la presentación de casos reales de proyectos emprendedores vinculados al mundo de las TI. Más información sobre el Plan Emprendia en www.msdnemprendia.com. dnm.noticias


dnm.opinion

Antonio Quirós

Planificación de la calidad Hace ya algún tiempo escribí en este mismo medio un artículo cuyo título era “Aseguramiento de la Calidad. Normas versus personas”. En aquel momento me preguntaba si la mayor eficacia en la persecución del error la logramos activando políticas de recursos humanos que nos ayuden a contratar a los mejores profesionales o si, por el contrario, basta con desarrollar sistemas de control de calidad que nos ayuden a lograrlo.

<< No me gusta repetirme y odio, por tanto, que parte de

Antonio Quirós es colaborador habitual de dotNetManía. Co-fundador de las revistas clippeRManía, FOXManía y Algoritmo.Actualmente es director de operaciones en Alhambra-Eidos.

lo concluido en aquella ocasión deba ser mencionado nuevamente en esta serie que llevo escribiendo desde hace varias entregas sobre los signos de madurez de las empresas que desarrollan software. Sin embargo, y para diferenciar este artículo de aquel otro, en éste me ceñiré a lo que supone la realización de planes de calidad en los proyectos de desarrollo de software frente a lo analizado allí, que iba más en la dirección de indagar sobre qué potenciaba más la calidad, si los métodos o si las personas. En cualquier caso y, por trabajar con una definición operativa razonable definiremos el aseguramiento de la calidad en el proceso de desarrollo de software como la concordancia del software producido con los requisitos funcionales y de rendimiento explícitamente establecidos, con los estándares de desarrollo explícitamente documentados y con las características implícitas que se esperan de todo software desarrollado profesionalmente. Cualquier compañía de software debe garantizar que con sus productos no se produce el triste espectáculo de ver a los usuarios de los mismos, durante los primeros días de cualquier implantación, sufriendo los múltiples errores que una versión poco testeada suele portar. Si los desarrolladores fuéramos conscientes del enorme impacto negativo que esto tiene para nosotros, para nuestras empresas, para nuestro prestigio, para nuestro futuro, seguro que nos esforzábamos más en garantizar que nuestros proyectos tiendan al Zero error tan demandado en cualquier metodología para el desarrollo de software que se precie.

Cualquier compañía de software debe garantizar que con sus productos no se produce el triste espectáculo de ver a los usuarios de los mismos (…) sufriendo los múltiples errores que una versión poco testeada suele portar

Nuestra profesión no consiste sólo en desarrollar software, consiste en desarrollar software libre de errores, y en la consecución de este objetivo el control de la calidad es un pilar básico. En ello se basa nuestra tesis de que compañías que no tienen adecuadamente protocolizados los mecanismos que usan para garantizar que los productos que construyen estén libres de errores no tienen cabida en el complejo mundo del software actual. Pero ¿cómo garantizar esto? Bien, no es muy difícil. En primer lugar hay que tener claro que todo proyecto debe tener realizado su correspondiente plan de pruebas y su correspondiente plan de calidad. Ambos no deben ser confundidos. El primero


<< dnm.opinion

La matriz de trazabilidad de los requisitos es una pieza importantísima del control de calidad, ya que es la que nos garantiza que todos los requisitos de usuario están tratados en los correspondientes requisitos de sistemas y/o en los casos de uso

Hay que reseñar también que el control de calidad va más allá de la duración del propio proyecto y debe también proponer qué otras acciones de auditoría posterior realizaremos sobre el proyecto objeto del plan. Algunas cuestiones muy interesantes son: • La realización del análisis post-mortem. Este es un informe de resumen del proyecto donde deben recogerse los parámetros básicos de su ejecución: confrontación de datos estimados y reales, incidencias específicas a mencionarse y apreciaciones especiales tanto del jefe como de otros miembros del equipo del proyecto. • El paso del proyecto por la comisión de buenas prácticas en la que se debe analizar todas las prácticas que hayan contribuido a que el proyecto haya sido exitoso. Todo ello con el fin de transmitir al resto del personal técnico dicha información y garantizar así la repetibilidad de estos éxitos en el futuro. • El paso del proyecto por el foro de errores de la compañía para que en dicho foro se reseñen todas aquellas decisiones incorrectas que se han concretado en un daño de cualquier tipo para el proyecto. La finalidad de este instrumento, obviamente, no es señalar culpables, sino analizar causas y corregir problemas para el futuro. En fin, para concluir ya, simplemente remarcar que el hecho de que una empresa tenga determinada su política de calidad y que realice planes de calidad ad hoc para cada proyecto que desarrolla no es un elemento baladí sino que representa un signo, más que relevante, de que tiene el suficiente grado de madurez como para garantizar que el éxito que haya obtenido en proyectos anteriores no es fruto del azar sino que obedece al desarrollo de unas prácticas adecuadas y que, por tanto, podemos tener garantía de la repetibilidad de dicho éxito.

<<dotNetManía

debe contener una definición rigurosa (casos de uso de pruebas bien definidos) de todas las pruebas que se han de realizar sobre los distintos componentes, programas, módulos, subsistemas, etc. que se vayan a construir. El plan de pruebas debe contener las instrucciones para su ejecución y las normas de actuación (iteraciones ante fallo, elaboración del informe de pruebas, etc.) que debe ejecutarse para seguir el mismo. Las sucesivas iteraciones sobre las pruebas nos irán dando garantía de que vamos afinando hasta lograr el producto libre de fallos que necesitamos. El plan de calidad es más abstracto y debe contener, como mínimo, los siguientes elementos: • Una descripción general de las políticas de calidad que estamos aplicando a nuestro proyecto. • Una relación de todos los entregables del proyecto con sus correspondientes criterios de aceptación. Por supuesto que aquí debemos incluir tanto el software como la documentación. Entregables son tanto una especificación de requisitos como el acta de una reunión, el código fuente de una clase, el ejecutable de un subsistema, etc. Diseñado así, es muy fácil para nuestro cliente supervisar el entregable, revisar si se cumplen los criterios de aceptación y, si procede, que nos valide la entrega realizada. Así, por ejemplo, un criterio de aceptación del código fuente debería ser que esté escrito según la guía de estilo que hayamos determinado, un criterio de aceptación de un ejecutable es que haya pasado el correspondiente plan de pruebas, etc. • Una descripción de las labores de control y monitorización que se han realizado en el proyecto. Por supuesto que dichas labores deben corresponderse con las que hayamos determinado como genéricas en nuestra política de calidad. Cualquier excepción debe ser remarcada con la explicación correspondiente que la ha hecho posible. • La matriz de trazabilidad de los requisitos es una pieza importantísima del control de calidad, ya que es la que nos garantiza que todos los requisitos de usuario están tratados en los correspondientes requisitos de sistemas y/o en los casos de uso. • Una lista de comprobación de que todas las actividades de control de calidad se han llevado a cabo, con la fecha y el nombre del responsable de verificarlas. Aquí debería certificarse que se han realizado las pruebas (tanto las unitarias como las de integración) y que los resultados son satisfactorios, que se han realizado igualmente las peer reviews, que no quedan incidencias reportadas por el cliente y pendientes de resolver, etc.

11


dnm.directo.entrevistas

Carlos Salazar

Entrevista a David Chappell Con ocasión de la conferencia de SOA y Business Process celebrada recientemente en Madrid, tuvimos la ocasión de charlar con David Chappell, Principal de Chappell & Associates (www.davidchappell.com) en San Francisco.David es además autor de libros sobre software empresarial que se han publicado en diez idiomas y se han utilizado en ciertas carreras del MIT,la ETH de Zurich y docenas de otras universidades.Es ponente habitual en eventos y conferencias en Estados Unidos,Europa,Asia y Latinoamérica.

<< En primer lugar, ¿podría presentarse ante los lectores?

Carlos Salazar es director de Raona Madrid, ingeniero superior en Informática y posee las certificaciones MCSD VB y MCSD.NET.

Me llamo David Chapell, soy conferenciante, escritor y consultor de Chapell & Associates en San Francisco, California. Estoy ampliamente focalizado en tecnología .NET, aunque también he realizado labores de consultoría para empresas como HP, IBM y otros. Mi último libro se titula “Understanding .NET” y últimamente he escrito una gran cantidad de artículos sobre .NET Framework 3.0. He venido a España como ponente en la edición europea del Tech-Ed y actualmente estoy realizando diversas charlas en un tour por toda Europa, entre ellas la de hoy sobre SOA y BPM. La semana pasada estuvo, pues, en el Tech-Ed europeo de Barcelona. Para los que no pudieron asistir a la cita, ¿qué aspectos le gustaría destacar? El Tech-Ed es un gran evento, por lo que es difícil resaltar unas partes respecto a otras aunque, lógicamente, hubo mucha atención en torno a la presentación de .NET Framework 3.0. Por otro lado, hubo una gran cantidad de sesiones sobre LINQ (Language Integrated Query) a cargo de su creador, Anders Hejlsberg, que fueron de las más comentadas. En anteriores ediciones del TechEd presentó Business Process Management, pero también Java y .NET. ¿Cómo resumiría para nuestros lectores los contenidos de esas sesiones? En la sesión sobre BPM tuvimos ocasión de revisar cuál es la estrategia que Microsoft está siguien-

do hoy en día para aplicar soluciones BPM. Los productos y tecnologías que, según Microsoft, caen dentro de la categoría general de BPM son Biztalk Server 2006 y Windows Workflow Foundation (WF), unido al soporte para WF incluido en Sharepoint Services 3.0 y Microsoft Office Sharepoint Server 2007. Existen dos perspectivas en la forma en que Microsoft está planteando los motores de flujos de trabajo. Dos motores de proceso separados con sus propias herramientas, uno para flujos de trabajo de sistema con Biztalk y otro para flujos de trabajo humanos con Windows Sharepoint Services. Hay quien puede pensar que eso no es un BPM, a menos que se combinen ambos planteamientos y, por tanto, en mi charla pudimos revisar estas tecnologías y comentar casos como éste.


<< dnm.directo.entrevistas

Es posible que en el futuro no se siga ninguna de estas alternativas o se imponga alguna versión mixta de todo esto, lo cual supondría un gran retraso, ya que significaría que ninguna de esas opciones atrae suficientemente a los desarrolladores para ser un competidor real ante .NET; y .NET, como todos, necesita competidores. Siguiendo con BPM, ¿nos podría sintetizar los principales puntos de Business Process Management y su importancia para el mercado?

• Crear la infraestructura orientada a servicios necesaria, no únicamente mediante el uso de SOAP sino también con el uso de un Enterprise

<<dotNetManía

En la otra sesión, “Comparing .NET and Java, the view from 2006”, tuvimos ocasión de revisar cómo se plantea el futuro de ambas tecnologías, lo cual resulta bastante interesante dada la situación en que nos encontramos. Por un lado, en el mundo .NET sabemos lo que viene después del .NET Framework 2.0 y es exactamente el .NET Framework 3.0. En cambio, en el mundo Java la cosa es bastante más compleja. En el mundo Java, J2EE 1.4 se encuentra instalado en la mayoría de servidores de aplicación Java existentes pero, mirando al futuro, existen diferentes alternativas que seguir. No es obvio decidir cuál de estas alternativas triunfará después de J2EE 1.4, y eso es lo que pudimos ver en esta sesión comparándolo, por supuesto, con la evolución en .NET con el Framework 2.0 y 3.0. A día de hoy existen tres iniciativas diferentes en esta evolución de J2EE: • JEE5. Liderada por Sun y, por tanto, el sucesor oficial de J2EE 1.4 • Open SOA. Liderada por IBM y BEA, y en la que podemos encontrar también otras empresas adyacentes como Oracle, SAP y, por qué no, Sun. Es en esta iniciativa donde encontramos dos nuevas tecnologías que están adquiriendo importancia: Service Data Objects (SDO) y Service Component Architecture (SCA). • El mundo open source. Iniciativa que no está bajo control de ninguna empresa y que ha producido tecnologías tan relevantes como Struts, Spring Framework, Hibernate, etc.

Debemos analizar la gestión de procesos de negocio (BPM) desde el punto de vista del negocio y desde el punto de vista de la tecnología. La visión de negocio no está totalmente separada de la visión tecnológica, ya que una persona de negocio debe utilizar ciertas herramientas para revisar y gestionar los procesos de una organización. Asimismo, desde el punto de vista tecnológico se debe facilitar la creación, gestión y monitorización de la lógica de los procesos, los flujos de trabajo y las orquestaciones y, por tanto, debemos proporcionar herramientas que permitan trabajar, definir, ejecutar y monitorizar esos procesos. ¿De qué manera podemos orientar el beneficio en el uso de BPM en las organizaciones? Lógicamente, el beneficio lo obtendremos en la medida en que las organizaciones se enfoquen a: • Estandarizar las comunicaciones orientadas a servicio utilizando protocolos comunes como SOAP para comunicar aplicaciones y con la utilización de un marco de trabajo común para crear aplicaciones orientadas a servicios, en este caso Windows Communication Foundation (WCF).

13


<< dnm.directo.entrevistas

<<dotNetManía

Service Bus (ESB) como middleware que soporta la comunicación e interacciones entre aplicaciones, usuarios, procesos de negocio y otros servicios. • Utilizar tecnologías BPM de forma efectiva. Independientemente del punto de vista de negocio o tecnológico que comentábamos anteriormente, debemos disponer de herramientas de ejecución de flujos de trabajo, herramientas gráficas para el diseño de los mismos, herramientas para implementar soluciones de integración, motores de reglas de negocio (Business Rules Engines –BRE–) y, por supuesto, herramientas de monitorización (Business Activity Monitoring). Basándonos en la oferta de Microsoft para BPM, estamos hablando de productos como Biztalk Server 2006, Windows Workflow Foundation (WF) y Windows Sharepoint Services 3.0 (WSS) complementándolo con Microsoft Office Sharepoint Server 2007 (MOSS 2007).

14

Así pues, en el ámbito de BPM, ahora Microsoft cubre todas las áreas que indicábamos, desde BAM o la integración con Biztalk hasta los flujos de trabajo con Windows Sharepoint Services 3.0 y MOSS 2007. Además, Windows Sharepoint Services ya se incluye con Windows 2003 Server, por lo que poco a poco veremos cómo se va imponiendo su uso en

nuestras organizaciones. También podremos ver cómo Windows Workflow Foundation (WF) se va a utilizar en diferentes áreas, ya sea alrededor de la tecnología Microsoft o por terceros. En muchas organizaciones, SOA es todavía un deseo o un objetivo de futuro más una realidad. Entre todos los beneficios que promete SOA, ¿qué cree que se mantendrá en el futuro? Soy bastante escéptico en lo que respecta a la habilidad de las organizaciones para conseguir los objetivos de reusabilidad de SOA y, de hecho, no conseguirlos podría ser decepcionante para muchas empresas. Pero la gente debe darse cuenta de que hay una parte muy importante que hay que comprender en la infraestructura necesaria de un ASP o en cómo deben aplicar tecnologías BPM a su problemática y situación interna. Todas estas iniciativas son movimientos que fortalecen y hacen progresar a las organizaciones y, por tanto, la gente no debería decepcionarse si no siguen al pie de la letra los principios de reutilización prometidos por SOA, ya que de hecho sí que están mejorando las comunicaciones y la infraestructura de sus organizaciones. ¿Podemos hablar de enriquecer la experiencia de usuario desde el punto de vista de SOA? En efecto, si analizamos los beneficios de SOA desde el punto de vista de la interfaz de usuario, podemos pensar en unificar y fortalecer la experiencia de usuario. Así, debería ser más fácil desarrollar interfaces gráficas que se comuniquen con diversas aplicaciones de una forma consistente. Por tanto, en el mundo de .NET Framework 3.0 esto significa que WPF puede aportar una plataforma común para definir interfaces de usuario que empleen servicios reutilizables. Creo que en el mundo SOA podríamos tener ese tipo de estándar de definición en cliente. A pesar de que me considero una “persona de servidor”, últimamente he tenido ocasión de revisar todo lo que incluye WPF y creo que es increíblemente interesante ver cómo podemos crear nuevas GUI con WPF. Cuando un desarrollador escucha alguna información sobre Vista API se siente un poco abrumado por la cantidad de input que recibe. ¿Serán Vista y Longhorn una especie de “pruebas de habilidad” para los programadores? En este caso lo importante no es lo difícil que pueda ser una u otra tecnología, sino determinar qué tecnologías de todas las disponibles nos interesan más para nuestro trabajo. Por ejemplo, si hablamos de .NET Framework 3.0, lo importante es que un desarrollador especialista en interfaces de usuario se centre en WPF y no tanto en WF, donde sólo puede necesitar ciertos conocimientos de referencia. Así pues, habrá que focalizarse en lo que hacemos y comprender el resto de tecnologías existentes.


dnm.lenguajes.net

Rafael Ontivero “RFOG”

C++/CLI: un nuevo enfoque al desarrollo en C++ para .NET C++/CLI es el lenguaje de bajo nivel dentro del mundo .NET,puesto que permite realizar tareas que son prácticamente imposibles con otros lenguajes;aparte de ello,permite ir incorporando paulatinamente facetas de .NET a proyectos ya existentes, tanto Win32 como MFC. Otros aspectos importantes son el rendimiento (tanto dentro del propio .NET Framework como en los cambios de contexto entre manejado/nativo) y la facilidad para mezclar ambos tipos de código.

<< Aunque el tema de actualizar proyectos existentes es inte-

Asignación en pila/montículo manejado

Rafael Ontivero tiene más de 20 años de experiencia como programador en múltiples lenguajes y entornos y como responsable de equipos de desarrollo.Actualmente es director técnico para España de la multinacional Suzo STC.

Mientras que en otros lenguajes .NET no existe forma sintáctica de diferenciar si nuestra variable es una referencia o un objeto en sí, C++/CLI nos obliga a que decidamos nosotros dónde va nuestro elemento, si en el montículo manejado (heap) o en la pila (stack). De hecho, disponemos de cuatro formas de definir/instanciar una clase. En primer lugar tenemos las clases-valor (value class), que Microsoft recomienda se utilicen para definir tipos sencillos y similares a los nativos. Los objetos de este tipo normalmente se colocan en la pila, pero nada nos impide instanciarlos en el montículo.

Otra de las mayores y más importantes diferencias de C++/CLI con otros lenguajes .NET la ofrece la destrucción determinista El segundo tipo de clase, y el más utilizado, es la clase-referencia (ref class), equivalente a las clases de los otros lenguajes. En este caso, la instanciación por defecto ha de realizarse en el montículo manejado, pero tampoco tendremos ningún impedimento si queremos obtener una variable en la pila. En el fuente 1 podemos observar cómo a los objetos alojados en el montículo se accede mediante el operador flecha (->) como si de un puntero se tratara, y se instancian mediante el operador ^ para distinguirlos de los tipos valor, a los que se accede mediante el operador punto. Esta decisión de diseño ha sido profundamente pensada por los creadores del lenguaje para evitar los problemas con la versión anterior del lenguaje C++ para CLR, de forma que ahora conocemos en todo momento el tipo y características del objeto que estamos usando. Una ventaja importante de lo anterior consiste en que si estamos leyendo código, rápidamente podemos determinar si una variable cualquiera es una refe-

<<dotNetManía

resante de por sí, en este artículo vamos a tratar las principales diferencias entre C++/CLI y los demás lenguajes .NET. Aún así, debemos citar la que es, bajo todos los aspectos, la primera y principal ventaja de C++/CLI sobre Visual Basic (C# es un lenguaje nuevo y por ello no tiene código antiguo), que consiste en la posibilidad de recompilar con mínimas modificaciones –generalmente ninguna– todo el código C++ existente. Evidentemente, no ganamos nada con ello salvo la posibilidad, ya citada, de ir añadiendo funcionalidades nuevas a un proyecto existente. Entre las aplicaciones más destacadas de esta técnica está la de utilizar Windows Forms dentro de una aplicación MFC o ir añadiendo elementos .NET al proyecto. Es lo que Microsoft llama just do it.

15


<< dnm.lenguajes.net Destrucción determinista

#using <system.dll> using namespace System; // *** Este tipo de clase sólo debe utilizarse para tipos pequeños value class ClaseValor { public: void Presentate(String ^inst) { Console::WriteLine( L”Hola, soy una clase valor y me instancian en {0}”,inst); } }; // *** Este tipo de clase es 100% compatible con otros lenguajes .NET ref class ClaseRef { public: void Presentate(String ^inst) { Console::WriteLine( L”Hola, soy una clase referencia y me instancian en {0}”,inst); } }; int main(void) { ClaseRef ^crMonti = gcnew ClaseRef(); crMonti->Presentate(“montículo”); ClaseRef crPila; crPila.Presentate(“pila”); ClaseValor ^cvMonti = gcnew ClaseValor(); cvMonti->Presentate(“montículo”); ClaseValor cvPila; cvPila.Presentate(“pila”); // *** No es necesaria la liberación determinista explícita // delete crMonti; // delete cvMonti; }

Fuente 1. Instanciación y uso de clases-valor y clases-referencia

<<dotNetManía

rencia o el propio objeto, a diferencia de C# o VB, en que deberemos tener presente su tipo.

16

[

NOTA

]

Para compilar el código de ejemplo, se debe disponer de una copia de Visual Studio 2005 con el soporte de C++ instalado o de Visual C++ 2005 Express. En el menú de inicio de Windows, dentro de la carpeta Visual Studio/Tools, se instala una serie de accesos directos para obtener consolas de comandos listas para poder compilar dentro de ellas. Abriendo una de ellas y tecleando cl /clr <fichero.cpp> podremos compilar y ejecutar los ejemplos suministrados.

Otra de las mayores y más importantes diferencias de C++/CLI con otros lenguajes .NET la ofrece la destrucción determinista. Mientras que en los otros lenguajes el programador nunca sabe cuándo sus objetos serán liberados por el sistema, en C++/CLI la liberación se puede forzar cuando se estime oportuno. Con esto no queremos decir que los programadores estén obligados a liberar sus recursos manualmente –poco habríamos ganado entonces frente al C++ tradicional–, sino a que podemos, voluntariamente, destruir nuestros objetos cuando queramos sin tener que estar pendientes del recolector de basura, lo que en ciertas situaciones de estrés en las que creamos y destruimos objetos de forma continuada nos supone una evidente ventaja sobre otros lenguajes, pues nuestros objetos son destruidos inmediatamente, evitando así agotar el montículo manejado o volver loco al recolector de basura. El concepto subyacente es bastante complejo y está relacionado con la interfaz IDisposable, pero podemos explicarlo bastante fácilmente sin necesidad de meternos en los entresijos de .NET Framework. Para no ser demasiado prolijos, diremos que en C++/CLI existen dos tipos de destructores. Si mediante el operador gcnew obtenemos la referencia a un nuevo objeto alojado en el montículo manejado, con delete realizamos su liberación. También podemos dejar que nuestra referencia salga de ámbito, momento en el cual el objeto al que representa quedará marcado para su destrucción cuando el recolector de basura lo estime oportuno. Si utilizamos delete estamos empleando destrucción determinista; si no lo hacemos, estamos dejando que el sistema se ocupe de la liberación (de igual forma que en C#). Pero ¿qué ocurre cuando nuestra clase incorpora otros objetos no manejados y estamos dejando al recolector de basura que se encargue de todo? ¿Debemos implementar toda la parafernalia del método Dispose() y demás? No es necesario, ya que C++/CLI presenta un comportamiento más sencillo. Debemos implementar dos destructores: el destructor típico del C++ tradicional y otro nuevo, conocido como destructor de finalización. En el primero pondremos el código necesario para la liberación de los recursos manejados y nativos si los hubiera, y en el segundo sólo incluiremos la liberación de los nativos. No es necesario decir que no necesitamos el destructor de finalización si no hemos asignado recursos nativos. El fuente 2 muestra un ejemplo un tanto artificial pero que expone lo explicado hasta ahora. La clase Destruccion cuenta con los dos destructores antes mencionados, y dentro de main() creamos tres objetos, uno de ellos en pila y otros dos alojados en el montículo. Al final llamamos a delete para liberar solo


<< dnm.lenguajes.net #using <system.dll> using namespace System; ref class Destruccion { int m_id; public: Destruccion(int id) { m_id=id; Console::WriteLine(“Soy el constructor de {0}”,id); } ~Destruccion() { Console::WriteLine(“Soy el destructor normal de {0}. Debes liberar recursos manejados y no-manejados”,m_id); } protected: !Destruccion() { Console::WriteLine(“Soy el destructor finalización de {0}. Debes liberar sólo recursos no-manejados”,m_id); } }; void main(void) { Destruccion porValor(0); Destruccion ^porRef1 = gcnew Destruccion(1); Destruccion ^porRef2 = gcnew Destruccion(2); delete porRef1; }

Fuente 2. Destrucción determinista

Figura 1. Programa del fuente 2 en ejecución

El lector atento habrá observado que también se llama al destructor normal del objeto referenciado por valor. ¿No debería llamarse al de finalización, puesto que es .NET quien lo libera? Bien, la explicación es muy sencilla: dentro de .NET Framework, una clase ha de estar alojada en el montículo para que el recolector de basura pueda realizar su trabajo, y si podemos alojarla en la pila

gracias a las características especiales de C++/CLI, estamos forzando, de nuevo, destrucción determinista… que ocurrirá cuando la variable salga de ámbito. En otras palabras, en C# (o VB.NET) una variable de tipo referencia no almacena el objeto en sí, sino una referencia a él, por lo que cuando se sale de ámbito lo que desaparece no es el objeto, sino la variable que lo representa (y el objeto queda marcado para su destrucción, sin saber cuándo lo será). En el caso que nos ocupa, lo que se destruye es el propio objeto, por lo que estamos, de nuevo, operando con destrucción determinista. Pero aquí C++/CLI no está jugando limpio con nosotros, ya que el diseño de .NET prohibe alojar objetos en la pila, y el lenguaje realmente está cumpliendo las reglas. Nuestro objeto teóricamente situado en la pila, realmente lo está en el montículo, pero el compilador nos ofrece la apariencia de que está donde nos pensamos. Lo que sí se está cumpliendo es la destrucción determinista.

Código limpio En la versión anterior de C++ para el CLR, conocida como Extensiones manejadas, una decisión de diseño poco cuidadosa llevó a que el programador se sintiera bastante incómodo y desorientado cuando estaba leyendo e interpretando código fuente.

<<dotNetManía

uno de ellos, y dejamos que sea el sistema el que se encargue del otro. En la figura 1 podemos ver qué ocurre exactamente. El objeto abandonado al sistema (porRef2) llama al destructor de finalización debido a que es el sistema quien libera los recursos manejados y nos deja a nosotros la tarea de liberar los nativos. El otro objeto asignado por referencia, al ser eliminado por nosotros, ejecuta el destructor normal y determinista.

17


<<dotNetManía

<< dnm.lenguajes.net

18

En esta versión, este problema se ha solucionado de forma elegante y limpia. Disponemos de la misma categoría de clase, la clase manejada (instanciada mediante ref class), pero ahora estamos completamente seguros de qué nos llevamos entre manos. Como una clase manejada es un concepto de clase distinto al del tradicional en C++, la instanciamos con la nueva palabra reservada gcnew, y su manejador es el “tejadillo” en lugar del asterisco; de esta forma somos plenamente conscientes de qué estamos haciendo. Durante la vida del objeto ya no es necesario que sepamos si es una referencia o un puntero puesto que sólo tenemos que usarlo, y finalmente a la hora de su destrucción también nos es en cierta medida indiferente, por lo que no se añade ninguna palabra reservada más. Estamos, pues, interfiriendo lo menos posible en el lenguaje y consiguiendo tener una nueva categoría de clase sin afectar para nada al código existente ni a las futuras ampliaciones de C++, como el próximo TR0. Esto nos lleva al siguiente paso natural, que es el de disponer de referencias de seguimiento (tracking references); igual que podemos tener una referencia a un objeto o a un puntero dentro del mundo nativo, también podemos tenerla en el manejado. El concepto subyacente es el de “alias”, “etiqueta” o “elemento de seguimiento”, y nada tiene que ver con el concepto de referencia CLR, aunque a simple vista parezca lo mismo. Al contrario que en el C++ tradicional, aquí el sistema en tiempo de ejecución sí que mantiene el seguimiento y no destruye el objeto hasta que todas sus referencias de seguimiento hayan desaparecido. Otro concepto heredado de C, que C++ mantuvo y que por supuesto también soporta C++/CLI, es el paso de una cantidad variable de argumentos a funciones, y al igual que todo dentro del CLR, es un mecanismo seguro en cuanto a tipos y a desbordamientos, puesto que los argumentos se reciben como un array. La única limitación consiste en que todos han de ser del mismo tipo. El fuente 3 muestra estas dos características. Inicialmente implementamos una función global que recibe un número indeterminado de parámetros del tipo Int32 y devuelve la suma de los mismos. En el interior de ésta podemos ver cómo recorrer todos y cada uno de los parámetros pasados. También podríamos haber usado la propiedad Length del array. Ya en main() llamamos a la función pasándole 4 enteros, asignamos el valor devuelto a la variable res y lo mostramos en pantalla. Las instrucciones siguientes toman una referencia del valor devuelto, incrementan res dentro de la función suma1res(), y muestran por pantalla el valor de res pero utilizando su referencia de seguimiento. El valor mostrado será 21. Comprobamos que trackRes sigue en todo momento y ejecuta sobre la variable res.

using namespace System; Int32 suma(... array<Int32>^args) { Int32 sum=0; for each(Int32 d in args) sum+=d; return sum; } void suma1res(Int32% r) { r++; } int main(void) { int res=suma(2,4,6,8); Console::WriteLine(res); int% trackRes=res; // referencia de seguimiento suma1res(trackRes); res++; Console::WriteLine(trackRes); Console::WriteLine(res); return 0; }

Fuente 3. Manejo de referencias de seguimiento y paso de argumentos variables.

Interop o “It Just Works” En C# puede producirse cierto desaliento cuando toca bregar con elementos de Win32 que no tienen su equivalente directo dentro de las clases .NET, dado que las llamadas a código nativo pueden resultar demasiado abstrusas y engorrosas de implementar. Mientras tanto, en C++/CLI el uso de código nativo es directo: tan solo se ha de incluir el fichero cabecera correspondiente y realizar las llamadas adecuadas. De hecho, una clase manejada puede contener punteros a elementos nativos siempre y cuando no se desee código seguro. En el fuente 4 podemos observar con detalle dos aspectos del mismo concepto. En primer lugar, dentro de main() se han colocado dos salidas de texto, una nativa utilizando los flujos estándar de C++ y la otra mediante un método de la clase Console de .NET Framework. A continuación, una clase manejada que contiene un puntero a otra nativa, instanciada en el constructor de la primera. Observe que en la manejada se han implementado los dos destructores y en ambos se libera explícitamente el puntero nativo. Conociendo el ejemplo, y sabiendo que esta clase sólo va a ser destruida por el recolector de basura, no es necesaria la implementación del destructor de finalización, pero es buena idea tenerlo por lo que pudiera pasar.


<< dnm.lenguajes.net

#using <system.dll> using namespace System; #include <iostream> using namespace std; class ClaseNativa { public: ClaseNativa() { cout << “Ctor nativo “; } }; ref class ClaseManejada { ClaseNativa *pNativa; public: ClaseManejada() { pNativa = new ClaseNativa(); cout << “en Ctor manejado” << endl; } ~ClaseManejada() { delete pNativa; } protected: !ClaseManejada() { delete pNativa; } }; void main(void) { cout << “Hola, Mundo en C++ nativo” << endl; Console::WriteLine(“Hola, Mundo en C++ manejado”); ClaseManejada ^m = gcnew ClaseManejada(); // *** Dejamos la liberación al recolector de basura }

En C++/CLI el uso de código nativo es directo: tan solo se ha de incluir el fichero cabecera correspondiente y realizar las llamadas adecuadas

da, o simplemente por una cuestión de rendimiento. Es lo que se conoce como bloqueo o fijación de una variable, operación que se realiza mediante el uso de un pin_ptr convenientemente asignado. El acto de bloquear un elemento CLI es en sí mismo bastante peligroso, pues lo que se está haciendo es marcar dicho elemento como no movible, por lo que el recolector de basura no podrá ni moverlo ni liberarlo hasta que no se desbloquee. Esto significa que en determinadas situaciones se impida la recolección y compactación de memoria, así como la asignación de nueva memoria aunque ésta esté disponible. El fuente 5 nos muestra cómo realizar un bloqueo sobre un elemento de una clase. La clase manejada TipoManejado posee una variable miembro pública. Dentro de main(), inicialmente asignamos dicha variable a un puntero del tipo pin_ptr (que bloquea el objeto dentro del CLR, imposibilitando su movimiento dentro del montículo), para luego asignarle el valor 8. Más adelante, asignamos el puntero bloqueado a un nuevo puntero nativo, y asignamos 255 al entero al que éste último apunta. La salida por pantalla es 8 y 255.

Fuente 4. Utilización de código nativo en C++/CLI using namespace System;

Disponemos de dos posibilidades a la hora de mezclar variables nativas y manejadas, o más bien una forma de convertirlas y otra más para utilizar una variable o clase manejada directamente desde el código nativo siempre que su formato sea compatible. La conversión de variables nativas a variables manejadas y viceversa requiere, igual que en los demás lenguajes .NET, el uso del marshaling, por lo que no vamos a entrar en detalles; simplemente afirmar que mediante la clase Marshal es posible la conversión. Pero hay veces que es necesaria no la conversión, sino el uso directo de una variable manejada por código nativo, como en el caso de funciones de retrollama-

ref class TipoManejado { public: int i; }; int main() { TipoManejado ^mt = gcnew TipoManejado; pin_ptr<int> pt = &mt->i; *pt = 8; Console::WriteLine(mt->i); char *pc = (char*) pt; *pc = 255; Console::WriteLine(mt->i); }

Fuente 5. Bloqueo de variables

<<dotNetManía

Mezcla de variables

19


<< dnm.lenguajes.net Métodos y variables globales En C++/CLI también podemos disponer de funciones globales, tanto nativas como manejadas, con la ayuda del preprocesador. Si queremos disponer de un método manejado global tenemos que rodearlo de las directivas #pragma managed y #pragma unmanaged, y justamente lo contrario en el caso de querer tener un método nativo. El uso de las directivas anteriores es opcional la mayoría de las veces, pero es conveniente indicarlo para claridad. El uso de variables CLR globales está restringido a los tipos de datos que se alojan en la pila. Por ello no podremos tener variables manejadas estáticas ni globales que sean referencias. El fuente 6 nos muestra cómo realizar estas tareas. Observe al final de main() que no es necesario el marshaling a la hora de convertir un tipo nativo en otro manejado siempre que exista un constructor para ello. La asignación de la cadena al puntero cadGlobal pudiera interpretarse como un error, pero no lo es, puesto que asignamos un puntero a una cadena estática previamente situada en el segmento de datos. Observe también la declaración de una variable manejada global llamada intGlobal.

Rendimiento y optimización C++/CLI es el lenguaje que produce un mejor rendimiento dentro de la plataforma .NET. Dentro de las partes de código manejado, el compilador realiza, debido a las características inherentes al mismo, toda una serie de optimizaciones sobre el código fuente que otros lenguajes no llevan a cabo. Con respecto a los segmentos de código nativo, está claro para todos que su rendimiento está muy por encima del de Visual Basic, Delphi o cualquier otro lenguaje existente, excepto quizás del de C. También dentro de los cambios de contexto entre código manejado y no manejado el C++/CLI gana por goleada a los demás lenguajes en cuanto a velocidad y, como ya hemos visto, facilidad. En el artículo “A rational attempt to substantiate C++/CLI as a first class CLI language”, de Nishant Sivakumar, disponible en http://www.codeproject.com/managedcpp/whycppcli.asp, se detalla la diferencia de rendimiento entre C# y C++/CLI durante la ejecución de transiciones repetidas entre código nativo y manejado.

<<dotNetManía

Plantillas, genéricos y STL.NET

20

Los programadores de las versiones más recientes de Visual Basic .NET y C# tienen a su disposición toda la potencia de los tipos genéricos, y no hay ni que decir que el C++/CLI los soporta también por completo. Pero las plantillas (en inglés templates) son otra cosa. Mientras que la resolución de tipos en los genéricos se lleva a cabo en tiempo de ejecución, la

#using <system.dll> using namespace System; #include <iostream> using namespace std; Int32 intGlobal; #pragma managed void metodoManaged(void) { Console::WriteLine(“método manejado”); } #pragma unmanaged void metodoNativo(void) { cout << “método nativo” << endl; } char *cadGlobal; #pragma managed void main(void) { metodoManaged(); metodoNativo(); cadGlobal = “Asignación nativa dentro de codigo manejado”; String ^s = gcnew String(cadGlobal); Console::WriteLine(s); }

Fuente 6. Métodos y variables globales

de las plantillas se realiza en tiempo de compilación, lo que permite detectar antes posibles problemas y evitar así la generación de excepciones durante la ejecución del programa. Otra diferencia muy importante entre estos dos elementos consiste en que para las plantillas el compilador genera código para cada tipo de dato instanciado, de forma que si a partir de una misma plantilla definimos muchos tipos de datos nuevos, el código crecerá de forma consecuente, mientras que con los genéricos, el tamaño del código será el mismo independientemente de la cantidad de tipos de datos “concretos” definidos, y solo ocuparán espacio en tiempo de ejecución conforme se vayan necesitando, mientras que con las plantillas estará presente todo el código. Un programador de C++ sin la STL (Standard Template Library, biblioteca que forma parte del estándar de C++) es un programador al que le falta lo más básico para trabajar. La STL es una colección de plantillas que representan estructuras de datos altamente optimizadas y funcionales, así como algoritmos e iteradores para ser aplicados a esos datos. La STL clásica se puede utilizar sin problemas dentro del lenguaje C++/CLI para código nativo, pero para tipos .NET es necesario seguir siempre una serie de reglas explicadas en el artículo “A rational attempt to substantiate C++/CLI as a first class CLI language” ya citado;


<< dnm.lenguajes.net

Diferencias menores con los demás lenguajes

Para saber más • A fecha de hoy tan solo se han publicado dos libros sobre C++/CLI: - “C++/CLI and the NET Framework”, de Stephen R. J. Frasier (APress, 2006). Este libro cubre en sus primeros capítulos el lenguaje C++/CLI y luego pasa a describir diferentes aspectos de .NET Framework desde el punto de vista del lenguaje, como el acceso a ficheros, las colecciones o el acceso a datos. - “Ivor Horton’s Beginning Visual C++ 2005”, de similares características al anterior, pero explicando con mayor profundidad tanto los temas C++/CLI como los nativos, pues también cubre el C++ nativo, y la programación Win32 y MFC. • Está pendiente de salir al mercado “CLR via C++/CLI”, de Jeffrey Richter y Julian Templeman, autores ampliamente reconocidos. • Microsoft está publicando continuamente artículos sobre la integración de código nativo con código .NET. Entre ellos podemos destacar “Integrate Windows Forms Into Your MFC Applications Through C++ Interop”, que será de utilidad a aquellos que utilicen MFC (http://msdn.microsoft.com/ visualc/default.aspx?pull=/msdnmag/issues/06/05/mixandmatch). • Hay infinidad de bitácoras dedicadas al lenguaje, entre las que podemos destacar la de Nishant Sivakumar (http://blog.voidnish.com). • Visual C++ Developer Center (http://msdn.microsoft.com/visualc) es el punto de entrada y portal de novedades sobre el lenguaje, y en él podrá encontrar numerosas referencias útiles. • La especificación de C++/CLI (fruto de su estandarización por ECMA) está disponible en http://www.ecma-international.org/publications/standards/Ecma-372.htm. • “A Design Rationale for C++/CLI”, de Herb Sutter (http://www.gotw.ca), documento en continua evolución, detalla, explica y racionaliza los puntos más oscuros del lenguaje, aclarando en gran medida todas las dudas que pudieran surgir en su aprendizaje.

Pero no por ello menos importantes. No suele ser muy habitual el uso del preprocesador dentro del mundo manejado, quizás por el grado de simplificación al que se le ha reducido en los lenguajes CLR, pero para C++/CLI se encuentra presente con toda la potencia equivalente a la de su implementación del C++ nativo. Podemos definir macros con valores, macros función, En castellano macros con argumentos variables, concatenaciones y un largo etcétera. • Por desgracia, poco o nada hay en castellano sobre C++/CLI, a excepción de lo que ha escrito el autor de este artículo. En su sitio Web (http://spaces. Dado que una clase manejada no puemsn.com/lococolina) se puede encontrar un pequeño resumen del lenguaje (unas de contener variables constantes, ni tam100 páginas en formato Word) y la traducción de un artículo de Nishant poco serlo, se ha implementado la palabra Sivakumar. reservada literal para realizar la misma • El autor, junto con Octavio Hernández, ha traducido al castellano el documento de Herb Sutter antes mencionado. Dicha traducción está disponible función; esto es, ser equivalente a static en http://www.pokrsoft.com/cpp/a_design_rationale_es.zip. const. Es común sustituir los números • Recientemente se acaban de abrir dos foros Web en castellano en mágicos que pueblan el código con macros, http://forums.microsoft.com/msdn-es. o con elementos static const dentro de clases (que conservan el tipo y permiten evitar errores tontos, pues realizan una comprobación Conclusión sintáctica completa). Una variable literal no ocupa espacio de almacenamiento, sino que es directamente sustiA lo largo de este artículo se han destacado las tuida allí donde se haya indicado. facetas en las que C++/CLI destaca y se separa de los Los punteros interiores (interior_ptr) son un tipo demás lenguajes .NET de Microsoft. A diferencia de especial de punteros permitido solamente en las Extensiones manejadas para C++ (la anterior verC++/CLI. Como su nombre indica, son punteros densión de C++ para .NET), con este nuevo lenguaje se tro de un tipo referencia, esto es, son punteros a algún puede realizar cualquier tarea prácticamente de la elemento interno de una clase, y su característica prinmisma forma que con C# o VB.NET, con la ventacipal es que siguen a la clase dentro del montículo, por ja de tener más control sobre el código generado. lo que se les permite todo lo que a un puntero nativo. Aunque también hay que decirlo: el lenguaje preUn puntero interior puede contener la dirección de senta una sintaxis más barroca, sintaxis que no asusun objeto del tipo value class situado en la pila, o la tará a un programador avezado de C++, pero posidirección de un manejador a un objeto en el montíblemente sí a los de otros lenguajes. En nuestra opiculo CLR, pero no la del propio objeto situado en el nión, las ventajas superan ampliamente al coste, sobre montículo manejado; también puede apuntar a un todo teniendo en cuenta las futuras incorporaciones, objeto nativo. Su declaración es sencilla: como la disponibilidad de la STL.NET, o la posibilidad de tener punteros a objetos manejados y refearray<double>^ data = {1.5, 3.5, 6.7, 4.2, 2.1}; rencias a objetos nativos. interior_ptr<double> pstart = &data[0];

<<dotNetManía

también podemos mezclar genéricos y plantillas mediante herencia. El uso conjunto de estas dos últimas características conlleva un importante coste en rendimiento, por lo que no se recomienda su uso. Está previsto que dentro de unos meses Microsoft ofrezca lo que se ha dado en llamar STL.NET, que no es otra cosa que la implementación de la STL realizada íntegramente en C++/CLI bajo la cobertura de .NET Framework, eliminando así todos los problemas de rendimiento y la necesidad de tener que utilizar código mixto.

21


dnm.plataforma.net

Jorge Serrano

Trabajo con DataSet y ReportViewer Cuando se trabaja con asiduidad con SQL Server 2000 Reporting Services, en muchas ocasiones se tiene la necesidad de operar con conjuntos de datos (DataSet). Sin embargo, SQL Server 2000 Reporting Services no nos ayuda mucho cuando se trata de trabajar con conjuntos de datos, y para usarlos estamos obligados a hacer algún pequeño enredo.

<< Con Visual Studio 2005 podemos por fin desarrollar informes para trabajar con Reporting Services, y en su caso, desde el propio Visual Studio 2005 podemos trabajar con el control ReportViewer, que es el control donde se presentan los datos de informes en páginas Web o aplicaciones Windows. ¿Cómo podemos entonces usar un DataSet con el control ReportViewer? Eso es justamente lo que aprenderemos a hacer en este artículo.

Iniciando nuestro proyecto No nos vamos a enredar demasiado, y vamos a llevar a cabo un ejercicio de aprendizaje netamente práctico, porque practicando es como se entiende la teoría y como se aprende a hacer las cosas; así que vamos a iniciar un nuevo proyecto de tipo Windows Forms y a insertar un control ReportViewer dentro del formulario principal. Para dar un aspecto más vistoso a nuestro proyecto, vamos a utilizar las etiquetas inteligentes (smart tags) del control ReportViewer, y a seleccionar la opción “Acoplar en contenedor principal”. De esta manera, acoplaremos el control ReportViewer al formulario, como se puede ver en la figura 1.

Jorge Serrano es colaborador habitual de dotNetManía. Es Ingeniero Informático y MVP de VB y de .NET. Es Webmaster de PortalVB.com y autor de diferentes libros y artículos técnicos.

Agregando un DataSet El siguiente paso es agregar un DataSet al proyecto. Para ello, haremos clic con el botón derecho del ratón en el explorador de soluciones y seleccionaremos la opción “Agregar” > “Nuevo elemento”. Seleccionaremos el elemento “Conjunto de datos” como plantilla a utilizar. De esta manera, se abrirá el diseñador del DataSet, que por defecto tendrá el nombre de DataSet1.xsd.

Figura 1. Formulario Windows con el control ReportViewer acoplado en él

Dentro del diseñador del DataSet, pulsaremos el botón derecho del ratón y seleccionaremos la opción “Agregar” > “DataTable” del menú contextual. De esta manera, agregaremos un DataTable con nombre DataTable1 por defecto, y lo que deberemos hacer a continuación es agregar los registros que queremos que tenga nuestro DataSet. Para llevar a cabo nuestra pequeña demostración, utilizaremos la base de datos de ejemplo AdventureWorks, y en concreto la tabla Production. Product. Atendiendo a esta tabla, nos fijaremos en los campos Name, ProductNumber y Color. Dentro del DataSet, incluiremos los tres campos que hemos fijado y que queremos mostrar en nuestro informe. Esto es lo que se puede ver en la figura 2. Debemos prestar especial atención al tipo de los campos, para indicarlo así en las propiedades de cada uno. En nuestro ejemplo, los tres campos son de tipo nvar-


<< dnm.plataforma.net char, por lo que indicaremos que todos los campos son del tipo .NET String, que es precisamente el selec-

Nuestro objetivo en esta demostración es prestar atención al apartado de detalle.

cionado por defecto.

Personalización del informe

Figura 2. Campos creados en el DataSet

Sólo a modo de personalizar el informe y como demostración, nos fijaremos en el campo Color . Nuestro objetivo no es el de presentar el nombre de este campo, sino el de presentar el color del mismo. Como hemos insertado un objeto cuadro de texto en este campo, será necesario que modifiquemos los valores de color de fondo y de borde de este control, para que presentemos ahí el color que contiene el campo.

Creación del informe y asignación al DataSet Si acudimos a la ventana del explorador de soluciones y en concreto a la solapa “Orígenes de datos”, veremos que allí se encuentra el DataSet que hemos creado anteriormente, junto a los campos de su correspondiente DataTable, con nombre DataTable1 por defecto. Esto es justamente lo que se puede ver en la figura 3.

Figura 4. Informe preparado con los campos insertados en él

El campo Color puede tener el valor nulo o un valor de color, así que haciendo clic sobre el objeto cuadro de texto, accederemos a la ventana de propiedades (F4). Dentro de la ventana de propiedades de este objeto, nos fijaremos primero en la propiedad BackgroundColor . Desplegaremos esta propiedad y seleccionaremos la opción “Expresión”, con lo que accederemos a una ventana dentro de la cual deberemos escribir la expresión con la que queremos producir el color de fondo del objeto. La ventana para editar la expresión se puede ver en la figura 5.

A continuación, añadiremos una plantilla de tipo “Informe” al proyecto, eligiendo la opción “Agregar”> “Nuevo elemento” del menú contextual que aparece al hacer clic con el botón derecho del ratón sobre el nodo del proyecto. Accederemos directamente al diseñador de informes de Visual Studio 2005, y en él y como primer paso insertaremos el objeto tabla del cuadro de herramientas. En este objeto, tenemos tres grupos de datos diferenciadores: el encabezado, el detalle y el pie.

Figura 5.Ventana para editar la expresión

<<dotNetManía

Figura 3. Campos del DataSet y DataTable desde la ventana de Orígenes de datos

23


<< dnm.plataforma.net Imports System.Data.SqlClient Imports Microsoft.Reporting.WinForms Public Class Form1 Private Function ObtenerCadenaConexion() As String Return “Data Source=.\SQLEXPRESS; “ ¡% “Initial Catalog=AdventureWorks;Integrated Security=SSPI;” End Function Private Function ObtenerSQL() As String Return “SELECT Name, ProductNumber, Color FROM Production.Product;” End Function Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) % Handles MyBase.Load Dim miDataSet As New DataSet miDataSet = CargarDatos() Me.ReportViewer1.ProcessingMode = ProcessingMode.Local Me.ReportViewer1.Name = “Visor de reportes” Me.ReportViewer1.LocalReport.ReportPath = “..\..\Report1.rdlc” Dim rds As New ReportDataSource rds.Name = “DataSet1_DataTable1” rds.Value = miDataSet.Tables(0) Me.ReportViewer1.LocalReport.DataSources.Add(rds) Me.ReportViewer1.RefreshReport() End Sub Private Function CargarDatos() As DataSet Dim datos As New DataSet1 Using conexion As New SqlConnection() conexion.ConnectionString = ObtenerCadenaConexion() conexion.Open() Dim comando As New SqlDataAdapter(ObtenerSQL(), conexion) comando.Fill(datos.Tables(0)) comando = Nothing conexion.Close() End Using Return datos End Function

La carga de datos desde un DataSet a informes de Reporting Services nos abre nuevas vías para desarrollar aplicaciones que consuman informes

pos del informe, con el objetivo de presentarlos en pantalla. De esta manera, al ejecutar el código de nuestra demostración obtenemos un informe en pantalla, con los datos volcados desde un DataSet, tal y como se indica en la figura 6.

End Class

Fuente 1

La expresión con la que vamos a trabajar es la que se indica en la que indica a continuación: =iif( Fields!Color.Value is Nothing, "Transparent", Fields!Color.Value)

Una vez hecho esto, accederemos a la propiedad BorderStyle y modificaremos esta propiedad con otra expresión similar a la del caso anterior. En este caso, la expresión deberá ser la siguiente:

<<dotNetManía

=iif( Fields!Color.Value is Nothing, "None", "Solid")

24

Con esto, si el campo Color es diferente de nulo, colorearemos el fondo del color del campo y pondremos un

borde en el objeto insertado en la tabla para resaltarlo más aún. En este punto, lo único que nos queda es escribir el código de nuestro ejemplo.

Escribiendo el código de nuestra aplicación A continuación escribiremos el código de este ejemplo, que se presenta en el fuente 1. Nuestro ejemplo se conecta a la base de datos AdventureWorks, ejecuta la sentencia SQL para recoger los datos que nos interesan de la tabla Production.Product y los vuelca al DataSet que hemos diseñado al principio. Finalmente, asocia los datos del DataSet al control ReportViewer, quien enlaza los campos del DataSet con los cam-

Figura 6. Ejecución de la demostración

Conclusiones En este artículo hemos aprendido a cargar datos desde un DataSet a un informe de Reporting Services utilizando el control ReportViewer de Visual Studio 2005. Además, hemos visto cómo parametrizar datos o expresiones desde las propiedades de los objetos que forman parte de un informe. Este ejemplo nos abre diferentes vías para poder desarrollar aplicaciones que consuman informes y cuyos datos puedan variar según diferentes necesidades, pudiendo parametrizarlos o personalizarlos según las diferentes situaciones en que nos podamos encontrar.


dnm.plataforma.net

Yamil Hernández

Miguel Katrib

Atributos, aspectos y cómo entretejer código desde Visual Studio para hacer AOP en .NET (I) Con la Programación Orientada a Aspectos (Aspect Oriented Programming – AOP) se pretende que la funcionalidad del código principal de una aplicación y la funcionalidad adicional indicada en forma de “aspectos” puedan ser reusadas, modificadas y extendidas sin afectarse entre sí.

<< Podemos querer que, con independencia de su propia

Miguel Katrib Miguel Katrib es Dr.en Computación y Catedrático del Dpto.de Ciencia de la Computación de la Universidad de La Habana.Dirige el Grupo WEBOO dedicado a la enseñanza y desarrollo de la Orientación a Objetos y la Programación en la Web.Miguel es redactor de dotNetManía y asesor de programación y tecnología .NET para CARE Technologies S.A. Yamil Hernández es Instructor de Programación de la Cátedra de Programación e Ingeniería de Software del Dpto. de Ciencia de la Computación de la Universidad de la Habana.Yamil es desarrollador y programador del grupo WEBOO donde se dedica especialmente a la Programación Orientada a Aspectos, Metaprogramación y Reflexión. Es colaborador e ilustrador de dotNetManía.

lógica de negocio, un código se ejecute en un contexto seguro, se ejecute con tolerancia a fallos o pueda ser auditable. La AOP [2] pretende que aspectos adicionales como éstos puedan expresarse y lograrse sin que para ello haya que entrometerse en la lógica del código principal de la aplicación, orientado a la solución del problema que se quiere resolver. En un trabajo previo publicado en dotNetManía [1] hablamos de cómo hacer Programación Orientada a Aspectos basándonos en la posibilidad que brinda .NET de colocar metainformación dentro del código a través un recurso tan importante como son los atributos. Una propuesta de solución para hacer AOP en .NET ([3] y [4]) se basa en definir y “colocar” adecuadamente atributos .NET en el código para expresar “aspectos” que permitan incorporar propiedades y funcionalidades adicionales a la expresada por el código pero sin disturbar la funcionalidad principal de éste. Esto nos proporciona una adecuada modularidad sintáctica sin exigir cambios al lenguaje fuente y los compiladores. Como finalmente el comportamiento de una aplicación computacional termina manifestándose en su ejecución sobre un procesador, los aspectos deben también manifestarse en alguna forma de código que se ejecutará en conjunción con el código principal. En la terminología de la AOP se denomina “entretejer código” (code weaving) a hacer que en tiempo de ejecución la ejecución del código principal se entremezcle con la ejecución del código asociado a los aspectos. La AOP pretende que esto se logre con la mayor transparencia posible de cara al desarrollador

Una propuesta de solución para hacer AOP en .NET se basa en definir y “colocar” adecuadamente atributos .NET en el código

y satisfaciendo los objetivos de siempre: reusabilidad y modificabilidad. En [1] mostramos posibles soluciones para este efecto de “entretejido”. Éstas se basaban bien en usar los mecanismos de .NET para interceptar las llamadas a métodos y poder evaluar el código con aspectos, o en usar una herramienta que generase y colocase intermediarios (objetos proxy) en el código final; estos intermediarios interceptarían las llamadas a un método y ejecutarían la funcionalidad de los aspectos, según el tipo de aspecto. Sin embargo, estos enfoques presentan inconvenientes: para el primer caso, el mecanismo de intercepción de .NET es complicado de usar y añade un coste adicional de tiempo en ejecución; para el segundo caso, la colocación de los intermediarios exige el uso de una herramienta, lo cual no es cómodo para el desarrollador acostumbrado a hacerlo todo desde Visual Studio y a su organización de los proyectos.


<< dnm.plataforma.net En este artículo se verá cómo definir aspectos mediante atributos, cumpliendo de este modo con la sintaxis de los lenguajes .NET, cómo lograr la ejecutabilidad de estos aspectos indicando los puntos de corte desde el propio Visual Studio y cómo entretejer el código de los aspectos con el código principal de la aplicación haciendo que sea el entorno integrado el que haga este entretejido en tiempo de compilación. Para ello mostraremos cómo puede ser extendida la funcionalidad de Visual Studio 2005 utilizando el mecanismo de añadidos (add-ins) que éste ofrece [5].

Tipos de aspectos

método Advice define la funcionalidad del aspecto. En el caso de un aspecto BeforeAspect , el Advice se ejecutará antes de ejecutar el método llamado; en el caso de un aspecto AfterAspect, se ejecutará después de ejecutar el método llamado, y en el caso de un aspecto InsteadAspect, se ejecutará en lugar del método llamado. El cómo se relaciona con la interpretación que tienen los parámetros del método Advice en dependencia de cuándo se aplica: • El primer parámetro, target, indica al objeto receptor del método llamado y será null en el caso de un método estático. Note que entonces Advice tendrá sobre el objeto del método al se le ha colocado el aspecto la misma visibilidad que tiene cualquier cliente de la clase. • El segundo parámetro, target Method, de tipo MethodBase, denota al objeto de reflexión que describe al método cuyo aspecto va a ser evaluado. • El tercer parámetro, de tipo object[], es un array que recibirá los mismos parámetros que se le han pasado al método cuyo aspecto va a ser evaluado; es un

array de longitud cero en el caso de que sea un método sin parámetros. • Para el caso de aspectos de tipo AfterAspect, el método Advice tiene un cuarto parámetro, ref object result. Este parámetro recibirá el valor de retorno del método invocado (en caso de void, el valor es null). De este modo, el valor de retorno de un método puede ser utilizado en la funcionalidad del aspecto. • La ejecución del Advice de un aspecto de tipo InsteadAspect devuelve un valor de tipo object, que sería el sustituto del valor que devolvería el método original invocado. Note que de modo genérico el tipo devuelto es object; es responsabilidad del programador que el objeto que se devuelva sea realmente del mismo tipo que el que devuelve el método original, pues esto no puede ser verificado en tiempo de compilación. El diccionario AspectPool de la clase AspectAttribute servirá como almacén para guardar información global relacionada con los aspectos.

<<dotNetManía

Anders Hejlsberg, dando respuesta a algunas preguntas sobre AOP en MSDN TV, comenta sobre la dificultad de conocer cómo será la interacción dinámica entre los códigos (es decir, dónde entra un código a ejecutar, dónde sale…), y por tanto plantea su preocupación sobre la AOP como una disciplina de programación de dominio general. Coincidimos con estas preocupaciones. No debemos ver la AOP con la excentricidad de estar a la moda. Esto podrá ganarnos detractores, pero pensamos que es más acertado ver la AOP como un complemento al desarrollo de software orientado a objetos. Este artículo considerará tres categorías de aspectos, que están relacionadas con el dónde, cuándo y cómo interactúa la funcionalidad de los aspectos con la funcionalidad del código principal. El dónde es lo que se engloba bajo el concepto de la AOP conocido como punto de corte (point cut). En nuestra propuesta, los aspectos estarán asociados a un método (o a un tipo, si consideramos que esto significa a todos los métodos de dicho tipo). Con respecto al cuándo, se considerarán tres categorías de aspectos: aquellos cuya funcionalidad se aplica antes de ejecutar un método, los aspectos cuya funcionalidad se aplica después de ejecutar un método y, por último, los aspectos cuya funcionalidad puede suplantar la ejecución de un método. Estas tres categorías de aspectos se recogen en el código del fuente 1. El

27


<< dnm.plataforma.net private class AspectAttribute: Attribute { // pool para intercambio entre los aspectos public static Hashtable AspectPool = new Hashtable(); } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Interface, Inherited = true) public abstract class BeforeAspect: AspectAttribute { public abstract void Advice(object target, MethodBase targetMethod, params object[] parameters ); } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = true, AllowMultiple = false) public abstract class InsteadAspect: AspectAttribute { public abstract object Advice(object target, MethodBase targetMethod, params object[] parameters, ); } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Interface, Inherited = true) public abstract class AfterAspect: AspectAttribute { public abstract void Advice(object target, MethodBase targetMethod, params object[] parameters ref object result ); }

Si se quisieran auditar todas las llamadas a todos los métodos de un tipo B, entonces bastaría con asociar el aspecto LogBefore a la definición del tipo, sin tener que hacerlo para cada uno de sus métodos. [LogBefore ("Log.txt")] class B { ... public void H1(){...} public void H2(){...} }

El atributo LogBefore se definiría entonces como se muestra en el fuente 2. Note que en este caso, de los parámetros del método Advice, solo se ha usado el parámetro targetMethod, que es lo único que hace falta para seguir el rastro de los métodos que han sido llamados. public class LogBefore : BeforeAspect { private string path; public LogBefore (string path) { this.path = path; } public override void Advice(object targetObject, MethodBase targetMethod, params object[] parameters) { StreamWriter strm = File.AppendText(path); strm.WriteLine("Method " + targetMethod.Name + " began at: " + DateTime.Now); strm.Close(); } }

Fuente 2

Fuente 1

Ejemplo de BeforeAspect Supongamos una clase A: class A { //... public void F1(){...} public void F2(){...} }

<<dotNetManía

para la que se quieren auditar los momentos de comienzo de la ejecución del método F1. Para ello, decoramos el método con el aspecto LogBefore de tipo BeforeAspect, y especificamos la dirección y el nombre del fichero donde se guardará la información, en el ejemplo Log.txt.

28

class A { //... [LogBefore ("Log.txt")] public void F1(){...} public void F2(){...} }

Ejemplo de InsteadAspect En este ejemplo se define un aspecto que permite indicar que un método sea tolerante a fallos; es decir, que si durante la ejecución del método ocurriese una excepción, se vuelva a intentar la ejecución del mismo (hasta una determinada cantidad de veces, que puede fijar quien coloca el aspecto). De este modo, para indicar que el método F1 de A se intente ejecutar hasta 3 veces en caso de fallo y que el método F2 se intente ejecutar hasta 5 veces, se podrían decorar esos métodos con el aspecto FaultTolerant, como se muestra a continuación: class A{ //... [FaultTolerant(3)] public void F1(){...} [FaultTolerant(5)] public void F2(){...} }


<< dnm.plataforma.net Para lograr esto, el aspecto FaulTolerant se define como de tipo InsteadAspect (fuente 3). En este caso, el entretejido que se haga de un aspecto de tipo InsteadAspect con el código tiene que garantizar que cuando se haga una llamada como a.F1() no se ejecute el método F1, sino que en su lugar se ejecute el método Advice del aspecto FaultTolerant. Note que es dentro del método Advice donde se ejecuta realmente el método llamado ( F1 en este caso) cuando se hace targetMethod.Invoke(target,parameters). Es el entretejido que se hace el que provoca que sea el método Advice el que se llame en lugar del método original; esto permite capturar la excepción que devuelva la ejecución del método original (que se invoca mediante reflexión) y reintentar su ejecución. El tener aislado este patrón de reintento dentro de la funcionalidad del aspecto ilustra la separación de incumbencias y permite no replicar el mismo código en cada uno de los métodos que se quisieran hacer tolerantes a fallos.

class FaultTolerant: InsteadAspect { int times; public FaultTolerant(int times){ this.times=times; } public override object Advice( object target, MethodBase targetMethod, object[] parameters) { while(true) try { return targetMethod.Invoke(target,parameters); } catch (Exception e) { if (times == 0) throw e.InnerException; else times --; } } }

Para llevar un registro de los momentos en que finaliza la ejecución del método F1, se decora ahora el método con el aspecto LogAfter de tipo AfterAspect. class A { //... [LogBefore("Log.txt")] [LogAfter("Log.txt")] public void F1(){...} public void F2(){...} }

Note que el atributo LogAfter se define de igual forma que el LogBefore (fuente 4). Es el mecanismo de “entretejido” el que según el tipo de aspecto distingue si la funcionalidad (método Advice) se aplica antes o después de la ejecución del método.

public class LogAfter : AfterAspect { private string path; public LogAfter (string path) { this.path = path; } public override void Advice(object targetObject, MethodBase targetMethod, ref object result, params object[] parameters) { StreamWriter strm = File.AppendText(path); strm.WriteLine("Method " + targetMethod.Name + "begin at: " + DateTime.Now); strm.Close(); } }

Fuente 4

Fuente 3

El mismo ejemplo de llevar la traza del comienzo de la ejecución de un método nos sirve para ilustrar el uso de un atributo AfterAspect. Usando un aspecto de este tipo se podrá auditar cuándo termina la ejecución de un método. Sea la misma clase A del ejemplo de BeforeAspect. class A { //... public void F1(){...} public void F2(){...} }

Macros y add-ins no son una novedad en las herramientas de desarrollo. De hecho, las primeras versiones de Word y Excel ya tenían un lenguaje propio para la definición de macros, que luego fue sustituido por Visual Basic for Applications (VBA). Pero Visual Studio .NET (en lo adelante VS) tiene ahora probablemente la infraestructura más rica para el trabajo con macros y add-ins. Las macros son pequeños programas que permiten automatizar tareas repetitivas (ver un trabajo previo sobre macros en dotNetManía [6]). Pero si queremos hacer algo más que automatizar procesos repe-

<<dotNetManía

Ejemplo de AfterAspect

Extendiendo Visual Studio con un “Weaver Add-in” para hacer el entretejido

29


<< dnm.plataforma.net titivos debemos hacer uso de los add-ins. Un add-in es código compilado que se agrega directamente dentro del proceso de VS. Más que una simple automatización de tareas comunes, un add-in es una forma de enriquecer el IDE de VS. Para que VS pueda reconocerlo, éste debe implementar la interfaz IDTExtensibility2. Afortunadamente, VS ofrece un asistente que genera automáticamente las clases necesarias para la programación de un add-in, incluyendo una plantilla que hace posible que solo tengamos que rellenar con el código apropiado los métodos que hay que definir de esta interfaz: OnConnection, OnDisconnection, OnAddInsUpdate, OnStartupComplete y OnBeginShutdown. La clase generada por el asistente, además de implementar la ya mencionada interfaz IDTExtensibility2, implementa también la intefaz IDTCommandTarget, necesaria cuando se quiere trabajar con uno o más comandos nombrados (fuente 5). En este trabajo, los comandos que se han nombrado se llaman addPointCutCommand y removePointCutCommand (fuente 6). Para los métodos OnConnection, QueryStatus y Exec, el asistente genera un código de propósito general, que debe ser o no adaptado en dependencia de la funcionalidad que se vaya a programar. Al ejecutar un add-in, que a fin de cuentas es un proyecto .NET desarrollado con Visual Studio (figura 1, ventana 1), se levanta un nuevo proceso VS (figura 1, ventana 2). El add-in se ejecutará en este nuevo proceso, lo que permite depurar el código del add-in dentro del proceso original de VS, lo cual resulta muy útil durante el proceso de desarrollo del mismo. Una vez depurado el add-in, éste puede “instalarse”, quedando integrado dentro de VS .NET y extendiendo así su funcionalidad.

<<dotNetManía

Figura 1.VS 2 como resultado de la ejecución de VS 1

30

En el asistente para la creación de add-ins de VS se puede especificar en qué momento se desea que éste se cargue. Una de las posibles opciones es que se cargue al hacer clic sobre algún nuevo ítem de algún menú de VS. Por defecto, VS incluye los addins en el menú “Herramientas”, aunque hay una gran

public class Connect : IDTExtensibility2, IDTCommandTarget { public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) { //... } public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom) {} public void OnAddInsUpdate(ref Array custom) {} public void OnStartupComplete(ref Array custom) {} public void OnBeginShutdown(ref Array custom) {} public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText) { //... } public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled) {} }

Fuente 5

Microsoft.VisualStudio.CommandBars.CommandBar codeWindowMenu = ((Microsoft.VisualStudio.CommandBars.CommandBars) _applicationObject.CommandBars)["Code Window"]; try { Command command1 = commands.AddNamedCommand2(weaverAddInInstance, "addPointCutCommand", "Add PointCut", "Click here to add Point Cut", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); Command command2 = commands.AddNamedCommand2(weaverAddInInstance, "Click here to remove Point Cut", "Remove PointCut", "Executes the command for Weaver", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); command1.AddControl(codeWindowMenu, 1); command2.AddControl(codeWindowMenu, 2); } catch (System.ArgumentException) { }

Fuente 6


<< dnm.plataforma.net

Para la implementación del entretejido de aspectos se han añadido dos nuevos items al menú de contexto del editor de código de Visual Studio

flexibilidad para lograr añadirlos como items de cualquier menú de VS. Todos los menús presentes en VS están contenidos dentro de una colección CommandBars. Sobre esta colección se puede iterar para tener acceso a cada CommandBar. El siguiente código permite iterar sobre los menús:

<<dotNetManía

foreach (Microsoft.VisualStudio.CommandBars.CommandBar cb in (Microsoft.VisualStudio.CommandBars.CommandBars)_ applicationObject.CommandBars) //...

32

Para la implementación del entretejido de aspectos (que hemos denominado Weaver Add-in) se han añadido dos nuevos items al menú de contexto (el que aparece al pulsar con el botón derecho) del editor de código de VS .NET. El nombre de este menú es “Code Window”, y a él añadiremos dos nuevos items, “Add PointCut” y “Remove PointCut”, para que quede como se muestra en la figura 2. El código que se muestra en el fuente 6 añade al menú de contexto dos nuevas opciones, que podrán ser manipuladas como comandos nombrados (named commands). Un comando nombrado es una suerte de código funcional al que se le asocia un nombre, a través del cual aquél podrá ser accedido programáticamente o invocado directamente desde el propio IDE de Visual Studio. Prácticamente casi cualquier acción que un desarrollador puede ejecutar dentro del IDE se encuentra disponible en forma de un comando nombrado. Es fácil agregar items a un menú de contexto o a una barra de comandos haciendo uso del método AddNamedCommand2, que devuelve como resultado el nuevo comando que se ha creado. Los parámetros del método son: • AddInInstance: La instancia del add-in que está adicionando este nuevo comando. • Name: El nombre programático del nuevo comando (addPointCutCommand y removePointCutCommand en el código del fuente 6). Esta cadena es el nombre de comando que usará el resto del addin para identificarlo; por ejemplo, cuando se aplica el método Exec en el fuente 5. • ButtonText: El nombre que mostrará visualmente el comando si es un botón o un icono (“Add

PointCut” y “Remove PointCut” en el ejemplo del fuente 6). Tooltip: El texto de ayuda que se despliega cuando en el IDE se pasa con el puntero del ratón sobre el comando. MSOButton : Indica si el tipo de figura que muestra el nuevo comando es una “Office Picture” o el ID de un recurso de mapa de bits de 16x16 (pero no un icono). En el fuente 6 se ha pasado el valor true para indicar que no se usará un recurso de mapa de bits propio, sino uno de los que brinda VS por defecto. Si quisiéramos personalizar la imagen a mostrar para el comando habría que pasar false y embeber el mapa de bits como un recurso de nuestro proyecto. Bitmap: El ID del mapa de bits que se desea mostrar en el botón. En el fuente 6 se utiliza el valor 59, que representa al icono ☺, predeterminado para el asistente de VS. Para cambiarlo, luego de agregar el correspondiente mapa de bits como recurso al proyecto se debe utilizar el valor 1 como ID. ContextUIGUIDs: Define en entorno en que puede ejecutar el comando (modo de depuración, modo de diseño, etc.). vsCommandStatusValue: Valor de enumeración que define el estado del comando. Puede ser vsCommandStatusEnabled, vsCommandStatusInvi sible, vsCommandStatusLatched, vsCommandStatus Ninched, vsCommandStatusSupported o vsCommand StatusUnsupported. CommandStyleFlags: Valor de enumeración que define el estilo visual de cualquier interfaz de usuario añadida por el comando. Puede ser vsCommandStyleComboCaseSensitive, vsCommand StyleComboNoAutoComplete, sCommandStylePict, vsCommandStylePictAndText o vsCommandStyle Text. ControlType: Valor de enumeración que define el tipo del control que se agrega cuando la interfaz de usuario es creada. Puede ser vsCommand ControlTypeButton, vsCommandControlTypeDrop DownCombo, vsCommandControlTypeMRUButton o vsCommandControlTypeMRUCombo.


<< dnm.plataforma.net Hasta aquí, con el código del fuente 6 lo que se ha hecho es solo darle una apariencia visual al add-in, es decir, indicar dónde y cómo aparece éste dentro del IDE. Ahora nos resta darle funcionalidad al add-in, es decir, programar qué queremos que ocurra cuando éste se ejecute (cuando se seleccione uno de los items de menú asociados, en el caso del ejemplo que nos ocupa).

Colocando puntos de corte (point cuts) Figura 2. Estableciendo un punto de corte

if (commandName == "Weaver.Connect.addPointCutCommand) status = (vsCommandStatus) vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;

Figura 3. Eliminando un punto de corte

El código del add-in debe asegurar también que sólo se pueda poner un punto de corte en los lugares permitidos (en este trabajo hemos considerado que un punto de corte puede

se indica que el comando addPointCut Command está habilitado y soportado. Esto a su vez indicará a VS que invoque el método Exec cuando se haga clic en cualquiera de los nuevos comandos que se han añadido (en nuestro caso, addPointCutCommand o removePointCut Command). Lo primero que se suele hacer desde un add-in es acceder y manipular

En el caso de los atributos asociados a aspectos, queremos que la funcionalidad de los mismos quede “entretejida” en el código resultante de la compilación

<<dotNetManía

Una vez que la funcionalidad programada en el add-in se ha integrado a VS, podemos especificar los puntos de corte (point cut), o sea, dónde se llevará a cabo el entretejido de los aspectos representados mediante atributos .NET, sobre el código de nuestra aplicación. En la sección anterior vimos cómo se colocan dentro del IDE los comandos para poner y quitar puntos de corte; a continuación vamos a describir cómo implementar la funcionalidad que queremos que tengan estos comandos. El compilador de C# no genera código IL ejecutable para los atributos que se hayan colocado en el código fuente. Un atributo queda en cierto modo seriado dentro del ensamblado resultante, y permanece pasivo durante la ejecución de éste, salvo que el propio ensamblado, u otro que lo utilice, analice por reflexión el atributo y le de alguna interpretación. En el caso de los atributos asociados a aspectos, queremos que la funcionalidad de los mismos quede “entretejida” en el código resultante de la compilación, algo que hay que indicarle al compilador. Esto es lo que lograremos implementando la semántica de los comandos addPointCutCommand y removePointCutCommand. Por ejemplo, para indicar que se ponga un punto de corte a un método F1 mediante el decorado con los aspectos LogBefore y LogAfter, se usa el editor de VS, se da clic derecho y se selecciona la opción “Add PointCut” (figura 2), que se ha añadido al menú según lo explicado en la sección anterior. De manera similar se puede quitar un punto de corte (figura 3).

estar asociado únicamente a la entrada de un método). Es deseable, por tanto, que el menú de contexto del editor del IDE despliegue los correspondientes items de nombres “Add PointCut” o “Remove PointCut” solo cuando éstos sean aplicables, es decir, si el cursor se encuentra en cualquier punto del texto del código de un método. Para lograr lo anterior se implementarán los métodos Query Status y Exec de la interfaz IDTCommand Target. Cuando durante la ejecución de un add-in se añade un comando nombrado (o sea, cuando se ejecuta el método AddNamedCommand2, como ocurre en el fuente 6), VS invoca al método QueryStatus (fuente 5). Para establecer el estado del comando nombrado, que se identifica por el nombre pasado a través del parámetro commandName, se debe asignar un valor de la enumeración vsCommandStatus al parámetro pasado por referencia status . Por ejemplo, mediante:

33


<< dnm.plataforma.net public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled) { handled = false; if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault) { TextSelection selection = (TextSelection)_applicationObject.ActiveWindow.Selection; // get the starting point EditPoint Start = selection.TopPoint.CreateEditPoint(); // get the element under the cursor CodeElement element = _applicationObject.ActiveDocument. ProjectItem.FileCodeModel. CodeElementFromPoint(Start, vsCMElement.vsCMElementFunction);

un punto de corte. Para ello, mantiene un ArrayList de nombre aspectizedMethods . Esta información será usada al hacerse la compilación y el entretejido de los aspectos. La información sobre el lugar donde se ha colocado el punto de corte es extraída del editor de texto de Visual Studio, como se verá en la número siguiente.

Conclusiones

if (element.Kind == vsCMElement.vsCMElementFunction) { if (commandName == "Weaver.Connect.addPointCutCommand") { aspectizedMethods.Add(element as CodeFunction); selection.MoveToPoint(element. GetStartPoint(vsCMPart.vsCMPartHeader),false); } else if (commandName == "Weaver.Connect.removePointCutCommand") { aspectizedMethods.Remove(element as CodeFunction); selection.MoveToPoint(element. GetStartPoint(vsCMPart.vsCMPartHeader), false); } _applicationObject. ExecuteCommand("Edit.ToggleBookMark", string.Empty); } handled = true; } }

<<dotNetManía

}

34

algunos objetos de tipos definidos en el espacio de nombres EnvDTE que son recibidos como parámetros en OnConnection. Este método es llamado cada vez que el add-in es cargado por VS. Los objetos antes mencionados de EnvDTE pueden accederse a partir del objeto raíz de la extensibilidad de VS, que es pasado como primer parámetro de OnConnection como una instancia del tipo DTE, que representa al IDE del VS que está ejecutando. El segundo parámetro de OnConnection describe cómo el add-in ha sido cargado; las distintas formas en que esto puede ocurrir están enumeradas en el tipo ext_ConnectMode del espacio de nombres Extensibility. El tercer parámetro es una instancia de nuestro propio add-in, de tipo EnvDTE.AddIn, y el cuarto parámetro es un array vacío que puede usarse para guardar y pasar información local específica del add-in. En el método Exec (fuente 7) debe implementarse lo que queremos que ocurra al ejecutar alguno de los comandos nombrados, o sea, hacer clic sobre el ítem que hemos añadido al menú de contexto. En este caso, el método Exec lleva un control sobre aquellos métodos a los que se les ha colocado (o quitado)

El modelo de extensibilidad de Visual Studio nos permite enriquecer mediante add-ins el entorno de desarrollo con nuevas funcionalidades. Esta primera entrega no ha pretendido ser un tutorial sobre add-ins, pero ha mostrado cómo usar los mismos para indicar dónde colocar los puntos de corte y cómo dejar esta información almacenada para que pueda ser utilizada por el compilador. Queda por ver cómo hacer que el add-in entreteja el código antes de la compilación para lograr que el código resultante de la compilación lleve a cabo en ejeFuente 7 cución la funcionalidad expresada mediante los atributos que han sido utilizados en calidad de aspectos. Este será el objeto de la segunda parte de este artículo.

Referencias

[1]

Kiczales, Gregor et al “Aspect Oriented Programming”, Springer Verlag, Proceedings of ECOOP 1997.

[2]

Hernández, Yamil y Katrib, Miguel “Aspectos e intercepción de métodos en .NET”, publicado en dotNetManía nº 10, diciembre de 2004.

[3]

Katrib, Miguel y Hernández, Yamil “Aspectos en .NET: Una propuesta basada en atributos”, Ideas 2005.

[4]

Katrib, Miguel y Hernández, Yamil “Aspect Oriented Programming in .NET based in Attributes“, aceptado para su publicación en JOT, marzo de 2007.

[5]

Smith, Les “Writing Add-Ins for Visual Studio .NET”, APress, 2002.

[6]

Quintero, Carlos “Macros en Visual Studio 2005”, publicado en dotNetManía nº 26, mayo de 2006.


dnm.inicio.fundamentos dnm.incio.taller

Guillermo “Guille” Som

Parámetros personalizados en los eventos En este cuarto artículo dedicado a los delegados y eventos nos centraremos en cómo comunicarnos entre la clase que define los eventos y la que los intercepta.Veremos esa comunicación de dos formas diferentes, usando parámetros por referencia y de la forma recomendada, que es definiendo nuestra propia clase para usar como parámetro de los eventos.También abordaremos una característica exclusiva de C#,que es la posibilidad de usar clases base como parámetros de los métodos que reciben los eventos.

Hasta ahora hemos estado usando los eventos de la forma habitual: para comunicarle a la aplicación receptora que algo ha ocurrido, y en esa comunicación solo hemos usado una vía, de forma que la clase que produce el evento “informe” de qué es lo que está ocurriendo, información que enviamos con los parámetros pasados al método receptor. Pero, ¿cómo podemos hacer que la aplicación receptora (el cliente) pueda comunicarse con la clase que produce el evento (el servidor), por ejemplo, para cancelar una acción o para pasarle cierta información?

Usando parámetros por referencia en los eventos

Guillermo “Guille” Som Es Microsoft MVP de Visual Basic desde 1997. Es redactor de dotNetManía, mentor de Solid Quality Iberoamericana, tutor de campusMVP, miembro de Ineta Speakers Bureau Latin America, y autor de los libros “Manual Imprescindible de Visual Basic .NET” y “Visual Basic 2005”. http://www.elguille.info

En principio, esto es algo sencillo de realizar, ya que lo único que tenemos que hacer es declarar por referencia uno (o varios) de los parámetros. De esta forma podemos asignar un valor a ese parámetro y usarlo en la clase que produce el evento. Por ejemplo, si tenemos el evento usado en los ejemplos de los artículos anteriores que avisa del cambio en el valor de una propiedad, podemos agregar un tercer parámetro para indicar si cancelamos dicha asignación. En el código del fuente 1 vemos cómo definir el delegado, el evento y la propiedad, que tiene en cuenta esta nueva posibilidad de cancelar la asignación, dato que sabremos si la aplicación cliente devuelve un valor verdadero en la variable usada para el tercer parámetro. Como es de esperar, el método de la clase cliente que recibe la notificación de que el evento se ha producido debe tener la misma “firma” que el dele-

public delegate void NombreCambiadoEventHandler( string nuevo, string anterior, ref bool cancelar); public event NombreCambiadoEventHandler NombreCambiadoRef; private string m_Nombre; public string Nombre { get { return m_Nombre; } set { // Lanzar el evento // indicando el nuevo valor y el anterior, // además de la variable para saber si cancela if( NombreCambiadoRef != null ) { bool cancelado = false; NombreCambiadoRef(value, m_Nombre, ref cancelado); if( cancelado ) { // Lo que haya que hacer para avisar // que se ha cancelado la asignación return; } } m_Nombre = value; } }

Fuente 1. Definición de un evento que permite cancelar la acción

gado, incluyendo el parámetro por referencia y, como es natural, podemos ignorar dicho parámetro o asignarle un valor verdadero en el caso de que queramos cancelar la asignación. En el código del fuente 2 cancelamos esa asignación si el nuevo valor es una cadena vacía o la longitud de la misma es inferior a 3 caracteres.

<<dotNetManía

<< Comunicarse con la clase que produce el evento

35


<< dnm.inicio.taller static void cli_NombreCambiadoRef( string nuevo, string anterior, ref bool cancelar) { // Cancelamos la acción si el nuevo valor no // cumple las condiciones que estimemos oportunas if( string.IsNullOrEmpty(nuevo) || nuevo.Length < 3 ) { Console.WriteLine( “cancelando... debe tener más” + “ de 2 caracteres...”); cancelar = true; } }

Fuente 2. El método que recibe el evento puede cancelar la asignación

Hay que aclarar que esa comprobación que hacemos en el lado del cliente en realidad la podíamos hacer en la propiedad, pero de lo que aquí se trata es de ver un ejemplo de cómo cancelar (o informar a la clase que ésa es nuestra intención), no de la solución mágica a todos nuestros problemas. Además, al hacerlo en el lado del cliente, esto nos da la posibilidad de que cada aplicación que use esa clase decida la comprobación que debe hacer. Por ejemplo, si la propiedad fuera una contraseña, el cliente podría validar si cumple ciertos requisitos impuestos por la aplicación.

Usando clases como parámetro de los eventos Si necesitamos pasar más datos (ya sean por valor o por referencia), tendremos que indicar más parámetros en la definición del delegado asociado con el evento, y aunque eso no es ningún problema, .NET nos permite una forma más elegante de hacerlo: usando un tipo personalizado como parámetro, es decir, una clase. Es más, el propio .NET Framework tiene una clase que podemos usar para estos menesteres: EventArgs. De hecho, todos los eventos de los controles del espacio de nombres Windows.Forms se basan (o se derivan) de esa clase; por tanto, podemos hacer lo mismo que hace el entorno en el que estamos programando, y crear nuestra propia clase basada en EventArgs. De esa forma también nos resultará más cómodo pasar (y recuperar) datos en ambos sentidos, con lo que de camino nos ahorramos la definición de parámetros por referencia, que entre otras cosas, no son deseables, al menos a la hora de dar claridad a nuestro código.

vo valor a la propiedad. Las otras dos, las que indican los valores nuevo y anterior, serán de solo lectura, ya que lo único que le interesa al método receptor del evento es saber qué valores contienen, y como son valores directamente relacionados con una propiedad de una clase, no deberíamos manipularlos, ya que si lo hacemos nos estaríamos saltando a la torera uno de los pilares de la programación orientada a objetos: la encapsulación. Pero... como somos los diseñadores de la clase, podemos hacer lo que mejor nos parezca, aunque no voy a ser yo el que incite a esa decisión. Las dos propiedades que vamos a exponer como de solo lectura las vamos a definir con los dos bloques de código que habitualmente tienen todas las propiedades, que como sabemos son el bloque get, que nos permite obtener el valor de la propiedad, y el bloque set, que es el usado cuando asignamos el valor. Para dar esa funcionalidad de solo lectura a pesar de definir el bloque set, vamos a usar la nueva característica de .NET Framework 2.0 que nos permite cambiar el ámbito (o visibilidad) de uno de los bloques de las propiedades (ver el número 20 de dotNetManía). De esta forma, la clase expondrá públicamente solo el bloque get, y el bloque set lo dejaremos como internal (Friend en Visual Basic) para que solo podamos usarlo desde el propio ensamblado. En el código del fuente 3 vemos la definición de la clase DatosCambiadosEventArgs, que es la que usaremos como parámetro del delegado y el evento definidos en la clase Cliente (ver el fuente 4). Ambas clases están definidas en una biblioteca de clases, que tendremos que añadir a las referencias del propublic class DatosCambiadosEventArgs : EventArgs { // Propiedad de solo lectura cuando se accede // desde fuera del propio ensamblado private string m_Nuevo; public string Nuevo { get { return m_Nuevo; } internal set { m_Nuevo = value; } } // Propiedad de solo lectura cuando se accede // desde fuera del propio ensamblado private string m_Anterior; public string Anterior { get { return m_Anterior; } internal set { m_Anterior = value; } }

<<dotNetManía

Crear clases para usar como parámetro de un evento

36

Para mantener las cosas sencillas, vamos a crear una clase que usaremos como parámetro de los eventos. Esta clase tendrá la misma funcionalidad que la mostrada en el código del fuente 1; es decir, la clase tendrá tres propiedades, dos de solo lectura y la tercera de lectura/escritura, ya que será la usada para saber si se quiere cancelar la acción de asignar un nue-

private bool m_Cancelar; public bool Cancelar { get { return m_Cancelar; } set { m_Cancelar = value; } } }

Fuente 3. La definición de la clase basada en EventArgs


<< dnm.inicio.taller

public class Cliente { public delegate void DatosCambiadosEventHandler( DatosCambiadosEventArgs e);

yecto en el que definimos la clase que interceptará los eventos y añadir la importación correspondiente del espacio de nombres que las contiene. Una vez hecho eso, la podremos usar tal como vemos en el código fuente 5.

public event DatosCambiadosEventHandler NombreCambiado;

Fuente 4. Parte de la clase Cliente en la que se definen los eventos que usan la clase definida en el fuente 3

static void cli_NombreCambiado(DatosCambiadosEventArgs e) { if( string.IsNullOrEmpty(e.Nuevo) || e.Nuevo.Length < 3 ) { Console.WriteLine(“ cancelando... debe tener” + “ más de 2 caracteres...”); e.Cancelar = true; // Si la clase que define el parámetro // está en otro ensamblado // esta propiedad será de solo lectura //e.Nuevo = “Miguel”; } }

Fuente 5. El método que intercepta el evento definido en el fuente 4

Definir la clase del evento en el mismo ensamblado que el cliente Si en lugar de crear un ensamblado para las clases (la que produce el evento y la que define el parámetro de dicho evento) decidimos que estén todas en el mismo ensamblado (proyecto), el hecho de proporcionar ámbitos diferentes a los bloques set de las dos propiedades que queremos que sean de solo lectura no nos soluciona la papeleta, ya que al estar declarados esos bloques con internal, serán accesibles desde cualquier parte del mismo ensamblado, y por tanto también desde el código de la aplicación cliente. Por lo tanto, en estos casos es preferible optar por la forma “recomendada” de definir esas propiedades como de solo lectura, y para poder asignarles el valor que tendrán lo haremos por medio de un constructor parametrizado. De esta forma, desde el constructor podremos asignar los valores correspondientes a los campos privados que siempre definimos para cada propiedad. En el código del fuente 6 tenemos la definición de la clase usada como parámetro de los eventos. En el código del fuente 6 también podríamos haber usado la característica de tener diferentes niveles de accesibilidad en las propiedades, pudiendo definir

class DatosCambiadosEventArgs : EventArgs { public DatosCambiadosEventArgs( string nuevo, string anterior) { m_Nuevo = nuevo; m_Anterior = anterior; } private string m_Nuevo; public string Nuevo { get { return m_Nuevo; } } private string m_Anterior; public string Anterior { get { return m_Anterior; } } private bool m_Cancelar; public bool Cancelar { get { return m_Cancelar; } set { m_Cancelar = value; } } }

Fuente 6. Definición de la clase basada en EventArgs usando un constructor con parámetros

<<dotNetManía

private string m_Nombre; public string Nombre { get { return m_Nombre; } set { // Lanzar el evento // indicando el nuevo valor y el anterior if( NombreCambiado != null ) { // Declaramos un objeto del tipo de la clase // usada para usar como parámetro del evento. DatosCambiadosEventArgs e = new DatosCambiadosEventArgs(); e.Cancelar = false; // Desde el propio ensamblado podemos acceder // al bloque set de las propiedadades Nuevo // y Anterior e.Nuevo = value; e.Anterior = m_Nombre; // Lanzamos el evento usando como argumento el // objeto creado a partir de la clase. NombreCambiado(e); // Comprobar si se cancela la asignación if( e.Cancelar ) { // Lo que haya que hacer para avisar // que se ha cancelado la asignación return; } } m_Nombre = value; } } // No mostrado el resto de la definición de la // clase Cliente

37


<< dnm.inicio.taller como private el bloque set, ya que solo necesitaríamos accederlo desde la propia clase que lo define, impidiendo de esa forma que se pueda asignar un valor desde fuera de la clase.

Métodos de apoyo para producir los eventos Otra de las recomendaciones que atañen a los eventos que tenemos definidos en una clase (o tipo), es la de crear un método (habitualmente definido como protegido) que sea el que en realidad se encargue de producir el evento. De esa forma, cuando queramos lanzar un evento, en lugar de hacerlo directamente usaremos ese método, al que le pasaremos los parámetros correspondientes y será el encargado de producir el evento. La razón de hacerlo así, y la de definir esos métodos como protected (protegidos) es para que desde las clases derivadas tengamos una forma fácil de producir los eventos que define la clase base sin necesidad de escribir todo el código que necesitemos cada vez que tengamos que producir un evento. La nomenclatura recomendada para este tipo de métodos es que tenga el mismo nombre que el evento, pero empezando con On; en el caso del evento NombreCambiado, ese método se llamará OnNombreCambiado. Esos métodos de apoyo también suelen ser de tipo void (no devuelven un valor), pero en el ejemplo que estamos usando a lo largo de este artículo podemos hacer que devuelva un valor de tipo bool, de forma que nos indique si se cancela o no la asignación de la propiedad. El hacerlo así es porque es preferible que devuelva un valor verdadero o falso en lugar de usar un parámetro por referencia. Para que tengamos las cosas claras, en el código del fuente 7 podemos ver la definición del método de apoyo para el evento NombreCambiado, además de ver cómo podemos usar ese método desde el bloque set de la propiedad Nombre. Recordemos que el método de apoyo OnNombre Cambiado devuelve un valor de tipo bool porque eso es lo que necesitamos, ya que desde la propiedad tenemos que saber si se cancela o no la asignación del nuevo valor. En el código completo que acompaña al artículo, la propiedad Apellidos también utiliza un método para lanzar el evento, pero en ese caso el valor de la propiedad Cancelar se ignora; por tanto, el método está declarado como void (Sub en Visual Basic), ya que no necesita devolver nada.

Eventos definidos en clases para usarlas en formularios

<<dotNetManía

Todos los eventos de los controles de Windows. Forms siempre tienen dos parámetros: el primero hace

38

referencia al objeto que produce el evento (el control) y el segundo contiene la información sobre el evento (normalmente una clase derivada de EventArgs). Si no ha de proporcionar ninguna información, este último

public string Nombre { get { return m_Nombre; } set { // Lanzar el evento // indicando el nuevo valor y el anterior. if( NombreCambiado != null ) { // Usamos el método de apoyo para lanzar el evento if( OnNombreCambiado(value, m_Nombre) ) { // Lo que haya que hacer para avisar // que se ha cancelado la asignación Console.WriteLine( “ Cancelado el nuevo “ + “nombre: {0}.”, value); return; } } m_Nombre = value; } } // Si vamos a usar un método de apoyo para lanzar // el evento y vamos a tener en cuenta la propiedad // Cancelar el método debería devolver el valor de // cancelación protected bool OnNombreCambiado(string nuevo, string anterior) { DatosCambiadosEventArgs e = new DatosCambiadosEventArgs(nuevo, anterior); e.Cancelar = false; NombreCambiado(e); return e.Cancelar; }

Fuente 7. Definición y uso de un método de apoyo desde el que lanzamos el evento

parámetro se define del tipo base EventArgs, pero siempre se utiliza, más que nada para dar “consistencia” a la forma de declarar los eventos. Sabiendo esto, debemos hacer un par de aclaraciones. La primera es que si nosotros definimos una clase basada en cualquier control, con idea de poder usarla en los formularios, y añadimos nuevos eventos, e incluso creamos nuestra propia clase para definir los parámetros de esos eventos, a la hora de producir el evento debemos tener en cuenta que el primer parámetro del delegado asociado a ese evento (y por tanto del método que recibe la notificación) es de tipo object, y representa al control que produce el evento. Como somos nosotros los que hemos definido esa clase, y desde ella lanzamos el evento, ese primer parámetro debe hacer referencia a la propia clase que produce el evento. Por otra parte, el segundo parámetro es de la clase que usamos para dar información al receptor del evento sobre lo que debe tener en cuenta en relación con ese evento que acaba de producirse; y aquí es cuando entra la segunda aclaración, ya que para ser “consistentes” con la forma de definir y usar los eventos en los formularios, nuestros eventos también deben tener siempre un segundo parámetro


<< dnm.inicio.taller

// El delegado para el evento TextoCambiado public delegate void DatosCambiadosEventHandler( object sender, DatosCambiadosEventArgs e); public event DatosCambiadosEventHandler TextoCambiado; protected bool OnTextoCambiado(string nuevo, string anterior) { DatosCambiadosEventArgs e = new DatosCambiadosEventArgs(nuevo, anterior); e.Cancelar = false; TextoCambiado(this, e); return e.Cancelar; }

Fuente 8. El evento DatosCambiados aplicado a una clase derivada de TextBox

En nuestro caso, el evento TextoCambiado será equivalente al evento TextChanged definido en la clase base ( TextBox ) de nuestro control, evento que nosotros aprovechamos para saber cuándo se produce un cambio en el texto. Y para saber cuándo se produce el evento, podemos usar el método asociado al evento que la propia clase base TextBox define: OnTextChanged. Aunque dentro de ese método no hagamos nada en especial (salvo que queramos volver a asignar el texto que ya hubiera de antes), debemos hacer la llamada al evento TextoCambiado para que el cliente se entere de que se está cambiando el texto, y antes de llamar al método OnTexto Cambiado hay que seguir haciendo la comprobación de que en realidad alguien está interceptando el evento, así evitamos los problemas que comento en el cuadro “De la importancia de comprobar en C# si se interceptan los eventos”. En el código del fuente 9 podemos ver cuál podría ser el código del método OnTextChanged, que es más extenso en el código incluido en el ZIP que acompaña al artículo, para que veamos otras posibilidades relacionadas con lo que podemos hacer si el cliente cancela la acción. Aunque ese cambio también se puede producir al asignar directamente el texto. Por tanto, en la propiedad Text también hacemos la correspondiente comprobación, tal como podemos ver en el código del fuente 10.

protected override void OnTextChanged(EventArgs e) { // Si no hacemos esta comprobación, // no podremos agregar el control al formulario. if( TextoCambiado != null ) { // Lanzar el evento, aunque no hagamos nada, por // tanto tampoco hace falta saber si se cancela o no OnTextoCambiado(this.Text, m_Text); } // Dejamos que la clase base termine de procesar // el evento base.OnTextChanged(e); }

Fuente 9. El código del método protegido OnTextChanged

public override string Text { get { return base.Text; } set { if( TextoCambiado != null ) { if( OnTextoCambiado(value, base.Text) ) { return; } } m_Text = value; base.Text = value; } }

Fuente 10. En la propiedad Text del control también comprobamos si se debe aceptar el cambio

Y ya que estamos con un control personalizado, comentar que podemos usar el atributo Default EventAtribute para indicar cual será el evento predeterminado de la clase. En nuestro caso, será el evenDe la importancia de comprobar en C# si se interceptan los eventos Como hemos estado viendo en los ejemplos de esta serie de artículos, cada vez que en C# queremos lanzar un evento, siempre debemos comprobar si ese evento se está interceptando (comprobamos si el evento no es nulo).Tal comprobación no es necesario hacerla en Visual Basic, y esta nota de advertencia va especialmente dirigida a los que antes programaban con Visual Basic (para .NET o anterior) y también para aquellos que quieren empezar a trabajar con C#,ya que si no hacemos esa comprobación y no se está interceptando el evento, será en tiempo de ejecución cuando recibamos el error de que el objeto no está creado; pero la información que recibiremos no será demasiado aclaratoria. Por ejemplo, si ese evento se produce en una clase derivada como es el caso de MiTextBox,y se intenta lanzar (sin antes comprobar si se está interceptando) en el método OnTextChanged, esto impedirá incluso que ese control lo podamos agregar a un formulario en tiempo de diseño. El diseñador de Windows Forms simplemente producirá un error de que hacemos referencia a un objeto no inicializado y, con suerte (haciendo el trabajo manualmente),detectaremos que el causante de ese error es la propiedad Text. En el código de ejemplo que acompaña a este artículo encontrarás una versión “errónea” del control MiTextBox.

<<dotNetManía

derivado del tipo EventArgs; si no es necesario proporcionar información extra, al menos debemos usar la propia clase base. En el código del fuente 8 vemos la definición del método asociado al evento de una clase derivada de TextBox que produce el evento TextoCambiado (el equivalente a DatosCambiados que hemos estado viendo hasta ahora).

39


<< dnm.inicio.taller to que acabamos de definir, tal como vemos en el código del fuente 11. De esa forma, al hacer doble clic en el control, se generará automáticamente ese evento.

[DefaultEvent(“TextoCambiado”)] public class MiTextBox : TextBox {

Fuente 11. Indicar que evento es el que usará el diseñador de formularios como evento predeterminado

Usar parámetros de la clase base en los métodos que reciben eventos

<<dotNetManía

Tal como vimos en el artículo dedicado a los delegados (dotNetManía nº 30), una de las novedades de C# 2.0 es permitir (por medio de la contravarianza) usar en los delegados parámetros de la clase base del tipo realmente definido en el delegado. Por ejemplo, el delegado que usamos en el evento TextoCambiado tiene definido un parámetro del tipo Datos CambiadosEventArgs que se deriva de EventArgs; pues bien, el método que intercepta ese evento lo podemos definir usando como parámetro o un tipo DatosCambiadosEventArgs o de cualquiera que esté en la jerarquía de esa clase, en nuestro caso, el tipo EventArgs (y por extensión el tipo Object ), con lo cual podemos hacer algo como lo mostrado en el código del fuente 12.

40

Esto mismo es aplicable al resto de eventos, y no solo a los que nosotros definamos. Por ejemplo, podemos interceptar el evento MouseMove tal como vemos en el fuente 13.

ciado con ese método no tiene la misma firma que el definido en el evento. En realidad, lo que hay detrás de esa nueva característica de los eventos “enrutados” de los controles que usaremos en nues-

//private void btnAsignar_MouseMove(object sender, MouseEventArgs e) private void btnAsignar_MouseMove(object sender, EventArgs e) { MouseEventArgs e2 = (MouseEventArgs)e; label1.Text = e2.X + “, “ + e2.Y; }

Fuente 13. Con el resto de eventos también podemos usar las clases base como parámetro del método

Como ya comentamos en su momento, esto no está permitido en Visual Basic ni en las versiones anteriores de C#. Y lo hemos querido aclarar (tanto que en Visual Basic no se puede hacer como que en C# 2.0 sí se puede), porque ahora que desde el pasado mes de noviembre está disponible la nueva versión 3.0 de .NET Framework (antes conocido como WinFX), al interceptar los eventos producidos en los controles usados en Windows Presentation Foundation (lo que antes se conocía como Avalon), en realidad el parámetro de esos eventos suele estar derivado de RoutedEventArgs, y es muy común que al estar acostumbrados a crear métodos que interceptan eventos en los controles definidos en Windows.Forms queramos seguir usando el parámetro EventArgs. Si usamos ese tipo de parámetro en vez del “correcto”, en C# no pasará nada y todo funcionará bien, pero en Visual Basic recibiremos un error indicándonos que el evento aso-

void miTextBox1_TextoCambiado(object sender, EventArgs e) { DatosCambiadosEventArgs e2 = (DatosCambiadosEventArgs)e; if( string.IsNullOrEmpty(e2.Nuevo) || e2.Nuevo.Length < 4 ) { label1.Text = “¡¡¡ Debes escribir más de tres caracteres !!!”; label1.Text += “\nAnterior: “ + e2.Anterior; e2.Cancelar = true; } else { label1.Text = miTextBox1.Text; } }

Fuente 12. Podemos definir métodos que usen parámetros de clases base del parámetro que el delegado define

tros proyectos XAML no es tan simple como la forma de usarlos, pero ese es otro tema.

Conclusiones Con este artículo damos por finalizado, al menos por ahora, el tema de los delegados y eventos que hemos estado tratando desde hace tres números. Por supuesto, confiamos que todo lo comentado haya servido para dar al lector una visión clara de cómo usar los eventos y los delegados, al menos desde el punto de vista de la relación tan estrecha que tienen con los eventos. A pesar de que lo habitual en esta sección de la revista es que el código mostrado y el lenguaje usado sea C#, el número anterior lo dedicamos completamente a Visual Basic, ya que en ese artículo nos centramos en una instrucción exclusiva de la versión 2005 de ese lenguaje. Con esto quiero aclarar que no es que no tengamos en cuenta a los programadores de Visual Basic en esta sección de inicio, ya que como suele ser costumbre, el código que acompaña a estos artículos siempre incluye los ejemplos en ambos lenguajes (al menos cuando hay equivalencia, ya que en ocasiones, algunas de las cosas mostradas solo se pueden hacer en uno de los dos lenguajes). Pero la intención siempre es mostrar los fundamentos de la programación en .NET, y será cosa del lector decidir con qué lenguaje pone en práctica esa información, y siempre intentamos que todo quede explicado de una manera suficientemente clara, cualquiera que sea el lenguaje que el lector decida usar.


dnm.plataforma.net

José Luis Quintero

Una mirada a WPF/E WPF/E (Windows Presentation Fundation Everywhere) se nos presenta como un subconjunto de WPF. Este subconjunto ha sido seleccionado con la intención de proporcionarnos diversas funcionalidades que permitirán la creación de entornos visuales ricos en nuestras páginas; tales entornos eran impensables hasta el momento, mediante la utilización únicamente de HTML.

<< La reciente CTP (Community Technology Preview) de diciembre de 2006 nos muestra numerosas ventajas, como son las animaciones de gráficos vectoriales en 2D y la reproducción de vídeo y audio. Y la forma de poder representar este mundo de animaciones y sonido en nuestros navegadores se nos presenta en forma de plug-in; en esta versión preliminar son varios los navegadores soportados además del Internet Explorer 6 y 7, como Firefox o Safari; incluso es posible ejecutarlo sobre Mac y PowerPC. WPF/E se nos presenta actualmente como una alternativa para crear diversos elementos en nuestras páginas que proporcionarán un valor añadido a nuestro código HTML. Ambos mundos pueden convivir ya que siguen una misma filosofía. En la actualidad accedemos a los elementos de HTML mediante Javascript, ya que estos elementos son enviados al cliente en texto plano; del mismo modo, WPF/E nos brinda esta oportunidad, dotándonos de la potencia de poder acceder a sus elementos XAML desde Javascript.

Iniciándonos en WPF/E

José Luis Quintero es consultor senior de Matchmind.Actualmente responsable del Centro de Alto Rendimiento (CAR.NET) en Tecnología Microsoft. Miembro activo de la comunidad con su sitio Web http://www.elquintero.net

Primeramente crearemos un sencillo ejemplo mediante el que mostraremos paso a paso cómo podemos incorporar el plug-in de WPF/E en nuestras páginas y hacer uso del mismo. Nuestro ejemplo constará de una simple pelota que irá rebotando en los bordes de nuestro control; para ello, utilizaremos un documento XAML que definirá dos imágenes, una de fondo y otra que representará la pelota en cuestión. Gracias a la utilización de Javascript, podremos interactuar con las propiedades de nuestra pelota.

Aunque en la actualidad Microsoft nos provee de unas plantillas para la creación de proyectos WPF/E (incluidas junto al CTP SDK –ver figura 1–), las cuales nos abstraen de todas las interioridades no vinculadas con la funcionalidades propias de nuestra aplicación, en este artículo intentaremos desvelar algunas de éstas y profundizar en ellas, ya que eso nos proporcionará una visión más detallada.

Figura 1. Nuevo proyecto WPF/E Javascript Application

Para comenzar, crearemos un proyecto Web clásico mediante la plantilla “ASP.NET Web Site”. En este proyecto web incluiremos, mediante “Add New Item”, un fichero XML que renombraremos como XAML (si dispone de las extensiones Orcas Development Tools, que nos permiten trabajar con ficheros XAML, podrá disfrutar de Intellisense). Una vez creado este fichero, incluiremos el código mostrado en el fuente 1.


1 <Canvas xmlns=”http://schemas.microsoft.com/client/2007” 2 xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” 3 Loaded=”javascript:MoverPelota”> 4 <Image Source=”resources/FondoPelota.png” Width=”500” Height=”400” /> 5 <Image x:Name=”Pelota” Source=”resources/Pelota.png” Width=”58” Height=”56” /> 6 </Canvas>

Fuente 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

var x=250; var y=200; var xpos=1;var ypos=1; var velocidad=1; function MoverPelota() { x+=velocidad*xpos; y+=velocidad*ypos; var wpfe = document.getElementById(“Controlwpfe”); var(imgPelota = wpfe.findName(“Pelota”)) if (x>wpfe.width-imgPelota.width) xpos=-1; if (x<14) xpos=1; if (y>wpfe.height-imgPelota.height) ypos=-1; if (y<0) ypos=1; imgPelota[“Canvas.Left”] = x; imgPelota[“Canvas.Top”] = y; window.setTimeout(“MoverPelota()”, 10); }

Fuente 2 1 <object 2 id=”WpfeControl” 3 width=”100” 4 height=”100” 5 classid=”CLSID:32C73088-76AE-40F7-AC40-81F62CB2C1DA”> 6 7 <param name=”BackgroundColor” value=”#ffebcd” /> 8 <param name=”SourceElement” value=null /> 9 <param name=”Source” value=”Ejemplo.xaml” /> 10 <param name=”WindowlessMode” value=”true” /> 11 <param name=”MaxFrameRate” value=”30” /> 12 <param name=”OnError” value=”myErrorHandler” /> 13 </object>

Fuente 3 ... 1 <head> 2 <title>Una mirada a “WPF/E”</title> 3 <script type=”text/javascript” src=”js/aghost.js”></script> 4 <script type=”text/javascript” src=”js/scriptPelota.js”></script> 5 </head> 6 <body> 7 <div id=”wpfeControl1Host”> 8 <script type=”text/javascript”> 9 var ag = new agHost(“wpfeControl1Host”,// Elemento HTML que posicionará // nuestro control // ID del Control ActiveX de WPF/E que creamos 10 “Controlwpfe”, 11 “487”,”400”, // Ancho y alto del control 12 “white”, // Color de fondo // Nombre de etiqueta de script que contiene el XAML 13 null, 14 “pluginPelota.xaml”, // Archivo fuente // IsWindowless false - fondo transparente 15 “false”, 16 “30”, // Especifica el número máximo de frames por segundo // Especifica la función de gestión de errores 17 null); 18 </script> 19 </div> 20 </body> ...

Fuente 4

En este código podemos observar, aparte de los establecimientos de espacios de nombres, la declaración de dos imágenes que se encuentran ubicadas en nuestro directorio resources . También podemos destacar la llamada al método MoverPelota en el momento de la finalización de la carga del documento; este método será el encargado de acceder a las propiedades de nuestra imagen y dotarla del movimiento que esperamos. El código de dicho método podemos verlo en el fuente2. Como se puede observar, gracias a la definición de los identificadores creados en el documento XAML (x:Name="Pelota") podremos acceder a nuestros elementos desde Javascript en tiempo de ejecución. Una vez creados tanto el fichero XAML como el fichero Javascript que nos dotará de la funcionalidad de movimiento, pasaremos a definir los elementos necesarios en nuestra página para que pueda ser mostrado nuestro control WPF/E. Junto a las plantillas de creación de proyectos WPF/E Microsoft nos proporciona un fichero Javascript ( aghost.js , incluido en el SDK), el cual se encarga de la identificación del navegador del cliente y de tomar la decisión sobre cómo incrustar nuestro control. En el caso de Internet Explorer, esto se realiza mediante la etiqueta <object>, encargada de instanciar el objeto en forma de ActiveX; en el caso de otros navegadores, como puede ser Firefox, se utilizará <embed> . En el fuente 3 podemos ver la definición de nuestra etiqueta <object> para el caso de Internet Explorer. Ya que contamos con el mencionado fichero aghost.js, nos serviremos de él y lo incluiremos en la página junto con nuestro fichero Javascript, como se muestra en el fuente 4. Una vez asociados los ficheros Javascript y abstrayéndonos de cómo se incrustará nuestro control en el navegador, procederemos a crear una nueva instancia, a la cual le indicamos los parámetros necesarios, como se puede ver en el fuente 4. Con esto ya

<<dotNetManía

<< dnm.plataforma.net

43


<< dnm.plataforma.net contamos con nuestra primera aplicación WPF/E; el resultado de la misma lo podemos ver en la figura 2.

Figura 2. Ejecución del ejemplo

Otras virtudes de WPF/E

<<dotNetManía

Ahora que contamos con la base fundamental para adentrarnos en este mundo de animaciones y gráficos vectoriales, intentaremos desvelar algunas de las grandes ventajas que nos proporciona WPF/E. Muchas de ellas ya las podemos imaginar si hemos buceado un poco en el universo de WPF.

44

Pinceles y formas básicas En todo entorno gráfico existen operaciones básicas, con las cuales se trabaja para formar diversas formas más complejas; habitualmente se denominan pinceles. En WPF/E también contamos con estos pinceles gracias a la clase SolidColorBrush, que nos proporciona la capacidad de crear pinceles que posteriormente podremos utilizar para rellenar nuestras formas. Como se muestra en el fuente 5, los pinceles pueden ser definidos con colores sólidos semitransparentes o bien establecerles un degradado. El resultado que produce este código lo podemos ver en la figura 3. También vemos en este ejemplo la forma de crear diversas formas mediante otros elementos de XAML, que proporciona multitud de ellos, entre los que podemos encontrar: Ellipse , Rectangle , Line , Polygon (representa una forma cerrada con un número arbitrario de lados), Polyline (nos muestra una serie de líneas conectadas que pueden o no constituir una forma cerrada), Path (nos proporciona una forma de representar diversas formas complejas como arcos y curvas).

1 <Canvas xmlns=”http://schemas.microsoft.com/client/2007” 2 xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”> 3 4 <Rectangle Width=”100” Height=”100” Fill=”Red” /> 5 6 <Ellipse Width=”100” Height=”100” Canvas.Left=”80” Canvas.Top=”65”> 7 <Ellipse.Fill> 8 <RadialGradientBrush> 9 <GradientStop Color=”Yellow” Offset=”0.0” /> 10 <GradientStop Color=”Red” Offset=”0.25” /> 11 <GradientStop Color=”Blue” Offset=”0.75” /> 12 <GradientStop Color=”LimeGreen” Offset=”1.0” /> 13 </RadialGradientBrush> 14 </Ellipse.Fill> 15 </Ellipse> 16 17 <Rectangle Opacity=”0.6” Height=”100” Width=”100” Canvas.Left=”155” 18 Canvas.Top=”10” Stroke=”#105581” StrokeThickness=”10” Fill=”#5991B5” /> 19 20 <Path Data=”M 20,100 C 20,340 300,-200 150,150z” 21 Stroke=”#135E92” Fill=”#CAF2DF” 22 Canvas.Left=”30” Canvas.Top=”105” /> 23 24 </Canvas>

Fuente 5

Figura 3. Ejecución del ejemplo del fuente 5

Transformaciones 2D WPF/E nos permite la manipulación tanto de imágenes como de formas en dos dimensiones, y para ello nos dota de diversas clases: • RotateTransform: Rota un elemento con el ángulo especificado. • ScaleTransform: Escala un elemento a partir de la especificación de sus coordenadas X e Y. • SkewTransform: Sesga un elemento a partir de los valores especificados en sus ángulos AngleX e AngleY. • TranslateTransform: Desplaza un elemento a partir de los valores expresados en sus coordenadas X e Y. En el fuente 6 definimos un conjunto de formas, a las cuales les aplicamos las diversas transformaciones. El resultado de este código lo podemos ver en la figura 4.

Figura 4. Ejecución del ejemplo del fuente 6


<< dnm.plataforma.net Creando animaciones <Rectangle Canvas.Left=”50” Canvas.Top=”20” Width=”50” Height=”50” Fill=”RoyalBlue”> <Rectangle.RenderTransform> <RotateTransform Angle=”45” /> </Rectangle.RenderTransform> </Rectangle> <Rectangle Canvas.Left=”25” Canvas.Top=”120” Width=”50” Height=”50” Fill=”Green”> <Rectangle.RenderTransform> <SkewTransform AngleY=”10”/> </Rectangle.RenderTransform> </Rectangle> <Ellipse Canvas.Left=”100” Canvas.Top=”30” Width=”50” Height=”50” Fill=”RoyalBlue”> <Ellipse.RenderTransform> <ScaleTransform ScaleX=”2”/> </Ellipse.RenderTransform> </Ellipse> <Ellipse Opacity=”0.6” Canvas.Left=”125” Canvas.Top=”125” Width=”50” Height=”50” Fill=”RoyalBlue”> </Ellipse> <Ellipse Canvas.Left=”125” Canvas.Top=”125” Width=”50” Height=”50” Fill=”RoyalBlue”> <Ellipse.RenderTransform> <TranslateTransform X=”10” Y=”10”/> </Ellipse.RenderTransform> </Ellipse> ...

Fuente 6 ... 3 <!—Rectangulo—> 4 <Rectangle 5 Canvas.Left=”50” Canvas.Top=”90” Width=”50” Height=”50” Fill=”RoyalBlue”> 6 <Rectangle.RenderTransform> 7 <RotateTransform x:Name=”Transform” Angle=”45” CenterX=”25” CenterY=”25” /> 8 </Rectangle.RenderTransform> 9 <Rectangle.Triggers> 10 <EventTrigger RoutedEvent=”Rectangle.Loaded”> 11 <BeginStoryboard> 12 <Storyboard> 13 <DoubleAnimation 14 Storyboard.TargetName=”Transform” 15 Storyboard.TargetProperty=”Angle” 16 From=”0” To=”360” Duration=”0:0:5” RepeatBehavior=”Forever” /> 17 </Storyboard> 18 </BeginStoryboard> 19 </EventTrigger> 20 </Rectangle.Triggers> 21 </Rectangle> 22 <!—Paloma—> 23 <Canvas.Triggers> 24 <EventTrigger RoutedEvent=”Canvas.Loaded”> 25 <EventTrigger.Actions> 26 <BeginStoryboard> 27 <Storyboard> 28 <DoubleAnimation 29 Storyboard.TargetName=”Paloma” 30 Storyboard.TargetProperty=”(Canvas.Left)” 31 To=”300” Duration=”0:0:3” RepeatBehavior=”Forever” /> 32 </Storyboard> 33 </BeginStoryboard> 34 </EventTrigger.Actions> 35 </EventTrigger> 36 </Canvas.Triggers> 37 <Image x:Name=”Paloma” Height=”77” Width=”55” 38 Canvas.Left=”10” Canvas.Top=”5” Source=”resources/Paloma.png” /> ...

Fuente 7

Al igual que en WPF, para el tratamiento de animaciones podemos contar con el elemento <Storyboard>. Este elemento nos permite modificar casi cualquier propiedad de un elemento XAML en tiempo de ejecución y variarla en función del tiempo, dotándonos de una gran funcionalidad, gracias a la cual podremos realizar animaciones de diversos tipos, como traslaciones, cambios de opacidad, rotaciones, etc. Para mostrar lo expuesto anteriormente hemos programado dos animaciones, que podemos ver en el fuente 7. En la primera de ellas realizamos una rotación de un rectángulo, variando para ello su propiedad Angle de 0 a 360 grados en un intervalo de tiempo de 5 segundos. En la segunda de las animaciones modificamos la propiedad Left de una imagen que contiene una forma de paloma, consiguiendo así un efecto de movimiento de la misma. El resultado de ambas animaciones se presenta la figura 5, en la que podemos observar tanto el efecto de traslación de la imagen como el de rotación del rectángulo.

Figura 5. Ejecución del ejemplo del fuente 7

Vídeo y audio En lo concerniente a reproducción de vídeo y audio, WPF/E nos proporciona el elemento <MediaElement>. Este elemento nos permite la reproducción tanto de vídeo como de audio, sopor-

<<dotNetManía

... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 31

45


<< dnm.plataforma.net 1 <MediaElement x:Name=”Reproductor” 2 Source=”resources/xbox.wmv” 3 Width=”300” Height=”300” />

Fuente 8

tando actualmente los formatos WMV (Windows Media Video) y WMA (Windows Media Audio), aunque en futuras versiones el número de formatos se verá ampliado, incluyéndose soporte para MP3, entre otros. Para poder incluir un elemento multimedia en nuestro control WPF/E, únicamente deberemos declarar un elemento de este tipo, como se muestra en el fuente 8. Al igual que los demás controles derivados de UIElement , un objeto MediaElement contendrá las propiedades compartidas de estos elementos como son Opacity , Clip , Render Transform , etcétera, permitiéndolos variar y distorsionar nuestro elemento. Adicionalmente, este control contiene propiedades propias como son: • Stretch: Permite especificar de qué forma se mostrará nuestro vídeo en el control MediaElement,

1 2 3 4 5 6 7 8 9 10 11

function btnStop_Click(sender, args) { sender.findName(“Reproductor”).stop(); } function btnPause_Click(sender, args) { sender.findName(“Reproductor”).pause(); } function btnPlay_Click(sender, args) { sender.findName(“Reproductor”).play(); }

Fuente 10

soportando como valores None, Uniform, UniformToFill y Fill. • IsMuted : Permite deshabilitar el audio de nuestro vídeo. • Volumen : Permite especificar el volumen de audio del objeto MediaElement. Puede variar entre 0 y 1, siendo su valor por defecto 0,5.

<<dotNetManía

También podremos controlar la reproducción del vídeo mediante los métodos play, pause y stop, que podremos invocar desde código Javascript. En el fuente 9 podemos ver un ejemplo de un pequeño reproductor multimedia. Al igual que en el primero de nuestros ejemplos, controlaFigura 6. Ejecución del ejemplo de los fuentes 7 y 8 mos los eventos de reproducción del vídeo gracias a Javascript; el código que implementa <Canvas xmlns=”http://schemas.microsoft.com/client/2007” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”> esta funcionalidad puede verse en el <MediaElement x:Name=”Reproductor” Source=”resources/xbox.wmv” fuente 10, y el reproductor en ejecuWidth=”300” Height=”300”/> ción en la figura 6. <!— Boton Play—>

46

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ... 48 49 50 51 52 53 54 55 ...

<Canvas MouseLeftButtonDown=”javascript:btnPlay_Click”> <Rectangle Stroke=”#FF122C7E” StrokeThickness=”2” Canvas.Top=”262” RadiusX=”2” RadiusY=”2” Height=”23” Width=”55”> <Rectangle.Fill> <LinearGradientBrush StartPoint=”0.5,2.109” EndPoint=”0.5,-1.109”> <GradientStop Color=”#FF0068FF” Offset=”0.433”/> <GradientStop Color=”#FFEAEAEA” Offset=”0.269”/> <GradientStop Color=”#FF0B0E12” Offset=”0.769”/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <TextBlock Canvas.Top=”264” Canvas.Left=”13” FontSize=”12” Foreground=”#FFFFFF” Text=”Play” /> </Canvas> <!— Marco del Video—> <Rectangle Canvas.Top=”32” Stroke=”#FF122C7E” Height=”230” Width=”300” StrokeThickness=”6” RadiusX=”2” RadiusY=”2” /> <!— Logo WPF—> <Path Stroke=”transparent” Canvas.Left=”210” Canvas.Top=”170” StrokeThickness=”0.5” Data=”M... “> <Path.Fill> <RadialGradientBrush>

Fuente 9

Conclusiones Como hemos podido ver a lo largo de todo este artículo, WPF/E nos brinda la oportunidad de construir experiencias de usuario más ricas e innovadoras, incluyendo en las mismas vídeo, audio y animaciones en dos dimensiones. Todo ello gracias a un plug-in multi-navegador muy ligero (1 Mb actualmente), con el cual podemos interactuar mediante código script. Si unimos todo lo anterior a que los lenguajes utilizados muestran compatibilidades ya conocidas con otras tecnologías como AJAX de ASP.NET y WPF, podemos afirmar que este producto nos provee de una gran herramienta en el ámbito del entorno Web.


dnm.todotnet.qa

Dino Esposito

Mi meta es el rendimiento Rendimiento y distribución son los temas que trataremos este mes. Un lector pregunta cómo mejorar el arranque de una aplicación. No es tarea fácil; y no hay ninguna “bala de plata” disponible. De cualquier forma, sí existe un larga lista de posibles sugerencias. Por otro lado, los manejadores (handlers) ASP.NET son adecuados para servir peticiones especiales de una forma especial.Pueden escribirse bien como ASHX o como recursos AXD. ¿Cuál es mejor?

Dino Esposito es mentor de Solid Quality Learning y autor de “Programming Microsoft ASP.NET 2.0 Core Reference” y “Programming ASP.NET 2.0 Applications Advanced Topics”, ambos de Microsoft Press.Afincado en Italia, Dino es un ponente habitual en los eventos de la industria a nivel mundial.Visite su blog en: http://weblogs.asp.net/despos. Puede enviarle sus consultas a TodotNet.QA@dotnetmania.com

crear manejadores personalizados usando tanto la extensión ASHX como la AXD. Aparte de las pequeñas diferencias sintácticas ¿cuál es la diferencia real entre estas dos opciones? No me puedo creer que sea solamente una cuestión de sintaxis; debe haber algo más. ¿Alguna idea? No te convence la afirmación y tienes razón. La diferencia real entre los manejadores ASHX y AXD tiene más de distribución que de mera sintaxis. Entremos en detalles. Un manejador HTTP es un componente especial de ASP.NET –léase, una clase con una interfaz bien definida– que el entorno de ejecución usa para procesar peticiones entrantes que se dirigen a ASP.NET. La clase System.Web.UI. Page es, por tanto, la más compleja y sofisticada de todos los manejadores HTTP. Recursos tales como ASMX, ASCX y ASAX tienen su propio manejador HTTP que se encarga de procesar las peticiones. En particular, el manejador HTTP encargado de servir los recursos ASAX finaliza la petición lanzando una excepción debido a que los recursos ASAX no se sirven al usuario, sino que son consumidos internamente. Cuando tienes que manejar un tipo de recurso de forma especial, escribes un manejador personalizado. Por ejemplo, imagínate que necesitas extraer una imagen de una base de datos, añadir una nota de copyright y devolverlo al usuario. ¿Cómo lo harías? Las imágenes solo pueden servirse mediante la etiqueta <img> y esta etiqueta solo acepta un tipo gráfico MIME. La idea es que establezcas un manejador HTTP personalizado, y por lo

Un manejador HTTP es una clase administrada que implementa la interfaz IHttpHandler. La interfaz se compone de dos métodos: IsReusable y ProcessRequest

tanto su URL, y le pases información suficiente en la cadena de consulta poder recuperar la imagen que necesitas. Internamente, el manejador HTTP procesará los bits de la imagen y añadirá cualquier marca de agua solicitada, configurando de forma correcta la respuesta para servirle la imagen. Después, enlazarás este código a la etiqueta <img> usando la URL de manejador HTTP. Como se ha mencionado, un manejador HTTP es una clase administrada que implementa la interfaz IHttpHandler. La interfaz se compone de dos métodos: IsReusable y ProcessRequest. El primero simplemente devuelve un valor booleano que indica si se requiere una nueva instancia de la clase de manejador para cada petición; el otro método simplemente define el comportamiento del manejador y configura el stream de respuesta como

<<dotNetManía

<< La documentación de ASP.NET informa que se pueden

47


48

TodotNet.qa@dotnetmania.com TodotNet.qa@dotnetmania.com

<<dotNetManía

<< dnm.todotnet.qa

Si tu meta es la flexibilidad y no quieres enlazar un endpoint a un fichero en el servidor, opta por la extensión AXD

se requiera. ¿Cómo se enlaza un manejador HTTP a una URL? En el fichero Web.config, se registra la clase del manejador HTTP como manejador para un conjunto de peticiones. A continuación vemos un ejemplo. <httpHandlers> <add verb="*" path="myHandler.aspx" type="Samples.SimpleHttpHandler, SimpleHandler" validate="false" /> </httpHandlers>

Con esta configuración activa, cualquier petición dirigida a myHandler.aspx será servida por la clase SimpleHttpHandler. El atributo verb permite seleccionar los verbos que se tendrán en consideración. El atributo validate indica si el entorno de ejecución de ASP.NET tiene que comprobar la existencia del manejador al comenzar la aplicación o lo hará bajo demanda. El endpoint asociado con un manejador HTTP no tiene por qué ser un recurso físico. Una de las diferencias entre ASHX y AXD es, precisamente, si se trata de un recurso físico o un endpoint virtual. Puedes escribir un manejador personalizado como una clase en C# o Visual Basic. NET y compilarlo en un ensamblado. A continuación, distribuyes el ensamblado al directorio bin de la aplicación y editas el fichero Web.config adecuadamente. Funciona, y puedes usar cualquier extensión para definir la URL de destino. Sin embargo, la extensión que utilices tiene que ser conocida por IIS. En otras palabras, IIS debe reconocer esa extensión, pongamos *.xyz , y en particular, saber que los recursos del tipo XYZ debe ser enviados al entorno de ejecución de ASP.NET. Así que si quieres utilizar extensiones XYZ primero tie-

nes que añadir esa extensión a la metabase de IIS. Si no quieres, o no tienes permisos para escribir en la metabase de IIS, entonces debes utilizar la extensión AXD. La extensión AXD es registrada automáticamente en la metabase de IIS cuando se instala ASP.NET 2.0. A partir de ese momento, cualquier petición que termine en AXD es automáticamente redirigida a ASP.NET. Pero todavía queda configurar el fichero Web.config, para especificar a qué endpoint apunta el manejador. Al editar el fichero Web.config, se reinicia la sesión y se borra el estado de la sesión y el caché. Una solución problemática, si hay que usarla con una aplicación activa. Escrito como un fichero ASHX, el manejador HTTP, es, de alguna forma, auto-contenido. Se puede insertar código C# o Visual Basic .NET ya sea en línea, dentro del fichero ASHX, o en una clase separada de código. A diferencia del AXD, la extensión ASHX es registrada automáticamente en ASP.NET para ser manejada por la clase que indica el propio fichero. Cualquier fichero ASHX comienza por una cabecera especial: <%@ WebHandler Language="C#" Class="Samples.MyHandler" %>

El atributo Class puede ser omitido si se inserta el código en línea. De lo contrario, todo el contenido del fichero ASHX está en la línea de cabecera. Con este truco del ASHX, se supone que la URL apunta a un recurso del servidor, que –internamente– utiliza la clase suministrada para gestionarlo. Consecuentemente, para habilitar un manejador ASHX, todo lo que hay que hacer es colocar el fichero en cualquier carpeta de la aplicación Web, incluyendo la carpeta raíz. No se necesitan cambios ni en IIS ni en el fichero Web.config. La distribución es de “costo cero”, y no se necesita reiniciar la aplicación. Concluyendo, si tu objetivo es minimizar el costo de la distribución (digamos que, porque vas a hacer cambios frecuentes a una aplicación activa) utiliza los recursos ASHX. En ese caso, el fichero contendrá o hará referencia directa al código fuente. Si tu meta es la flexibilidad y no quieres enlazar un endpoint a un fichero en el servidor, opta por la extensión AXD. De esta forma, sitúas la información de enlace en el Web.config. La extensión AXD es preferible a cualquier otra personalizada, porque te ahorras la edición manual de la metabase de IIS en tiempo de distribución. Mi aplicación Windows tarda mucho en mostrar su primera interfaz de usuario y no existe ningún cuello de botella donde el código pueda “colgarse” que justifique ese rendimiento tan pobre. He añadido una ventana de “splash”, pero todavía resul-


Ciertos controles ricos como ListView y TreeView, nunca debieran de ser cargados en Form_Load, porque esta tarea es una posible fuente de cuellos de botella

el uso de la utilidad ngen.exe. Esto transforma el código intermedio (lenguaje IL) en código máquina específico de tu CPU. Esto tiene ventajas e inconvenientes, no obstante. Por un lado, el código nativo puede ser compartido entre procesos. Esto no es una ventaja para el código en sí, pero es bueno cuando se comparten ensamblados. Por el contrario, el código JIT es privado a un proceso y debe ser recreado cada vez. Omitiendo la compilación JIT, con toda seguridad apreciarás una mejora en el rendimiento. Es difícil decir, sin embargo, cuál será el impacto en un “arranque en frío”. No existe compilación JIT, pero sí alguna operación adicional de entrada/salida de carga de código binario. El uso de ensamblados firmados también puede ayudar si les sitúas en el GAC (Global Assembly Cache). En este caso, te ahorras el tiempo que lleva verificar la firma del ensamblado para cada página de memoria. Y, finalmente, puedes tratar de asignar una dirección de memoria base bien conocida para cada DLL de tu programa. Haciéndolo de esa forma, evitas la carga del proceso de reubicación en memoria. En tu correo mencionas una ventana splash. Como has podido observar, una ventana de este tipo hace cualquier cosa menos mejorar el rendimiento. Simplemente, entretiene al usuario un poco mejorando su percepción del rendimiento de la aplicación. Pero no hace nada para reducir el costo de la carga. Esta reciente oleada sobre AJAX trae a colación el objeto XMLHttpRequest. Sé que este objeto está ampliamente soportado, pero ¿es un estándar ratificado? No todavía. Hay un comité W3C que trabaja actualmente en la elaboración de una API estándar para el objeto XMLHttpRequest. El último borrador de trabajo está disponible en http://www.w3.org/ TR/XMLHttpRequest. Traducción por Marino Posadas

<<dotNetManía

ta demasiado lenta. ¿Se puede intentar alguna otra cosa? Nos guste o no, las aplicaciones administradas .NET requieren de la carga del Framework antes de iniciar su funcionamiento. Si la aplicación es la primera que se lanza cada mañana, cuando el usuario se conecta, ella correrá con los “costos” de esa carga inicial de la máquina virtual de .NET. Este escenario es conocido también como “arranque en frío”. En esta situación, una buena cantidad de tiempo se gasta en operaciones de entrada/salida requeridas para la carga de páginas en memoria. Tras esto, cualquier lanzamiento de la misma aplicación (o de otra aplicación .NET), será significativamente más rápido debido a que la mayoría de los ensamblados .NET ya se encuentran cargados en memoria. Este otro escenario se conoce como “arranque en caliente”. No hay mucho que se pueda hacer para minimizar esto, salvo reducir el número de ensamblados a cargar. La reducción de la carga en memoria también disminuye la posibilidad de que la máquina tenga que entrar en algún momento en procesos de paginación. Como norma general, ten en cuenta que una DLL de mayor tamaño es también preferible a un conjunto de módulos pequeños. Siempre hablando en general, deberías tratar de minimizar el trabajo realizado en Form_Load. Ten en cuenta que no se muestra ninguna interfaz de usuario hasta que todo el trabajo de ese evento ha concluido. Ejemplos de procesos que enlentecen la carga inicial, son el relleno de los controles, operaciones de red o bases de datos, cachés de datos, etc. Las tareas relativas a la inicialización y configuración, sin embargo, no se consideran críticas. Una regla, muchas veces olvidada, establece que no deberías mostrar ninguna interfaz de usuario que no se necesite mostrar al principio. Por ejemplo, ¿por qué rellenar todas y cada una de las páginas de un control TabControl? Será mejor hacerlo cuando la aplicación está en espera o cuando resulte absolutamente necesario. Si optas por el evento Application. Idle , ¡recuerda destruir el manejador de eventos cuando termines! Ciertos controles ricos, tales como ListView y TreeView , nunca debieran de ser cargados en Form_Load porque esta tarea es una posible fuente de cuellos de botella. Y si tienes que hacerlo, al menos incluye ese proceso entre un par de sentencias BeginUpdate/EndUpdate, de forma que se detenga el repintado del control para cada cambio individual. Además, utiliza el método AddRange() cuando tengas que insertar varios items. En general, las operaciones masivas son más eficientes que los cambios individuales. Si todavía no obtienes el rendimiento deseado, evita la compilación Just-In-Time (JIT) mediante

TodotNet.qa@dotnetmania.com TodotNet.qa@dotnetmania.com

<< dnm.todotnet.qa

49


dnm.laboratorio.net

Lorenzo Ponte

Ribbon.NET La aparición de herramientas como Microsoft Office 2007 trae consigo que todos los ojos de usuarios y desarrolladores acaben fijándose al milímetro en cada aspecto de la nueva versión. Este tipo de aplicaciones a las que accede un número muy grande de personas suelen ser tomadas como referencia por los desarrolladores en aquellos aspectos más interesantes de cara a actualizar o mejorar la interfaz de usuario de sus aplicaciones. Ribbon.NET proporciona unas librerías que permiten dar el look and feel de Office 2007 a las aplicaciones desarrolladas bajo la plataforma .NET. Mediante una fácil implementación, estarás en disposición de dar a tus formularios un aspecto similar al que ofrece Office 2007, con bordes redondeados, tonos azul pastel, botones que parecen salirse de la pantalla, etc. El aspecto de las aplicaciones transformadas mediante estas librerías parecerá haber sido sacado directamente del corazón de Office 2007. Hay que destacar que los diseños que ahora muestra Office 2007 han sido creados para entroncar con el nuevo sistema operativo de Microsoft, Windows Vista. Desarrollados utilizando el nuevo motor de presentación de WinFX, estos controles representan una auténtica revolución en el diseño y presentación de formularios. Ribbon.NET permite formatear con aspecto de Office 2007 los siguientes tipos de controles:

Lorenzo Ponte es redactor de dotNetManía. Es arquitecto de sistemas y aplicaciones .NET. Experto en datawarehousing y business intelligence, marketing intelligence y CRM analítico. Actualmente es consultor de la empresa Matchmind y webmaster de clikear.com

• RibbonFormBase: subclase que proporciona a los formularios Windows Forms el estilo y aspecto de Office 2007. • RibbonControl: proporciona el aspecto estándar de Office 2007 a elementos en general. • RibbonButton: permite crear botones con el aspecto de Office 2007. • RibbonButtonBar: permite crear paneles de controles con el aspecto de Office 2007. • RibbonStatusBar: aporta a la barra de estado los estilos y el aspecto de Office 2007. El código fuente muestra un pequeño fragmento de código en el que se puede apreciar lo sencillo que es implementar este tipo de librerías, en concreto un botón de un formulario. Si quieres estar a la última moda en diseño de aplicaciones, te recomendamos estas librerías que te ayudarán a dar ese toque final a tus aplicaciones y servirán de valor añadido de cara a su presentación. Ficha técnica Nombre Versión Fabricante Web Categoría Precio Valoración

Ribbon.NET 1 ComponentWorkshop www.componentworkshop.com/Ribbon.aspx Diseño $89

this.ribbonButtonControl.BackColor = System.Drawing.Color.Transparent; this.ribbonButtonControl.Image = (System.Drawing.Image)(resources.GetObject("ribbonButtonControl12.Image"))); this.ribbonButtonControl.ImageAlignment = System.Drawing.ContentAlignment.MiddleLeft; this.ribbonButtonControl.Location = new System.Drawing.Point(169, 3); this.ribbonButtonControl.Name = "ribbonButtonControl12"; this.ribbonButtonControl.Selected = false; this.ribbonButtonControl.Size = new System.Drawing.Size(70, 22); this.ribbonButtonControl.Style = CW.Ribbon.Renderers.RibbonControlRenderers.Office2007Blue; this.ribbonButtonControl.SuperTipSettings.DescriptionText = ""; this.ribbonButtonControl.SuperTipSettings.FooterText = ""; this.ribbonButtonControl.SuperTipSettings.ShowDelay = 1000; this.ribbonButtonControl.SuperTipSettings.TitleText = "Super Tip"; this.ribbonButtonControl.SuperTipSettings.Visible = true; this.ribbonButtonControl.TabIndex = 1; this.ribbonButtonControl.Text = "Options"; this.ribbonButtonControl.TextAlignment = System.Drawing.ContentAlignment.MiddleLeft; this.ribbonButtonControl.Click += new System.EventHandler(this.ribbonButtonControl12_Click);


<< dnm.laboratorio.net PowUpload Tener que subir archivos a un servidor remoto es una tarea diaria a la que se enfrentan multitud de desarrolladores. No solo los desarrolladores demandan este tipo de servicio; los usuarios comunes también quieren por sí mismos actualizar sus portales o intranets, pudiendo subir documentos, imágenes, etc. confidenciales para ser utilizados por sus organizaciones. Para realizar este tipo de acciones existe un protocolo específico, FTP (File Transfer Protocol). Es un protocolo bastante limitado a la hora de integrarlo dentro de una aplicación o poder usarlo desde cualquier PC conectado a Internet. PowUpload soluciona este tipo de problemas. Entre sus principales características están que puede ser implementado en cualquier aplicación desarrollada bajo la plataforma .NET, que todo el tráfico se realiza mediante HTTP (lo que hace posible utilizarlo desde cualquier PC que posea tan solo una conexión a Internet) y que permite subir de una vez hasta 1 Gb (con .NET Framework 1.0/1.1) o 2 Gb (con .NET Framework 2.0). La forma de implementación es muy sencilla: primero se debe crear un formulario, añadiéndole entre otros uno o más controles <INPUT TYPE=FILE> necesarios para seleccionar los archivos a subir. A continuación, podemos agregar un botón al formulario y asociarle al evento ServerClick un gestor de evento que llame al método de PowUpload que se encargará de recorrer los controles tipo FILE e ir subiéndolos simultáneamente al servidor. PowUpload también proporciona un elemento visual consistente en una barra de progreso que indica en todo momento el porcentaje de subida durante

private void btnUploadFile_ServerClick( object sender, System.EventArgs e) { string FolderToSave = Server.MapPath("") + "\\Archivos\\"; Upload UploadResult = new Upload(); if(UploadResult.Files != null && UploadResult.Files.Count>0) { UploadedFile myFile = UploadResult.Files["file1"]; myFile.SaveAs(FolderToSave + myFile.SafeFileName, true); IMGPATH = "UploadedFiles/" + myFile.SafeFileName; ReadProperties(); } }

el proceso. Este componente es muy importante, ya que nos dará una referencia de lo que queda por subir al servidor. PowUpload también permite cancelar el proceso en cualquier momento, matando el proceso que utiliza y liberando la memoria del PC. Otra de las características útiles de PowUpload es la compatibilidad con SSL (HTTPS), para el caso en que los archivos a subir necesiten un extra de seguridad. El código fuente muestra la programación típica del evento que desencadena las subidas. Ficha técnica Nombre Versión Fabricante Web Categoría Precio Valoración

PowUpload 1 element-it www.element-it.com/PowUpload.aspx Utilidades $199

PowerWEB Zoom for ASP.NET A continuación se detallan algunas de las características de PowerWEB Zoom: • Compatibilidad con ASP.NET 1.x y 2.0. • Permite configurar el teclado con teclas rápidas para hacer un uso más ágil de sus funcionalidades. Ofrece diferentes modos de renderización de imágenes. Ficha técnica Nombre Versión Fabricante Web Categoría Precio Valoración

PowerWEB Zoom 1 DART www.dart.com/powerweb/zoom.asp Categoría: Utilidades $499

<<dotNetManía

PowerWEB Zoom es un componente que dota de la posibilidad de aumento/reducción (zoom) visual a aquellas aplicaciones que lo tengan implementado. Mediante una interfaz muy intuitiva, se puede controlar mediante el ratón un cuadro que va ampliando las partes de la pantalla por las que éste pasa. Este componente está especialmente indicado para ampliar fotos de gran resolución, resaltando zonas que necesiten ser vistas con mayor precisión. Un claro ejemplo al que se podría aplicar PowerWEB Zoom son los mapas de Google Maps. Otra de sus aplicaciones potenciales es la de hacer accesible una aplicación Web a colectivos de personas con dificultades de visión; este componente les permitirá ver los contenidos más ampliados.

51


<< dnm.comunidad.net

BcN DEV

.NET developers community of Barcelona Como decía Hadi en la presentación del Grupo de Usuarios de Málaga en la edición de dotNetManía de septiembre,“¿qué podíamos hacer para complicarnos aún más la vida?”. Pues algo similar pasó por nuestras cabezas a mediados de este año 2006…

<<dotNetManía

<< En una de las presentaciones técnicas del nuevo Visual

52

Studio 2005 y .NET Framework 2.0 decidimos llevar a cabo una idea que ya iba calando en mi interior hacia tiempo: la creación de un grupo de usuarios. Bueno, realmente la intención inicial fue la de apuntarnos al grupo de usuarios que operase en Barcelona, pero al no haber ninguno, decidimos crearlo… Hablo en plural porque a lo largo de todo el proceso me animó y apoyó mi buen amigo y compañero de aventuras .NETianas David Zardoya, genial programador se le mire por donde se le mire (normalmente de abajo hacia arriba, ya que es bastante alto). Lo cierto es que fue una idea tremenda y, ni cortos ni perezosos, abordamos a Alfonso Rodríguez de Microsoft, quien nos animó a llevar adelante el proyecto… A lo largo de dos meses se realizó un par de sesiones sobre varias de las características del nuevo .NET 2.0, refactorización y plantillas de código, así como una sesión magistral sobre ASP.NET por parte de Aurelio Porras, experto de Microsoft. Luego el tema quedó parado algún tiempo debido a problemas con el hosting y a temas personales/laborales que no nos permitieron dedicarle mucho tiempo. Hasta hace alrededor de un mes y medio, cuando tuve la buena fortuna que me llamara Pep Lluis Baño de Spain.NET, podríamos decir que el pionero de los grupos de usuarios de España, y me animó a reactivar el tema. Total, que aquí estamos de nuevo, con los problemas de hosting solucionados. Ahora tenemos una flamante y renovada página Web, http://www.bcndev.net; se han establecido colaboraciones con el centro de formación Soft-Obert, que nos ha cedido amablemente aulas para realizar las reuniones, con proyectores, aire acondicionado y soporte técnico para temas de redes; y se ha hecho un plan de promoción con el objetivo de incrementar el número de socios y ofrecer los servicios que puedan ser de interés para los mismos. El grupo volvió a activarse -oficialmente- con la ayuda de Alfonso

Rodríguez el pasado 23 de noviembre, durante la presentación del nuevo .NET Framework 3.0. Precisamente en la fecha en que se escribe este artículo ha tenido lugar la segunda sesión del grupo de usuarios, en la que se presentaron dos ponencias: una sobre MONO, el entorno open source para el desarrollo y la ejecución multiplataforma de .NET (presentada por Toni Recio), y la otra ponencia sobre Windows Workflow Foundation, llevada a cabo por quien escribe estas líneas.

Cabe destacar el buen ambiente, colaboración y ganas de los asistentes, así como la intensidad de las charlas que tuvimos después de las ponencias, centradas sobre las posibilidades de estas dos tecnologías. Por cierto, las presentaciones y código fuente de las ponencias están colgadas en nuestra página Web a disposición de quien desee conocer las principales características de estos productos. Como objetivos principales, el grupo de usuarios de Barcelona, BcnDev.Net, tiene los de fomentar el aprendizaje, fomentar el espíritu de compartición de conocimientos y realizar un “pique” sano para que vayamos incidiendo en diferentes temas de interés y exponién-


dnm.comunidad.net

Windows Presentation Foundation Organiza: BcN DEV Fecha: 25 de enero de 2007 Ubicación: Soft Obert St. Antoni Maria Claret, 122 08025 Barcelona Horario: 18:00 a 20:00 h Tema: Windows Presentation Foundation, introducción, ejemplos y posibilidades Ponentes: Toni Recio, Josep Cubero Más información: http://www.bcndev.net

Prepárate para un nuevo día para el desarrollador Organiza: MSDN España Fechas y lugares: • Sevilla: 16 de enero de 2007 • Valladolid: 18 de enero de 2007 • Tenerife: 23 de enero de 2007 • Málaga: 25 de enero de 2007

únicamente en Windows Presentation Foundation (WPF). Uno de los ponentes es Toni Recio (http://www.tonirecio.com) y el otro es José Cubero (http://jusep-net.blogspot.com); ambos llevan bastante tiempo trabajando con el producto y sus betas. Si sois desarrolladores o aficionados a .NET, no dejéis de venir a esta reunión o las siguientes. ¡Realmente el poder asistir a una charla de un experto como Toni Recio o David Zardoya, o incluso de Marçal Serrate (si conseguimos animarle a que exponga sus experiencias con la arquitectura CSLA de Rockford Lhotka) no tiene precio! Y puede que por febrero podamos arrancar algunas horas de David Carmona y Aurelio Porras, dos de los gurús en .NET de Microsoft España. ¡No lo dudéis, acercaos! Sin duda alguna, vamos a divertirnos y a aprender mucho. Encontraréis más información sobre el grupo y detalles sobre los eventos planificados en nuestra página Web (http://www.bcndev.net). Desde estas líneas aprovecho para agradecer a Alfonso Rodríguez su apoyo incondicional, y a Paco Marín por ofrecernos este espacio para dar a conocer a BcnDev.Net. José Luis Latorre fundador del Grupo de Usuarios .NET de Barcelona

En estas sesiones técnicas tendremos la oportunidad de ver en detalle las nuevas funcionalidades de Microsoft .NET Framework 3.0 y más: º Windows Presentation Foundation, el subsistema de presentación unificado para Windows, con el que crear una nueva generación de interfaces de usuario sobre .NET. º Windows Communication Foundation, desarrollo de aplicaciones distribuidas en nuevos modelos de comunicación como servicios Web seguros, fiables y transaccionales capaces de interoperar a través de distintas plataformas. º Las capacidades de definición de flujos de trabajo declarativos que estarán disponibles para los desarrolladores a través del Windows Workflow Foundation, incluido en .NET Framework 3.0. º Por último, veremos Sharepoint 2007, una plataforma única, integrada y ampliable que permite construir aplicaciones web con funcionalidad avanzada de visualización, búsquedas o gestión de contenidos, entre otras. Más información: http://www.microsoft.com/spanish/msdn/spain.

<<dotNetManía

eventos.eventos.eventos

dolos a los demás compañeros, ya que es imposible estar en todo, pero si cada uno se encarga de estudiar una parte y la transmite a los demás, tanto nuestra necesidad de aprendizaje como nuestra curiosidad interior estarán algo más satisfechas. Además de este fomento del intercambio de conocimientos y experiencias, BcnDev.Net tiene el objetivo de aportar valor al colectivo de desarrolladores .NET de Barcelona. Este valor se pretende canalizar vía el portal Web creado sobre dotNetNuke, un framework de aplicaciones Web muy flexible y fácilmente extensible. Hemos abierto una bolsa de trabajo gratuita y una sección de noticias en las que iremos comentando las novedades de interés general y local. También enviamos un boletín periódico a los socios con las noticias de interés del sector. Asimismo, pretendemos abrir una sección de artículos y apuntarnos a la iniciativa de Panorama Box, de la cual estamos esperando respuesta. El grupo tiene en total actualmente unos 60 miembros, varios de ellos con muchas ganas de hacer cosas. Por lo demás, es un grupo abierto; cabe decir que como todos los demás grupos de usuarios: aquí todos somos iguales y tenemos voz por igual. En nuestros foros o en las ponencias cualquiera puede proponer y participar. Y hablando de ponencias, nuestra próxima sesión, planificada para el 25 de enero de 2007, estará centrada

53


Suscríbase y llévese los dos próximos libros gratis además, el CD Vol. 3 con los números 13 al 23 en PDF

❑ Nº19 (6,50€)

❑ Nº20 (8,50€)

❑ Nº21 (6,50€)

❑ Nº22 (6,50€)

❑ Nº23 (6,50€)

❑ Nº24 (6,50€)

❑ Nº25 (6,50€)

❑ Nº26 (6,50€)

❑ Nº27 (6,50€)

❑ Nº28 (6,50€)

❑ Nº29 (6,50€)

❑ Nº30 (6,50€)

❑ Nº31 (6,50€)

❑ Nº32 (6,50€)

✃❑ ❑

Oferta válida hasta el 31 de enero de 2007 o hasta agotar existencias Deseo suscribirme a dotNetManía por un año (11 números) por un precio de 65,00€ IVA incluido y recibir gratuitamente los dos próximos cuadernos técnicos que publique Netalia, y además el CD Volumen 2 con los ejemplares desde el 12 al 22 en formato PDF de alta calidad de forma gratuita. Si su dirección está fuera de España consulte los detalles en www.dotnetmania.com Deseo que me envíen los números atrasados marcados según el precio de portada. Otros: DATOS DE ENVÍO CIF/NIF. . . . . . . . . . . . . . . . . . . . Empresa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nombre y apellidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dirección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Población . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Código Postal . . . . . . . . . . . . . . . . . . . Provincia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Teléfono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fax . . . . . . . . . . . . . . . . . . . . . . . . . . . email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DATOS DE FACTURACIÓN (sólo si son distintos a los datos de envío) CIF/NIF. . . . . . . . . . . . . . . . . . . . Empresa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nombre y apellidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dirección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Población . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Código Postal . . . . . . . . . . . . . . . . . . . Provincia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Teléfono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fax . . . . . . . . . . . . . . . . . . . . . . . . . . . email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . FORMA DE PAGO ❑ Talón nominativo a nombre NETALIA, S.L. ❑ Transferencia bancaria a nombre de NETALIA, S.L. a: La Caixa - Número de cuenta 2100 4315 48 2200014696 (Indique su nombre en la transferencia) ❑ Domiciliación Bancaria (con renovación automática, previo aviso) Indique su número de cuenta: ❑ Tarjeta de crédito ❑ VISA ❑ MASTERCARD Número de su tarjeta: Fecha de caducidad: / (imprescindible) Firma y/o sello a

de

Puede enviar sus datos por Fax al 91 499 13 64, o por teléfono al 91 666 74 77, o por email a la dirección suscripciones@dotnetmania.com, o también puede enviarlos por correo postal a la siguiente dirección:

de 2007

Usted autoriza a la mecanización de estos datos. El responsable y destinatario de éstos es Netalia, S.L. Usted tiene derecho a acceder a sus datos, modificarlos y cancelarlos cuando lo desee. Sus datos no serán cedidos en ninguna de las formas posibles a terceras partes y no se utilizarán más que para el buen funcionamiento de su suscripción a la revista dotNetManía y para informarle de las actividades comerciales que realice la editorial Netalia, S.L. Si no desea recibir información comercial de dotNetManía marque la casilla siguiente ❑

Netalia, S.L. C/ Robledal, 135 28529- Rivas Vaciamadrid (Madrid)


<< dnm.biblioteca.net

dnm.biblioteca.net Por Marino Posadas

Microsoft SQL ServerTM 2005:Applied Techniques Step by Step Solid Quality Learning Editorial: Microsoft Press ISBN: 0735623163 Páginas: 496 Primera edición: Junio 2006 Idioma: Ingles

El texto recoge además, todos los aspectos relacionados con la correcta configuración y puesta a punto del servidor, así como el uso adecuado de las numerosas utilidades adicionales que acompañan a SQL Server 2005, y un tratamiento detallado de algunas nuevas capacidades, como Notification Services. El libro se complementa con un CD que contiene todo el código de ejemplo utilizado en la larga lista de prácticas que lo acompañan.

CLR via C#, Second Edition Jeffrey Richter Editorial: Microsoft Press ISBN: 0735621632 Páginas: 736 Primera edición: 2006 Idioma: Inglés Ya hemos comentado en esta sección alguna obra de Richter con anterioridad. Considerado uno de los evangelistas tecnológicos más reputados de la actualidad, el autor, literalmente, “se mete en las profundidades del CLR”, para, usando C# como lenguaje de soporte, revisar la construcción de aplicaciones basadas en la versión 2.0 de .NET Framework, con gran profundidad y detallando especialmente aquellos aspectos más angulosos de su arquitectura. Si queremos saber cómo funcionan realmente cosas como el recolector de basura, la reflexión, la descripción de metadatos disponible en tiempo de ejecución, la conversión a código IL, o la escritura correcta de aplicaciones multiproceso, ésta es una magnífica referencia. Eso sí, no es un libro para principiantes, y requiere un cierto conocimiento previo de .NET y el lenguaje C# en particular.

<<dotNetManía

<<

Mucho hay escrito ya sobre SQL Server 2005, pero no tanto sobre la aplicación de las técnicas soportadas por el producto a la programación del día a día con que se topa el desarrollador, comenzando por el propio proceso de instalación, y avanzando en dificultad, sin asumir conocimientos previos del producto. Ese es precisamente el objetivo de esta obra, firmada por varios de los componentes de Solid Quality Learning (autores de la mayoría de los cursos oficiales de Microsoft de SQL Server 2005).

55


[ ]

dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>>


dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >


noticias.noticias.noticias

<< dnm.desvan Marino Posadas

Rosario,Hawaii,Mónaco y Edimburgo.No es un viaje,son productos en desarrollo Siguiendo la tradición, Microsoft continúa bautizando sus productos beta con nombres de conocidas ciudades. Los últimos en conocerse públicamente son: Rosario (nueva versión de Visual Studio Team System focalizada en procesos de prueba, que seguirá a Orcas), Hawaii (éste, algo más conocido, referente a los productos de desarrollo posteriores a Orcas), Mónaco (parte de iLife, conjunto de aplicaciones para crear y gestionar contenido digital) y Edimburgo (un tipo de producto o servicio –todavía no se sabe bien– para el pequeño negocio, asociado a las comunicaciones). A todo esto, la Free Software Foundation, liderada por el conocido Richard Stallman, ha comenzado su campaña particular contra Vista en un nuevo sitio llamado www.badvista.org. Quien suscribe tuvo oportunidad de pulsar las opiniones sobre tecnología (y sobre política) de Stallman a su paso por la Universidad de Deusto. La entrevista está disponible en mi sitio: http://www.elavefenix.net/Panorama/Stallman.htm.

Documentos en la Red Documentación de C# 3.0 y LINQ en castellano. Desde

<<dotNetManía

Zhenan Bao, de la Universidad de Stanford (USA) está liderando las investigaciones para conseguir el crecimiento de cristales semiconductores orgánicos sobre una superficie, lo que podría revolucionar la llamada “electrónica flexible”. La técnica es barata de producción, y podría mejorar también el rendimiento de muchos de los dispositivos existentes hoy en día, dado que los transistores creados mediante esta técnica pueden funcionar hasta 3 veces más rápido que los que usamos en la actualidad, según sus autores. El lector interesado puede leer el artículo completo “Crystal printing promises flexible electronics”, en http://www.newscientisttech.com/article.ns?id=dn10791&feedId= online-news_rss20. La noticia puede complementarse con otra proveniente de Japón, donde el Dr. Takanori Fukushita, de la Universidad de Tokio, afirma haber conseguido un tipo de nanocable capaz de convertir la luz en electricidad, de modo similar a como lo hacen los semiconductores de los paneles solares, lo que podría ser crucial como sistema energético de los robots.

Utilidades del mes ImageMinimizer.Programa gratuito, pequeño y rápido que permite cambiar el formato, calidad y tamaño de cualquier gráfico. Incluso admite comandos del tipo “Enviar a” y el cambio de un conjunto de gráficos simultáneamente. Accesible en el sitio web http://www.phoenixbit.com/site/products.asp?productid=imageminimizer.

hace unos días están disponibles públicamente traducciones al castellano de varios documentos preliminares de C# 3.0 y LINQ, realizadas por nuestro editor técnico Octavio Hernández. Estos documentos son: • Especificación de C# 3.0: http://www.microsoft.com/spanish/msdn/articulos/archivo/041206/voices/CSharp3 Specification.mspx. • Presentación técnica de ADO.NET vNext: http://www. microsoft.com/spanish/msdn/articulos/archivo/041206/voices/ADONETTechPreview.mspx. • Próximamente aparecerán otras traducciones de documentos relacionados con LINQ.

Giveaway of the Day. Podemos traducirlo como “Regalo del

Altamente recomendado a todo el que quiera estar al tanto de lo que nos deparan las próximas versión de C# y ADO.NET (ambas repletas de novedades basadas en LINQ).

Sitio del mes

Explore ASP.NET 2.0 Web Part Infrastructure . El

58

La electrónica flexible promete una nueva era de productos

conocido sitio DevX publica este mes este documento sobre los WebParts donde hace un recorrido bastante completo de la infraestructura y mecanismos de desarrollo de estos populares controles de servidor de la versión 2.0 de ASP.NET: http://www.devx.com/codemag/Article/33332?trk=DXRSS _LATEST.

día”. Es un sitio donde diariamente se pone a la disposición de los usuarios software shareware, pero de forma gratuita durante 24 horas. Una razón para visitar el sitio con frecuencia. Dispone, además, de una sección específica para desarrolladores. Disponible en http://www.giveawayoftheday.com.

Coding4Fun. Interesante centro para desarrolladores alojado en MSDN, con secciones de desarrollo para Windows, Web, juegos, hardware y eventos. Un diseño muy “fashion”, a lo Vista, y referencias organizadas a todas las API y SDK necesarias para el desarrollador curioso. Disponible en http://msdn.microsoft.com/coding4fun. Windows InstallerTeam Blog. El nombre lo dice todo. El equipo de Windows Installer y sus “cuitas” con las API y procesos de instalación. Muy específico. Para tener en la reserva cuando algo “se resiste”… http://blogs.msdn.com/windows_installer_team.


dotNetManía #033  
Read more
Read more
Similar to
Popular now
Just for you