El Calendario que le estaba faltando a WPF

Transcripción

El Calendario que le estaba faltando a WPF
www.dotnetmania.com
nº 45 febrero 2008 6,50 €
Visual Basic • C# • ASP.NET • ADO.NET • SQL Server • Windows System
dotNetManía
dedicada a los profesionales de la plataforma .NET
El Calendario que le estaba faltando a WPF
El Marco de trabajo de entidades de ADO.NET v3.5 (II) • VS 2005 Team Edition para profesionales
de bases de datos (y II) • Manejadores de eventos en SharePoint 2007 • Componentes de uso
general. Acceso a datos • Una isla para Visual Basic en dotNetManía
Comunidad.NET
AndorraDotNet
TodotNet@QA
Cachés globales y Silverlight
Laboratorio.NET
Visual Guard .NET
entrevista
Don Syme
Investigador
Microsoft Research
editorial
dotNetManía
Dedicada a los profesionales de la plataforma .NET
Vol. III •Número 45 • Febrero 2008
Precio: 6,50 €
dotNetManía, año 5to.
Redactor jefe
Marino Posadas
([email protected])
Editor técnico
Octavio Hernández
([email protected])
Redacción
Dino Esposito, Guillermo 'Guille' Som, José
Manuel Alarcón, Luis Miguel Blanco y Miguel
Katrib (Grupo Weboo)
Empresas Colaboradoras
Alhambra-Eidos
Krasis
Plain Concepts
Raona
Solid Quality Learning
Además colaboran en este número
Daniel Seara, Gustavo Vélez, Iskander Sierra,
José Luis Latorre, Mario del Valle, Rubén
Garrigós y Unai Zorrilla.
Corresponsal para América Latina
Pablo Tilotta
Ilustraciones
Mascota (Clico): Yamil Hernández
Portada: Javier Roldán
Fotografía
Roberto Mariscal
Atención al suscriptor
Pilar Pérez
([email protected])
Edición, suscripciones y publicidad
.netalia
c/ Thomas Edison, 4 Oficina 1406
Parque empresarial Rivas Futura
28521 - Rivas Vaciamadrid (Madrid)
www.dotnetmania.com
Tf. (34) 91 666 74 77
Fax (34) 91 499 13 64
Imprime
Gráficas MARTE
ISSN
1698-5451
Bienvenido al número 45, de febrero de
2008, de dotNetManía.
Con éste comenzamos el quinto volumen, y con él nuestra declaración de intenciones para este año: dotNetManía online. Empecé a editar contenidos en formato digital en 1991 (clippeRmanía); desde
ese momento hasta la fecha he participado en varios proyectos de contenidos digitales que no terminaron de cuajar, a pesar
de las evidentes ventajas... ¿quizá no era el
momento? Ahora sí creo que pueda ser el
momento de combinar la documentación
impresa con la documentación online, y
éste será nuestro principal propósito en los
próximos meses.
Durante los días 26 y 27 de febrero se
celebrará a nivel mundial el lanzamiento
de Visual Studio 2008, junto con el de
SQL Server 2008 y de Windows Server
2008, en el que será, posiblemente, el
evento más importante en la historia de
Microsoft. Me consta que en España se
están haciendo enormes esfuerzos para
conseguir una afluencia de miles de profesionales. La cita será en el Palacio de
Congresos de Madrid y el evento se llama Microsoft Tech Days.
Y hablando de eventos, este mes informamos de Envision, un evento para diseñadores celebrado en Milán. Que una
revista para desarrolladores como es ésta
cubra, aunque sea mínimamente, un evento para diseñadores, puede ser síntoma de
que algo está cambiando. Que en un evento para diseñadores se hable de interfaces
de usuario, aplicaciones móviles, Web
2.0..., lo confirma.
Este mes entrevistamos a Don Syme,
principal artífice de F#, un lenguaje con
capacidades para el cálculo matemático.
Don nos demuestra cómo la pasión por lo
que uno hace es el mejor argumento comercial. Marino Posadas no deja de hablar
maravillas de este lenguaje desde que entrevistó a Don y sin duda convencerá al más
pintado. Tenga cuidado con su lectura, no
vaya a convencerle también. Si despierta su
interés y quiere conocer más sobre éste u
otros lenguajes .NET, le recomiendo una
visita a http://www.dotnetlanguages.net.
El Grupo Weboo vuelve a ocupar la
portada con “El calendario que le estaba
faltando a WPF”, continuando con la saga
relacionada con elementos avanzados de
WPF. En este caso, nos explican cómo
definir un control personalizado desde
cero, usando como ejemplo el gadget
Calendario de Windows Vista y mostrando cómo se implementaría en WPF.
Interesante artículo el que Gustavo
Vélez publica bajo el largo y descriptivo
título: “Manejadores de eventos en SharePoint 2007. Los flujos de trabajo no
siempre son necesarios para hacer que las
cosas funcionen bien”. Con la integración de Workflow Foundation y SharePoint 2007, la utilidad que los manejadores de eventos tenían a la hora de crear
flujos de trabajo desaparece en su mayor
parte. Sin embargo, Gustavo nos describe las tareas donde usar manejadores de
eventos en lugar de flujos de trabajo es
más conveniente.
Finalmente, Guillermo “Guille”
Som se ha comprado una isla, la isla de
Visual Basic en dotNetManía, y la ha
llamado Isla.VB. Una columna o reducto para los programadores que quieran
ver código Visual Basic de la mano del
viejo maestro, que dice estar rodeado de
“cesharperos” por todas partes.
Depósito Legal
M-3.075-2004
Paco Marín
<< dotNetManía
Editor
Paco Marín
([email protected])
3
sumario 45
Entrevista a Don Syme
10-12
En el pasado Tech-Ed se hablaba mucho de un nuevo lenguaje de la familia #. Ya son 4 ó 5 (F#,
S#, P#, etc.), pero éste en concreto dispone de características para el cálculo matemático que
cualquier científico valorará. Su artífice principal es Don Syme, investigador en Microsoft Research
Cambridge (Reino Unido), cabeza del equipo de investigación de aspectos avanzados del CLR en su
versión 2.0, amable persona y excelente demostrador de las cualidades de “su lenguaje”.
El Marco de trabajo de entidades de ADO.NET v3.5 (II)
14-17
En nuestro anterior artículo [1] hicimos una introducción al Marco de entidades de ADO.NET
3.5, en la que se trató de dar especial importancia a la capacidad de éste para crear una capa de
abstracción sobre el modelo relacional. Esta abstracción, a la postre, nos permitirá centrarnos en una
programación más conceptual, enfocada en el dominio del negocio que deseamos modelar. En esta
entrega y las siguientes veremos cómo modelar nuestro dominio de trabajo y cómo mapear el mismo
contra el almacén relacional sobre el que estemos trabajando.
VS 2005 Team Edition para profesionales de bases de datos (y II)
18-22
Visual Studio 2005 Team Edition for Database Professionals es la herramienta para profesionales
de base de datos de la plataforma Visual Studio. Desplegar nuevos entornos de datos, refactorizar
objetos, realizar pruebas unitarias de la base de datos... todo se vuelve sencillo con DataDude.
El Calendario que le estaba faltando a WPF
24-30
Con este artículo continúa la saga relacionada con elementos avanzados de WPF. En el último de
estos trabajos, vimos cómo definir un control personalizado, al presentar un “scroll circular”. Sin
embargo, en aquel caso realmente bastó con asociarle las plantillas y estilos adecuados al control
básico ScrollBar ya existente en WPF.
Manejadores de eventos en SharePoint 2007.
Los flujos de trabajo no siempre son necesarios para hacer que las cosas funcionen bien.
32-36
Los manejadores de eventos de SharePoint 2007 son más que una herencia de la versión 2003: en
WSS y MOSS 2007 han sido ampliados y enriquecidos considerablemente. Ahora pueden ser
utilizados a lo largo y ancho del sistema, y su modelo de objetos ha sido mejorado en diferentes
direcciones. Los manejadores de eventos permiten realizar algunas de las tareas que los flujos de
trabajo están en capacidad de ejecutar, pero de una forma mucho más sencilla y efectiva, e inclusive
pueden anticiparse a eventos, algo que es difícil de realizar con flujos de trabajo.
Componentes de uso general.Acceso a datos
38-42
Comenzamos aquí el desarrollo del primer componente de funcionalidad compleja. Dada la
importancia que tiene a la hora de desarrollar aplicaciones, comenzaremos con el acceso a datos,
explicando según se desarrolla los fundamentos y consideraciones en los que basa, para que se pueda
usar, modificar o repensar completamente y que os pueda ser realmente útil.
Una isla para Visual Basic en dotNetManía.
O cómo hacer las cosas mejor con Visual Basic.
44-48
Con el quinto año de dotNetManía estrenamos una nueva columna en la revista dedicada
exclusivamente a los que gustan desarrollar con Visual Basic. No es que antes no hubiera nada para
Visual Basic, pero ya iba siendo hora de que tuviésemos nuestro propio rincón. En esta isla
tendremos ocasión de ver muchas cosas relacionadas con Visual Basic, particularmente con la versión
9.0, que es la que se incluye en Visual Studio 2008, aunque muchos conceptos serán válidos también
para las versiones anteriores.
dnm.todotnet.qa
Cachés globales y Silverlight
49-51
dnm.laboratorio.net
52-54
Visual Guard .NET
dnm.biblioteca.net
55
Silverlight 1.0 Unleashed
Silverlight 1.0
dnm.comunidad.net
56-57
AndorraDotNet. Grupo de usuarios .NET de Andorra
dnm.desvan
58
<<dotNetManía
noticias noticias noticias noticias
noticias
6
Microsoft Ibérica presenta
Visual Studio 2008 en castellano
La compañía presentó la versión en castellano de Visual Studio 2008 y de .NET
Framework 3.5, como paso previo al Microsoft Tech Days, el mayor evento de
lanzamiento realizado hasta la fecha por Microsoft, en el que además de Visual Studio
2008 se presentarán SQL Server 2008 y Windows Server 2008.
Microsoft Ibérica presentó el pasado 15 de enero la versión
en castellano de Visual Studio 2008 y de .NET Framework
3.5. Según Enrique Fernández-Laguilhoat, director de
Plataforma y Desarrollo de Microsoft Ibérica, “Visual Studio 2008 posibilita una nueva generación de aplicaciones
con una experiencia de usuario revolucionaria, ya que proporciona toda la potencia de la plataforma Windows Presentation Foundation, con la productividad del IDE (Integrated Development Environment), y una integración con
nuestras herramientas de diseño, Microsoft Expression, que
permiten la colaboración entre desarrollador y diseñador.
Por su parte, los servicios online –que Microsoft lleva impulsando desde el nacimiento de .NET en 1999– están transformando el mercado TIC. Nuestra compañía ha encontrado en este mundo de servicios a través de Internet otra
forma de seguir proporcionando valor al cliente, combinándolos de forma equilibrada con nuestras ofertas líderes de software de sobremesa y servidor. Se trata de ofrecer a nuestros partners nuevas vías de hacer negocio sobre
una plataforma que liderará el futuro de Internet. Visual
Studio 2008 permite desarrollar este tipo de aplicaciones
de una forma productiva, ágil e integrada con tecnologías
como LINQ, WCF y WF.”
El mercado de desarrollo de software en España
Enrique Fernández-Laguilhoat aprovechó para dar
cifras del estado actual del mercado de desarrollo en
España, además de dar un repaso a todas las novedades de
Visual Studio 2008 y un rápido repaso a los avances de los
últimos años, desde las tecnologías cliente-servidor, las
aplicaciones distribuidas, más tarde servicios Web y finalmente entramos en el concepto de software+servicios en
el que se engloba Visual Studio 2008.
Actualmente, el mercado del desarrollo de software
cuenta con 97.500 desarrolladores profesionales en
España (algunas fuentes estiman esta cifra en 130.000),
de los cuales 61.500 están repartidos en 8.500 empresas
de desarrollo a medida, 7.000 son programadores en
1.200 ISV y 29.000 son desarrolladores corporativos
(grandes bancos, organismos oficiales, con desarrolladores en nómina).
Según la compañía, el 70% de los desarrolladores ha
adoptado la tecnología .NET, y en cifras globales los
desarrolladores de .NET y los desarrolladores de Java
están prácticamente a la par en estos momentos. La
comunidad de desarrolladores en España ha venido creciendo y organizándose, de modo que hasta la fecha existen 20 grupos de usuarios con 4.000 miembros y 39 MVP
certificados. Por su parte, MSDN online ha registrado
30.000 inscripciones y en los programas de betatesting y
pruebas han participado 11.000 desarrolladores. Además,
se han realizado 35.000 y 2.800 descargas de las versiones Express y de prueba de Visual Studio, respectivamente.
Microsoft Tech Days: presentación Mundial de Visual
Studio 2008,Windows Server 2008 y SQL Server 2008
Los días 26 y 27 de
febrero son los designados
para el lanzamiento mundial de Visual Studio 2008,
SQL Server 2008 y Windows Server 2008 y. El evento en español tendrá lugar
en el Palacio Municipal de Congresos de Madrid.
Junto con la presentación de estas tres nuevas soluciones, se contactará con la presentación que Steve Ballmer realizará ese mismo día en Estados Unidos. También se contará con la presencia de Rosa Mª García,
presidenta de Microsoft Ibérica, además de los responsables del área de Desarrollo y Plataformas de la compañía en nuestro país.
Si quiere más información, puede visitar la página
www.microsoft.es/lanzamiento.
Disponibilidad de Visual Studio 2008 en castellano
La versión en castellano de Visual Studio 2008 estará
disponible a partir del 1 de febrero para los suscriptores
MSDN en España. Más información y descargas en
http://www.microsoft.com/spanish/msdn/latam/visualstudio2008.
<< dnm.directo.noticias
Sun Microsystems adquiere MySQL
El acuerdo acelera la estrategia de crecimiento de Sun, que
toma una relevante posición en un mercado mundial de bases
de datos que asciende a más de 15.000 millones de dólares.
Sun Microsystems anuncia que ha llegado a un acuerdo definitivo para adquirir MySQL AB, uno de los máximos
iconos de la tecnología Open Source y
desarrollador de una de las bases de
datos sobre código abierto de mayor
crecimiento del mundo. La adquisición
se llevará a cabo por aproximadamente
1.000 millones de dólares.
Una vez se complete la transacción
propuesta, MySQL se integrará en las
organizaciones de Software, Ventas y
Servicios de Sun, y Marten Mickos,
hasta ahora CEO de MySQL, pasará a
formar parte del equipo directivo de
Sun. Mientras tanto, un equipo conjunto formado por representantes de
ambas compañías desarrollará los planes de integración basados en las sinergias técnicas, de producto, así como
culturales y las mejores prácticas de
negocio y desarrollo de ambas compañías. MySQL tiene su sede central
en Cupertino, California, y Uppsala,
Suecia, y cuenta con 400 empleados en
25 países.
La base de datos open source
MySQL es la “M” en el acrónimo
LAMP –la plataforma de software
compuesta por la unión de las tecnologías de sistema operativo Linux, el
servidor web Apache, el gestor de base
de datos MySQL y los lenguajes de
programación PHP/Perl–. Sun está
comprometida en mejorar y optimizar las tecnologías LAMP sobre
GNU/Linux y Microsoft Windows
junto con OpenSolaris y Mac OS/X.
Se espera que la operación quede
totalmente cerrada a finales del tercer
trimestre o principios del cuarto del año
fiscal 2008.
El código fuente de .NET
Framework disponible
Microsoft ha liberado el código fuente de
las librerías de .NET Framework, permitiendo su depuración con Visual Studio
2008. Está disponible el código de las
siguientes librerías:
- .NET Base Class Libraries (System, System.CodeDom, System.Collections, System.ComponentModel, System.Diagnostics,
System.Drawing, System.Globalization,
System.IO, System.Net, System.Reflection, System.Runtime, System.Security,
System.Text, System.Threading, etc).
- ASP.NET ( System.Web, System.Web.
Extensions).
- Windows Forms ( System.Windows.
Forms).
- Windows Presentation Foundation
(System.Windows).
- ADO.NET y XML (System.Data y System.Xml).
En breve, se incluirán nuevas librerías,
incluyendo LINQ, WCF y Workflow. Más
información en: http://weblogs.asp.net/scottgu.
Microsoft presenta Microsoft Dynamics CRM 4.0
La nueva versión de Microsoft Dynamics CRM incorpora más de 200 novedades con una experiencia
de usuario muy familiar, ya que está integrada con las herramientas de Microsoft Office.
• Una avanzada arquitectura multiempresa (multi-tenant) que soporta
varios clientes por servidor.
• Nuevas capacidades globales que ofrecen al usuario la posibilidad de elegir
entre más de 25 idiomas y múltiples
divisas.
• Nuevas capacidades de Business Intelligence, con nuevas vistas y asistentes
de informes para el usuario final.
• Automatización de procesos avanzada gracias a la integración con
Microsoft Windows Workflow
Foundation.
• Nuevas posibilidades de colaboración
con Microsoft Office Communications Server 2007, con indicadores de
presencia en tiempo real dentro de la
propia aplicación CRM.
Disponibilidad de la solución
Microsoft
Dyna mics CRM
4.0 ya está disponible en inglés,
alemán, fran cés,
holandés, español,
danés y finlandés.
El resto de idiomas se irán lanzando a lo largo de
las próximas semanas. Los clientes actuales con un plan de mantenimiento activo
(Software Assurance) pueden disponer de
la nueva versión sin cargo adicional.
La solución hospedada por Microsoft,
“Microsoft Dynamics CRM Live” se ofrece solo en Estados Unidos y Canadá.
<<dotNetManía
Microsoft ha presentado su nuevo software
de gestión de relaciones con clientes, Microsoft Dynamics CRM 4.0, anteriormente
conocido como Titan. La nueva versión se
ofrece bajo dos nombres de producto:
Microsoft Dynamics CRM 4.0 para las
implantaciones en local y hospedadas por
partners y Microsoft Dynamics CRM Live
para la solución hospedada por Microsoft.
Al haber sido diseñada con un mismo
código base tanto para las implantaciones
en local como hospedadas, los clientes
podrán elegir el modelo que mejor se adapte a sus necesidades, con la flexibilidad de
cambiar de opción en función de la evolución de dichas necesidades.
Microsoft Dynamics CRM 4.0 ofrece
más de 200 novedades, entre las que se
incluyen:
7
eventos
<<dotNetManía
eventos
ENVISION
8
Influencing digital communication
El pasado mes de enero se celebró en
Milán, Italia, un evento sin precedentes, dedicado a la forma en que diseñamos y comunicamos mediante los nuevos medios digitales. Todo ello sin concretar tecnologías y de
una forma general, sin entrar en técnicas ni
herramientas, simplemente centrándose en
conceptos, y en las nuevas tendencias de
diseño y líneas de investigación en todos los
ámbitos, desde la creación de logotipos hasta las interfaces de usuario.
Este evento fue Envision, http://www.
envision-event.com, un curioso (y, a todas
luces, exitoso) experimento cuyo planteamiento era una interactividad total entre
ponentes y asistentes, con un número bastante reducido de estos últimos. Se estructuró alrededor de la realización de ponencias seguidas de una tanda de preguntas al
ponente, estableciendo un diálogo directo con los asistentes. La última sesión
correspondió a una distribución de los ponentes entre
las mesas en que estaban ubicados los asistentes, lo que
provocó unas conversaciones muy interesantes.
En Envision pudimos contemplar, desde el punto
de vista de varias figuras internacionales del diseño, la
evolución de las tecnologías y cómo los cambios sociales afectan a las comunicaciones digitales y a las formas de transmitir mensajes. Tuvimos la suerte de contar con la presencia de figuras como Matt Bagwell,
Giles Colborne, August De Los Reyes, Catriona
Campbell, Phil Gerrard, Wolfgang Henseler, Frederick Fuchs, Pete Barr-Watson y James Deeley, todos
ellos expertos reconocidos internacionalmente en sus áreas. Para más información sobre los ponentes, visite
http://www.envision-event.com/agenda/bios.aspx.
Durante el evento se pudieron vislumbrar tendencias como el diseño simplista, estilo “KISS –Keep It
Simple, Stupid–”; el análisis del impacto emocional de
determinados diseños, psicoanalizándolos literalmente; el análisis de lo verdaderamente relevante; la evolución de las interfaces y la nueva moda “multitouch”,
adaptando las interfaces a nuevas formas de interactuar
mucho más naturales; la definición del diseño como un
nuevo lenguaje, y con él, cómo reacciona el ser humano al mismo, evaluando la respuesta emocional de las
personas; y lo que se define como emotional designer,
que busca un diseño motivado casi exclusivamente por
su impacto emocional en las personas.
También se expusieron los procesos de diseño que
buscan que éste provoque un impacto en el público, causando fuertes experiencias con el resultado de una retención de información mucho más efectiva. Y tuvimos el
placer de ver otras líneas de diseño que han aparecido
debido a las nuevas tecnologías, como el diseño minimalista, derivado de las nuevas necesidades de interfaces “mínimas” para dispositivos móviles, o cómo afecta
el fenómeno Web 2.0 al diseño. Por último, se expuso
el roadmap de la nueva línea de productos Microsoft para
diseñadores y cómo el gigante informático pretende
potenciar todas estas líneas de negocio y facilitar su integración con el mundo, a veces opuesto, del desarrollo.
Sin duda, todo apunta a una nueva era, en la que el
diseño y todas las aplicaciones del mismo van a ocupar
un lugar primordial, haciendo mucho más agradable
nuestra forma de percibir e interactuar con la tecnología.
Un nuevo diseño que nos sea emocionalmente mucho
más agradable y extremadamente natural y fácil de usar.
Sin duda, toda una visión de futuro... ¿o debería decir
“de presente”?
José Luis Latorre
entrevista
Marino Posadas
entrevista a
Marino Posadas
es director de tecnologías de desarrollo para España
y Portugal de Solid
Quality Mentors.
Puedes leer su blog
en http://www.
elavefenix.net.
Don Syme
En el pasado Tech-Ed se hablaba mucho de un
nuevo lenguaje de la familia #. Ya son 4 ó 5
(F#, S#, P#, etc.), pero éste en concreto
dispone de características para el cálculo
matemático que cualquier científico valorará.
Su artífice principal es Don Syme, investigador
en Microsoft Research Cambridge (Reino
Unido), cabeza del equipo de investigación de
aspectos avanzados del CLR en su versión
2.0, amable persona y excelente demostrador
de las cualidades de “su lenguaje”.
Aunque lo hemos comentado en
privado, ya es proverbial que el entrevistado se introduzca a sí mismo…
Claro, mi nombre es Don Syme,
trabajo en Cambridge, y podría decirse que tengo dos áreas de interés: una
relacionada con la División de Desarrollo, y otra como investigador. Mi trabajo en los últimos 10 años ha sido el
de aportar novedades al paisaje de ofertas que constituye .NET, y que luego
son implementadas en lenguajes como
C#, Visual Basic, y ahora también en
F#.
Respecto a mi pasado, bueno, soy
Doctor en Informática, y quizás la par-
te más conocida de mi obra es algo que
muchos desarrolladores utilizan todos
los días: los tipos genéricos, que se
introdujeron en la versión 2.0 de .NET.
De hecho, ese proyecto comenzó hace
muchos años, en 1999.
Además, ha sido una de las características de la versión 2.0 que, por un
lado, era la más solicitada, y por otro,
la más ampliamente aceptada y utilizada, cuando ha estado disponible.
Los genéricos fueron un trabajo ligado, en sus inicios, a los lenguajes exclusivamente, y luego hicimos un gran esfuerzo para incorporarlos al CLR de forma
transparente, en la forma que pueden utilizarse desde la versión 2.0.
Sin embargo, respecto a los nuevos cambios en los lenguajes .NET
3.5, hay una variedad de opiniones.
La mayoría piensa que son muy interesantes y aportan productividad,
pero también hay voces detractoras
de algunas novedades como los
métodos extensores, que para más
de uno rompen con los principios de
la programación orientada a objetos.
Interesantísimo el tema. Verás, yo
mismo no soy un defensor de ese tipo
de extensiones, digamos que no es mi
favorita. Y supongo que, al final, será
una cuestión de buenas prácticas en la
forma en que se utilicen. Pero es indudable que podemos encontrar escenarios donde los métodos extensores son
totalmente requeridos si queremos dar
con una solución sencilla.
Y, además, como investigadores
estuvimos trabajando en la forma de
hacer que estas extensiones no rompieran en ningún momento la extraordinaria arquitectura sobre la que está
basada el CLR. Eso era un objetivo primordial, y algunas de las limitaciones
impuestas para su uso vienen de esas
consideraciones. Es lo mismo que ocurre con LINQ. Creo que son características muy poderosas, muy interesantes de cara al desarrollador, pero que
es responsabilidad del usuario usarlas
en el escenario
correcto y en el sitio
correcto.
Mi respuesta es
no, pero quiero
saber la tuya. Y esto
viene a tenor de
algunos comentarios que leí en tu
Web. ¿Programar
en un lenguaje
seguro es hacer programación segura?
Es muy importante la seguridad de
tipos, es muy importante que el lenguaje y la plataforma
ofrezcan características programables
de seguridad, y es muy importante la
seguridad que ofrece la ejecución en un
entorno como el CLR, con sus características de verificación, que son amplí-
simas. Pero –efectivamente– por mucho
que haga la plataforma, la programación segura es una decisión de los analistas, planificadores y codificadores.
Siempre habrá prácticas incorrectas de
programación si el código no tiene en
cuenta la seguridad.
Como vamos a hablar del lenguaje nuevo dentro de nada, quiero
comenzar por una pregunta que
–desde los desarrolladores, hasta
alumnos míos de post-grado en universidades– me han hecho con respecto a los lenguajes: ¿hacía falta
otro lenguaje nuevo, ahora que parece que, en esta materia, está todo
inventado?
Pues creo que sí, porque –una vez
más– depende de la tarea que quieras
hacer. Cuando veo a gente trabajar en
F# porque quieren abordar cierto tipo
de problemas, y los veo avanzar muy
rápidamente en la solución, me convenzo de que sí. De que cada tipo de problemática tiene, idealmente, su lenguaje; aquel en el que el problema a resolver se expresa con más sencillez y ofrece un mejor tiempo de respuesta.
Una de las contradicciones de la
situación es ésa: por un lado, hay una
convergencia clara en los lenguajes, y
la mayoría de usuarios se decanta por
las opciones C# o VB.NET en .NET,
e incluso tenemos Java (similar sintácticamente a C#) en otras plataformas,
<<dotNetManía
<< dnm.directo.entrevista
11
<<dotNetManía
<< dnm.directo.entrevista
12
y por otro, también puedes programar
en lenguajes funcionales, cosa que no
era posible hace 10 años en la forma en
que lo es hoy en día. Y estamos notando que incluso desarrolladores de otras
plataformas se están sintiendo atraídos
por F#, por lo que pueden aprender a
hacer con el lenguaje y porque es una
experiencia gratificante observar cómo
este lenguaje soluciona algunos problemas clásicos del cálculo, su elegancia, su simplicidad y su potencia.
De hecho, para su diseño nos fijamos en características de muchos lenguajes, desde Prolog, pasando por lenguajes funcionales, a muchos otros de
tipo más experimental. Incluso en el
propio lenguaje SQL, con toda su
potencia expresiva.
Bueno, pues vamos a hablar de
F# como lenguaje…
Tenemos un equipo de trabajo en
Cambridge, dedicado al desarrollo de
este lenguaje, y también contamos con
dos personas en Redmond. Y la forma
en que yo lo veo tiene mucho que ver
con la programación funcional. Es crucial en los tipos genéricos, en LINQ,
en los lenguajes funcionales, claro, y
también lo es aquí.
Debido a las características propias
que tiene, F#, junto a otros lenguajes
de la plataforma, convierten a .NET en
una plataforma multi-paradigmática,
donde manteniendo los criterios fundamentales, contamos con una variedad enorme de posibilidades para realizar las tareas. En F#, por ejemplo,
podemos abordar la representación gráfica de funciones (tanto en 2D como en
3D) de una manera simplísima y con un
rendimiento espectacular. Esto permite eliminar muchas complicaciones propias de lenguajes que no han sido pensados para esto, sino para representar
entidades, y conseguir un código sucinto, que te permite empezar a jugar con
el lenguaje, obtener inmediatamente
resultados de esas pruebas, y acabar,
como si acabas un juego, con una aplicación completa que resuelve un problema concreto.
Desde el punto de vista de las
novedades, por decirlo así, ¿cuál dirías
que es la oferta de F# como lenguaje?
Supongo que es una combinación de
factores muy productivos desde el punto
de vista operativo (Don echa mano de
su portátil y comienza a hacernos una
demo del lenguaje). Como ves, la sintaxis del lenguaje es muy bella, y solo
necesita plantear como sentencias los
objetivos que se persiguen. Si te das cuenta, estamos obteniendo resultados de forma rapidísima, con muy poco código, que
además resulta muy fácil de comprender,
precisamente por la misma razón. Y la
rapidez es una de las cosas que más llama
la atención. La gente no puede creer que
operaciones como la que estamos planteando ahora (era un cálculo matricial
con matrices de 10000 elementos),
puedan dar una respuesta tan inmediata.
Y además, F# puede combinarse con
otros lenguajes, de forma que F# ofrezca
la solución que podamos necesitar desde
un punto de vista de cálculo numérico
mientras el resto de nuestra aplicación
está hecha en C# o VB.NET o lo que nos
parezca bien. Podemos disfrutar de las
ventajas que ofrece cada lenguaje, sin
abandonar ninguno de los pilares sólidos
que nos da la plataforma, y haciendo que
cada lenguaje se ocupe de aquello que
hace más eficazmente. Por ejemplo, hacer
lo que estamos haciendo ahora en C++
(estaba representando gráficamente
los contenidos de la matriz inversa de
una dada, en una superficie tridimensional) no solo nos llevaría muchísimo
más tiempo de codificación, sino que no
tendríamos la inmediatez de la representación gráfica, y mucho
menos este tiempo de
respuesta.
Además, en todos
los procesos de re-cálculo, cuando cambiamos las condiciones
originales, como puedes ver (y lo podíamos
ver; créame el lector,
que no salíamos de
nuestro asombro),
todo el proceso es casi
instantáneo…
Desde luego, ya me hubiera gustado tener algo así cuando estudiaba Física en la universidad…
De hecho estoy escribiendo un libro
–junto a Jon Harrop– titulado precisamente “F# para científicos”, en el que
tratamos cómo resolver la mayor parte de los problemas matemáticos relacionados con el cálculo: desde las características que has visto, hasta transformadas de Fourier, implementación de
operadores especiales como lagrangianos, hamiltonianos, etc.
Pues vamos a recomendar los
sitios Web de ambos, si te parece,
para los lectores que quieran introducirse en el lenguaje. El oficial de
MS-Research (http://research.microsoft.com/fsharp/fsharp.aspx), el tuyo
(http://blogs.msdn.com/dsyme) y el de
Jon (http://fsharpnews.blogspot.com).
Desde el punto de vista bibliográfico, también he visto un libro en la
editorial APress…
Sí, se llama “Expert F#”, y –aparte de
mí– colaboraron en él Adam Granicz y
Antonio Cisternino. Creo que es una
buena introducción al tema. Y además,
ya hay mucha gente haciendo eco de las
características del lenguaje en numerosos blogs, y pensamos seguir incorporando gente al equipo a medida que el
proyecto siga creciendo.
Unai Zorrilla
Octavio Hernández
plataforma.net
El Marco de trabajo de entidades
de ADO.NET v3.5 (II)
En nuestro anterior artículo [1] hicimos una introducción al Marco de
entidades de ADO.NET 3.5, en la que se trató de dar especial importancia a la capacidad de éste para crear una capa de abstracción sobre
el modelo relacional. Esta abstracción, a la postre, nos permitirá centrarnos en una programación más conceptual, enfocada en el dominio
del negocio que deseamos modelar. En esta entrega y las siguientes veremos cómo modelar nuestro dominio de trabajo y cómo mapear el mismo contra el almacén relacional sobre el que estemos trabajando.
Unai Zorrilla es
Development Team
Leader de Plain Concepts
y tutor de campusMVP.
MVP desde 2004,
colabora activamente con
Microsoft en eventos de
arquitectura y
desarrollo, así como en
giras de productos. Autor
del libro "Modelando
procesos de negocio con
Workflow Foundation".
Octavio Hernández es
Mentoring Team Leader
de Plain Concepts, editor
técnico de dotNetManía y
tutor de campusMVP.
Es MVP de C# desde
2004, MCSD y MCT.
Autor del libro "C# 3.0 y
LINQ".
Si juntáramos en una misma sala a un programador de algún lenguaje orientado a objetos y a un
DBA para modelar un determinado sistema, el
modelo de clases y el modelo relacional generado por cada uno de ellos seguramente distarían
muchísimo uno de otro. El programador modelaría el proceso teniendo en cuenta conceptos
como la herencia de clases, el polimorfismo, la
agregación de tipos y el uso de contratos como
las interfaces; además, tendría en cuenta distintas
métricas para valorar la calidad del modelo: profundidad de la herencia, complejidad del código,
etc. y procuraría aplicar patrones de diseño para
resolver problemas ya conocidos. Por otra parte,
el DBA crearía su modelo relacional teniendo en
cuenta factores muy distintos a los anteriores;
algunos de estos factores podrían ser el estudio
de las formas normales, la integridad referencial
y el uso de índices apropiados. Ambos tendrían
argumentos de sobra para defender los modelos
creados, y sin lugar a dudas ambos tendrían razón.
Esta impedancia entre ambos mundos es la que
se lleva mucho tiempo intentando resolver, teniendo como objetivo que ambas partes puedan trabajar sobre sus modelos e intentando que ninguno tenga que realizar demasiadas concesiones al
otro.
El Marco de entidades de ADO.NET v3.5 nos
permitirá crear de una forma relativamente sencilla una capa de abstracción sobre el modelo relacional, posibilitando así el desarrollo de un modelo acorde con un lenguaje orientado a objetos como
C# o Visual Basic. En esta entrega y las siguientes veremos cómo, a partir de un modelo relacional, podemos crear un modelo de objetos que haga
uso de la herencia, la agregación de tipos y la creación de tipos complejos o entidades.
Al igual que en el anterior artículo de esta serie
sobre el Marco de entidades, partiremos del modelo relacional FUTBOL2006, que a pesar de ser
un modelo sencillo, nos permitirá jugar con
Figura 1. Modelo lógico de FUTBOL2006
<< dnm.plataforma.net
La herramienta visual
de diseño
Como comentamos la vez anterior, el
Marco de entidades se apoya en tres
ficheros XML de metadatos: el modelo relacional del almacén se especifica
en el fichero SSDL y el modelo conceptual en el fichero CSDL, mientras
que el fichero MSL define un mapeado entre los dos modelos. Precisamente estos dos últimos son los que debemos modificar para reflejar nuestros
conceptos, y esas modificaciones pueden realizarse de dos maneras:
a) Editando manualmente los ficheros,
para luego validar su contenido y
generar los ficheros de código
correspondientes utilizando EDMGen.EXE. Presentamos las posibilidades que ofrece esta herramienta de
línea de comandos en nuestra entrega anterior.
b) Utilizando las herramientas visuales integradas en Visual Studio
2008 (actualmente parte de Entity
Framework Tools CTP). Ésta es la
vía que utilizaremos a partir de
aquí.
Para crear un modelo de datos del
Marco de entidades se deberá, sobre el
nodo correspondiente al proyecto en el
Explorador de soluciones, seleccionar
la opción “Add…” | “New item” |
“ADO.NET Entity Data Model”. Aparecerá un asistente que nos permitirá
elegir la base de datos de origen (también se puede generar un modelo a partir de cero, si se desea). El modelo inicial generado en nuestro caso se muestra en la figura 2.
[
Dentro de esta única
tabla tendremos una
columna, conocida
como discriminador,
que nos permitirá diferenciar según su valor
a qué tipo concreto
corresponde cada una
de las filas de la tabla.
Mediante esta estrategia, las consultas sobre
tipos distintos se realizan de una forma óptima, puesto que solamente tendremos que
realizar un filtro sobre
la columna que actúa
Figura 2. Modelo conceptual inicial de FUTBOL2006
como discriminador.
La entidad Futbolista
del modelo de la figura 2 es un ejemplo
Mapeando la herencia
en el que puede aplicarse una herencia
de tipos
por jerarquía, en la que la propiedad
Los modelos relacionales no soporPosicion nos permite discriminar los
tan de forma directa el concepto de
distintos tipos de futbolistas que se pueherencia de tipos. El Marco de entidaden establecer dentro de nuestro modedes, por su parte, prevé tres mecanislo de dominio. En el modelo relacional,
mos diferentes para modelar la herenla columna Posicion es de tipo nchar(1)
cia, que son:
y toma valores como ‘P’ para indicar que
• Tabla por jerarquía (Table per Hieel jugador es un portero, ‘D’ para indirarchy, TPH).
car que se trata un defensa o ‘M’ para
• Tabla por tipo concreto (Table per
indicar que la posición del futbolista es
Type, TPT).
la de mediocentro. Este conocimiento
• Tabla por subclase (Table per Subsobre el discriminador nos permite creclass, TPS).
En esta entrega y las siguientes veremos cómo modelar las relaciones de
herencia utilizando cada uno de estos
tres mecanismos.
Tabla por jerarquía
Esta técnica consiste en mapear toda
la jerarquía de tipos dentro de una misma tabla de nuestro modelo relacional.
NOTA
Cuando se crea un modelo de entidades mediante el asistente, Visual
Studio genera un fichero .EDMX que “condensa” en un único esquema
los contenidos de los ficheros .SSDL, .CSDL y .MSL. Al generar el proyecto, el contenido de este fichero se “desdobla” en las tres partes correspondientes en el directorio de salida.
]
Figura 3. Agregando entidades
al modelo conceptual
ar una jerarquía de clases en nuestro
modelo conceptual.
El primer paso a realizar será el de
eliminar de la entidad Futbolista la propiedad Posicion, para que posteriormente pueda ser utilizada en las condi-
<<dotNetManía
muchos de los conceptos antes mencionados. En la figura 1 puede verse
parte de este modelo relacional.
15
<< dnm.plataforma.net
ciones de mapeado de nuestras entidades lógicas al modelo relacional subyacente. De acuerdo con nuestro discriminador, crearemos dentro del modelo conceptual las entidades Portero,
Defensa, Mediocentro y Delantero; para
ello es suficiente con usar el menú contextual del modelo conceptual, como se
muestra en la figura 3.
La ventana de creación de entidades nos permitirá indicar si la nueva
entidad creada es una herencia de algún
tipo de entidad ya existente en el modelo; en nuestro caso, seleccionamos Futbolista como tipo base para esta nueva entidad (figura 4).
Figura 6. Modelo de herencia con tabla por jerarquía.
Figura 4. Creando la entidad Portero
con un tipo base
<<dotNetManía
Una vez creada la nueva entidad,
deberemos establecer qué valor de discriminador permite establecer que un
Futbolista es un Portero. La ventana de
detalles de mapeado nos permitirá indicar la tabla del modelo relacional a la
16
Figura 7. Diagrama de clases resultante
que se asocia esta entidad (por supuesto, la tabla Futbolista), y la condición
por la cual se establecerá que una fila
Figura 5. Mapeando la entidad Portero.
de esta tabla corresponde a una entidad
de tipo Portero (figura 5).
Si realizamos el mismo proceso para
las entidades Defensa, Mediocentro y
Delantero, obtendremos un modelo
conceptual similar al que se puede
observar en la figura 6.
Por supuesto, todo este trabajo realizado sobre el diseñador tiene su contrapartida en los ficheros CSDL y
MSL. Por un lado, dentro del modelo
conceptual tendremos definidas nuevas
entidades, como se puede ver en el fragmento XML del listado 1. El fichero de
mapeado, por su parte, contendrá nuevos elementos de tipo Condition,
<< dnm.plataforma.net
namespace DNM
{
using FUTBOL2006Model;
class Program
{
static void Main(string[] args)
{
FUTBOL2006Entities ctx = new FUTBOL2006Entities(
metadata=.\\Futbol2006.csdl|.\\Futbol2006.ssdl|.\\Futbol2006.msl;”
+ “provider=System.Data.SqlClient;”
+ “provider connection string=”
+ “\”Data Source=.;Initial Catalog=FUTBOL2006;Integrated Security=True\””
);
Listado 1. Nuevas entidades en el fichero CSDL
// a new kid in town...
Portero p = new Portero();
p.Nombre = “PABLO PELAEZ”;
p.Sexo = “V”;
p.FechaNacimiento = new DateTime(1973, 2, 18);
p.Club = ctx.Club.First(c => c.Codigo == “RMA”);
p.Pais = ctx.Pais.First(x => x.Codigo == “ES”);
// ¡observe que no hay propiedad Posicion!
ctx.AddToFutbolista(p);
ctx.SaveChanges(true); // persistir los cambios
mediante los cuales se especifican los
valores que debe tomar la columna discriminador para cada una de las nuevas
entidades creadas con tipo base Futbolista (listado 2).
Utilizando el modelo
obtenido
Una vez terminado el trabajo anterior, tendremos nuestro modelo conceptual y la
jerarquía de clases tal como nos los muestra el diagrama de clases de la figura 7.
Como la semana anterior, no quisiéramos terminar la columna sin mostrar
un pequeño ejemplo de código, para que
el lector vaya familiarizándose con el estilo de programación que promueve el
// porteros de equipos madrileños
var q = from c in ctx.Futbolista
where c is Portero && c.Club.Ciudad == “MADRID”
select c.Nombre;
// ejecutar la consulta
foreach (var s in q) Console.WriteLine(s);
Console.ReadLine();
}
}
}
Listado 3. Programa de ejemplo.
<EntityTypeMapping TypeName=”IsTypeOf(FUTBOL2006Model.Portero)”>
<MappingFragment StoreEntitySet=”Futbolista”>
<ScalarProperty Name=”Id” ColumnName=”Id” />
<Condition ColumnName=”Posicion” Value=”P” />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName=”IsTypeOf(FUTBOL2006Model.Defensa)”>
<MappingFragment StoreEntitySet=”Futbolista”>
<ScalarProperty Name=”Id” ColumnName=”Id” />
<Condition ColumnName=”Posicion” Value=”D” />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName=”IsTypeOf(FUTBOL2006Model.Mediocentro)”>
<MappingFragment StoreEntitySet=”Futbolista”>
<ScalarProperty Name=”Id” ColumnName=”Id” />
<Condition ColumnName=”Posicion” Value=”M” />
</MappingFragment>
</EntityTypeMapping>
<EntityTypeMapping TypeName=”IsTypeOf(FUTBOL2006Model.Delantero)”>
<MappingFragment StoreEntitySet=”Futbolista”>
<ScalarProperty Name=”Id” ColumnName=”Id” />
<Condition ColumnName=”Posicion” Value=”L” />
</MappingFragment>
</EntityTypeMapping>
Listado 2. Condiciones en el fichero C-S
Marco de entidades. El listado 3 muestra
un programa en el que se crea un Portero y se persiste en la base de datos; a continuación, se ejecuta una consulta para
comprobar que la inserción ha sido
correcta.
El próximo mes continuaremos presentando los mecanismos que ofrece el
Marco de entidades para modelar la
herencia.
Referencias
[ 1 ] Hernández, Octavio y Zorrilla,
Unai “El Marco de trabajo de
entidades de ADO.NET 3.5”, en
dotNetManía nº 44, enero de
2007.
[ 2 ] Blog del equipo de ADO.NET
Entity Framework, en http://blogs.
msdn.com/adonet.
<<dotNetManía
<EntityType Name=”Portero” BaseType=
”FUTBOL2006Model.Futbolista” />
<EntityType Name=”Defensa” BaseType=
”FUTBOL2006Model.Futbolista” />
<EntityType Name=”Mediocentro” BaseType=
”FUTBOL2006Model.Futbolista” />
<EntityType Name=”Delantero” BaseType=
”FUTBOL2006Model.Futbolista” />
17
plataforma.net
Rubén Garrigós
VS 2005 Team Edition
para profesionales de bases de datos (y II)
Visual Studio 2005 Team Edition for Database Professionals es la herramienta
para profesionales de base de datos de la plataforma Visual Studio. Desplegar
nuevos entornos de datos, refactorizar objetos, realizar pruebas unitarias de la
base de datos... todo se vuelve sencillo con DataDude.
Introducción
Rubén Garrigós es un
arquitecto de soluciones
Microsoft certificado
como MCT, MSCD .NET
y MCITP SQL Server
2005. Es experto en eCommerce B2C y B2B y
en plataformas de datos
sobre SQL Server en
Solid Quality Mentors.
Junto a Eladio Rincón y
Carlos Sacristán escribe
en “El rincón del DBA”:
http://blogs.solidq.com/ES/
ElRinconDelDBA
En nuestro anterior artículo vimos cómo Visual
Studio 2005 Team Edition for Database Professionals (DataDude para los amigos) nos proporciona interesantes funcionalidades para hacer nuestro trabajo diario más cómodo. En esta segunda
parte vamos a continuar abordando otros requerimientos habituales en nuestro día a día:
• “Necesito desplegar la base de datos en un nuevo entorno, a partir de los últimos cambios y
con un conjunto de datos listo para utilizar”.
• “Hay que renombrar unos objetos de bases
de datos y encargarse de todas sus dependencias. No está bien que tengamos columnas telfono, farturas, lineafracturas u otras
perlas similares”.
• “Necesitamos garantizar que los nuevos cambios realizados en el modelo no produzcan
errores en la capa de datos”.
• “El sistema en producción contendrá 1 millón
de clientes y 10 millones de facturas. Debes
comprobar que el rendimiento no se deteriora en exceso”.
Despliegue de cambios
El despliegue de cambios en los modelos de datos
es un proceso que se realiza frecuentemente de
forma bastante artesanal. Probablemente tengamos definido nuestro propio procedimiento de
despliegue, y siguiéndolo paso a paso nos asegu-
ramos que se cumplen ciertas condiciones como:
disponer de una copia de seguridad actual de la
base de datos, no tener usuarios conectados, etc.
Acto seguido suele venir un conjunto de scripts
ordenados o un largo script que deberemos lanzar
para realizar las modificaciones pertinentes. Finalmente, se suelen realizar algunas comprobaciones
básicas y se da el despliegue por finalizado.
Este proceso tiene varios inconvenientes y puede acabar siendo demasiado lento para las necesidades actuales, bastante propenso a fallos y con una
vuelta atrás complicada. DataDude nos ofrece la
generación automática de un script de despliegue
unificado que tendrá en cuenta todos los cambios
aplicados a los objetos, así como varios scripts de
pre-despliegue y post-despliegue que pueden ser
personalizados. Por citar algunos, los scripts de predespliegue son responsables de generar o modificar los servidores enlazados y los logins creados, y
los de post-despliegue de los cambios en roles y
permisos. Adicionalmente podemos añadir nuevos
scripts, por ejemplo para actualizar un registro en
una tabla de estado. De esta forma indicaríamos a
las aplicaciones que estamos realizando una operación de mantenimiento en la base de datos.
Utilizando la funcionalidad de despliegue de
DataDude, cuando lo realicemos contra un servidor en el que ya teníamos desplegado nuestro
modelo de base de datos, se nos advertirá de cualquier situación que pueda producir pérdidas de
datos. Para mayor seguridad, tenemos la opción
de que se realice una copia de seguridad automáticamente como paso previo al despliegue, evi-
<< dnm.plataforma.net
tegia similar, pero siempre se requería de una gran
intervención manual por nuestra parte. Con la nueva herramienta de refactorización de DataDude, al
renombrar un objeto se replicará el cambio en todos
los objetos afectados. Por ejemplo, para cambiar el
nombre de una columna tan solo tendremos que seleccionar la opción “renombrar” en el objeto del esquema deseado, previsualizar los cambios a aplicar y aplicarlos (figuras 2 y 3).
Figura 2. Renombrar objetos.
Figura 1. Scripts de despliegue
tando así la posibilidad de un olvido en este punto.
Algunas veces no será viable realizar la copia de seguridad de esta forma, y entonces deberá ser realizada
manualmente en los scripts de pre-despliegue para
adaptarse a las peculiaridades del sistema destino.
Además, si nuestro modelo de recuperación es completo, el proceso de despliegue nos generará un punto de restauración, por lo que ante cualquier problema nos revertirá al estado anterior al despliegue.
Finalmente, indicar que este proceso de compilación y despliegue del modelo de datos puede ser automatizado mediante el uso de scripts y MSBuild de forma que éste se realice contra varios servidores, cada
día o de forma sincronizada con las compilaciones y
despliegues de nuestras aplicaciones.
Una nueva funcionalidad que aparece con DataDude es la posibilidad de realizar cambios a los objetos
de nuestro modelo (tablas, procedimientos, funciones, vistas…) de forma que las referencias a éstos se
actualicen y se transmitan en cascada por el resto del
modelo.
Hasta ahora, la alternativa habitual del profesional de base de datos pasaba por el uso del socorrido
procedimiento almacenado sp_depends o alguna estra-
Comparado con el tedioso proceso de tener que
realizar esta labor manualmente, deshaciendo los cambios en cada uno de los objetos, la ventaja es evidente. Como medida de seguridad adicional, se registran
adicionalmente en ficheros de log los cambios realizados por la refactorización.
Previa aplicación del script de despliegue (que será el
que reflejará los cambios de nuestro proyecto en la base
de datos), debemos tener en cuenta algunas considera-
<<dotNetManía
Refactorización
Figura 3. Actualización automática de los
objetos afectados por el cambio
19
<< dnm.plataforma.net
ciones adicionales. La primera de ellas es
que los cambios en tablas por defecto se
aplican previo borrado del objeto afectado. Otro problema que nos podemos
encontrar es que no se realice el renombrado de forma correcta en scripts personalizados pre-despliegue, post-despliegue, tests unitarios, etc. El motivo en este
caso suele ser que los objetos referenciados no utilizan el nombre cualificado de
éstos. En estos casos es posible que algunas referencias queden sin actualizar, y
por ello una buena práctica consiste en el
uso siempre del nombre totalmente cualificado (por ejemplo AdventureWorksLT.SalesLT.ProductDescription en
vez de ProductDescription).
<<dotNetManía
Tests Unitarios
20
Los test unitarios nos proveen de una forma de testear componentes individuales
en un sistema. Su naturaleza está destinada a comprobar el funcionamiento
correcto o incorrecto de cada componente de forma individual. El valor de
contar con una batería de tests que nos
permita asegurar el funcionamiento a
nivel unitario correcto crecerá con el
tiempo, con el aumento de la complejidad del modelo y con la cantidad de cambios que se introduzcan durante las iteraciones del ciclo de desarrollo.
Los tests unitarios suelen ir destinados a comprobar el buen funcionamiento de un componente con una funcionalidad muy concreta, como podría ser en
nuestro caso un procedimiento almacenado. Uno de los principales problemas
con los que nos encontramos a la hora de
implementar los tests unitarios de forma
manual es el coste de su realización y
mantenimiento. La creación de los esqueletos que realicen la llamada a los procedimientos, comprueben los valores
devueltos y validen ciertas condiciones
requiere algunas veces más esfuerzo que
la codificación del propio procedimiento. En este apartado, DataDude nos facilita la generación de forma automática de
esqueletos para procedimientos, funciones y triggers y nos soporta directamente
la evaluación de las condiciones que se
muestran en la tabla 1.
Condición
Descripción
Empty Resultset
Comprueba que se devuelve un resultset vacío. Se debe precisar
el resultset a evaluar si se devuelven varios como resultado.
Execution Time
Comprueba que se ejecute la prueba en menos de un umbral de
tiempo seleccionado. Esto puede ser útil para detectar problemas de rendimiento tras un cambio o como complemento para
cumplir un SLA.
Inconclusive
Indica que el test aún no está completo, que tenemos pendiente
definir cuál es el comportamiento esperado.
Not Empty Resultset Comprueba que se devuelve un resultset no vacío. Se debe precisar el resultset a evaluar si se devuelven varios como resultado.
Row Count
Comprueba que se devuelve un número exacto de registros en
el resultset indicado.
Scalar Value
Comprueba que el valor devuelto en un resultset, en la fila y
columna indicada, coincide con un valor dado. También puede
configurarse para aceptar o no nulos.
Tabla 1. Condiciones soportadas
Cuando creemos un nuevo test a
nuestro proyecto, se añadirá un nuevo
proyecto de tests asociado a la solución y
deberemos indicar la conexión principal
a la base de datos y, de forma opcional, la
privilegiada. Es muy interesante el que se
disponga de esta diferenciación, pues nos
permitirá comprobar que la ejecución de
la prueba se realizará en un contexto de
seguridad adecuado y no en el de un
administrador de base de datos. La conexión privilegiada se utilizará en los scripts
de pre y post-ejecución y nos permitirá,
por ejemplo, acceder directamente a
aquellas tablas a las que el usuario que ejecuta el procedimiento no debería tener
acceso directamente para comprobar que
el funcionamiento del procedimiento ha
sido el esperado.
Un ejemplo de esqueleto autogenerado de prueba para un procedimiento sería el siguiente:
— database unit test for dbo.uspLogError
DECLARE @RC INT,
@ErrorLogID INT
SELECT @RC = 0
EXEC @RC = [dbo].[uspLogError]
@ErrorLogID OUTPUT
SELECT RC=@RC,
ErrorLogID=@ErrorLogID
En este caso, podría ser suficiente
comprobar que el valor devuelto es 0, lo
cual indicaría una ejecución correcta. En
otros casos deberemos realizar comprobaciones adicionales que podemos codificar en T-SQL y lanzar un error en caso
de no superarlas de esta forma:
if (@RC=2 and @ErrorLogID>25)
RAISERROR(
‘El identificador del error está fuera de rango’,
12, 1 )
Una característica de los tests unitarios bien diseñados es que garantizan su
repetibilidad, siendo los resultados idénticos en distintas ejecuciones dado un mismo entorno de prueba. Para conseguirlo, es necesario garantizar que se cumplen ciertas pre-condiciones antes de lanzar un test. Un ejemplo claro para el test
de un procedimiento almacenado de
inserción de cliente sería comprobar previamente que el cliente que va a insertarse no existe ya. Este test unitario del procedimiento contendrá a su vez los tests o
acciones necesarios para garantizar su funcionamiento acorde a lo especificado. En
<< dnm.plataforma.net
Planes de generación de datos
de prueba
Muy relacionada con la repetibilidad
está la preparación de datos de prueba.
En muchos casos las pruebas requieren
de un contexto más o menos complejo
para poder ser lanzadas. Por ejemplo,
en el ejemplo comentado anteriormente
de creación de un cliente podemos
requerir de una tabla de países, otra de
códigos postales y otra de tipos de clientes. No resultaría nada conveniente
tener que preparar el entorno de datos
completo y deshacerlo al finalizar cada
prueba unitaria.
Un plan de generación de datos pertenece a un proyecto de base de datos,
aunque un mismo proyecto puede contener diferentes planes de generación
de datos. Un ejemplo típico consiste en
tener un plan de generación orientado
a las pruebas, otro a las pruebas de rendimiento y otro para despliegues de
nuevos entornos.
Cuando añadimos un plan de generación nuevo, se nos muestran las tablas
que componen nuestro modelo para que
indiquemos cuáles queremos que participen en este plan de generación de
datos. Para cada tabla podremos configurar el número de filas a generar y si
queremos mantener proporcionalidad
con alguna tabla relacionada. Si estamos
generando datos para una tabla que nos
relaciona un cliente con sus direcciones
de correo, podemos determinar un ratio
de 3:1 para que por cada cliente se generen 3 direcciones asociadas. Esto es especialmente relevante cuando generamos
planes de generación de datos para pruebas de carga, pues el rendimiento puede variar extraordinariamente si un sistema debe soportar 100 facturas por
cliente o 100.000 facturas por cliente.
Una vez hemos determinado la cantidad de registros a generar, debemos
indicar cómo vamos a generar dichos
datos columna a columna. Las columnas que tengan definido un identificador autoincremental asociado a la clave primaria o sean columnas calculadas
aparecerán deshabilitadas, pues se generarán los datos acorde a su definición.
Para el resto disponemos de generadores de dos tipos principalmente: gene-
radores basados en el tipo del dato y
generadores basados en la extracción
de datos de una fuente de datos.
Entre los primeros nos encontramos
generadores de enteros, de números en
coma flotante, de booleanos o de cadenas, y todos ellos parametrizables. Algunos de los parámetros son: valor mínimo
y máximo, longitud del dato, tipo de distribución para la generación aleatoria,
semilla a utilizar en el generador, porcentaje de nulos a generar... De estos parámetros hay que destacar la importancia
de la semilla utilizada. Será ésta la que nos
permitirá asegurar la repetibilidad del
dato generado entre distintas ejecuciones
del plan de generación de datos.
Entre los segundos contamos con
el Data Bound Generator, que nos permite obtener los datos a partir de una
consulta. Respecto a los datos devueltos podremos especificar un porcentaje de nulos a generar, así como una
semilla. En este caso la semilla no se
utilizará para inicializar un generador
de datos aleatorio, sino para seleccionar, de entre los registros devueltos por
la consulta, cuáles utilizar. Obviamente, para garantizar la repetibilidad, la
consulta que utilicemos deberá devolver siempre los mismos datos.
Para aquellos casos en los que estos
generadores no sean suficientes y necesitemos de generadores específicos,
Figura 4. Plan de generación de datos
<<dotNetManía
este caso necesitaríamos, al menos, otro
test que garantizara que cuando el cliente ya existe se devuelva el error esperado.
Por otra parte y para garantizar la repetibilidad, deberíamos borrar dicho cliente al finalizar el test para dejar el entorno
listo para la próxima ejecución.
Para llevar a cabo estas tareas comentadas disponemos de varios scripts asociados a los scripts de prueba. Disponemos de los scripts “pre-test”, “post-test”,
“Test initialize” y “Test cleanup”. Los dos
primeros se ejecutan antes y después de
cada test específico y son específicos para
cada test, mientras que los segundos se
llaman antes y después de cada uno de
los tests de la clase de pruebas. Indicar
que finalmente estos tests se implementan con clases del nuevo espacio de nombres Microsoft.VisualStudio.TeamSystem.Data.UnitTesting, con lo que es posible modificar el comportamiento de las
clases generadas para adaptarlo a nuestras necesidades más allá de la ejecución
de scripts T-SQL. Por ejemplo, podríamos modificar en el servidor de pruebas
un fichero XML que se utilice en nuestros procedimientos con OPENROWSET. Esto
nos permitiría fijar y comprobar precondiciones que no sean directamente
parte del motor relacional.
21
<< dnm.plataforma.net
contamos con la posibilidad de crear
nuestros propios generadores (MyDataGenerator), al igual que hacíamos con
los comprobadores de los tests unitarios. Estos generadores es posible obtenerlos por composición de generadores ya existentes, por ejemplo combinando el generador de expresiones
regulares con el Data Bound Generator, o bien crearlos desde cero de forma que se ajusten a nuestras necesidades específicas.
“DataDude, parece que hay algún problema en la sincronización de datos
con una de nuestras sucursales. Necesitaría comparar los datos de facturas y clientes para confirmar que está
todo correcto“.
“DataDude, hay que renombrar unos
objetos de bases de datos y encargarse de todas sus dependencias. No
está bien que tengamos clientes con
“telfono”, “farturas”, “lineafracturas”
u otras perlas similares”.
Mediante la herramienta de comparación de datos comprobaremos si es cierta o no la sospecha. Utilizaremos como
origen la base de datos de la sucursal y
como destino la base de datos central.
Utilizando refactorización realizaremos los cambios uno a uno y supervisaremos los objetos a los que afectan.
Aplicaremos los cambios y compilaremos el modelo de nuevo para comprobar que no existen errores. A continuación, desplegaremos en nuestro
entorno de pruebas y pasaremos las
pruebas unitarias para contrastar que
en tiempo de ejecución todo sigue funcionando como esperamos.
Figura 5. Generadores de datos
Otra vida es posible
<<dotNetManía
Como colofón a estos artículos, vamos
a indicar qué funcionalidades podemos utilizar de DataDude para ayudarnos en la resolución de los requerimientos planteados al inicio de los
artículos.
22
Indicaremos ignorar los datos que existan solo en destino para centrarnos en
aquellos datos que existen en origen
pero no en destino. Seleccionaremos
las tablas que contengan los datos y
obtendremos las diferencias y el script
de inserción si lo necesitamos para sincronizar los datos.
“DataDude, necesito conocer las diferencias del modelo de datos de desarrollo respecto al modelo de producción. También un script para sincronizar nuestro entorno de desarrollo”.
“DataDude, necesito desplegar la base
de datos en un nuevo entorno, a partir
de los últimos cambios y con un conjunto de datos listo para utilizar”.
Utilizando la herramienta de
comparación de esquemas podremos
obtener de forma rápida las diferencias existentes y el script en caso de
ser necesario. Podemos realizar la
comparación bien seleccionando
directamente la base de datos de producción como origen, o bien un proyecto de Visual Studio que tengamos
sincronizado. Como destino seleccionaremos la base de datos de desarrollo del equipo o un proyecto de
base de datos sincronizado con ésta.
Si existen diferencias, tan solo tendremos que generar el script, revisarlo y entregarlo.
El primer paso será obtener la última versión del modelo del SourceSafe o de la herramienta de control de
cambios utilizada. Una vez hecho esto,
compilaremos el modelo para asegurarnos de que no existen errores en el
proyecto. Modificaremos el destino del
despliegue, revisaremos el script de despliegue generado y lo ejecutaremos.
En estos momentos sería buena idea
también pasar la batería de tests unitarios si disponemos de ellos. Para ello
ejecutaremos previamente el plan de
generación de datos para dejar la base
de datos desplegada y probada, lista
para su uso.
“DataDude, necesitamos garantizar que
los nuevos cambios realizados en el
modelo no produzcan errores en la
capa de datos”.
Tras aplicar los cambios en el modelo, lanzaremos nuestras pruebas unitarias previamente diseñadas. Rápidamente comprobaremos si alguna de éstas ha
fallado y en dicho caso analizaremos el
origen del error. Daremos el ok cuando
todas las pruebas unitarias se superen sin
errores.
“DataDude, el sistema en producción
contendrá 1 millón de clientes y 10
millones de facturas. Debemos comprobar que el rendimiento no se deteriora en exceso”.
Crearemos un plan de generación de
datos especial para la realización de la
prueba de carga. Dicho plan generará
las tablas con tantos registros como los
esperados en producción. A continuación, bien manualmente o bien mediante un test de carga de VS2005, lanzaremos las diferentes pruebas unitarias para
comprobar el grado de desempeño y
determinaremos si es necesario tomar
medidas como la creación de nuevos
índices, particionado, reescritura de código T-SQL, etc.
plataforma.net
Mario del Valle,
Iskander Sierra,
Miguel Katrib
El Calendario que le estaba
faltando a WPF
Con este artículo continúa la saga relacionada con elementos avanzados de WPF [1-4]. En el último de estos trabajos [4], vimos cómo definir un control personalizado, al presentar un “scroll circular”. Sin embargo, en aquel caso realmente bastó con asociarle las plantillas y estilos
adecuados al control básico ScrollBar ya existente en WPF.
Miguel Katrib es doctor y
profesor jefe de programación del departamento
de Ciencia de la Computación de la Universidad
de La Habana. Miguel es
líder del grupo WEBOO,
dedicado a la orientación
a objetos y la programación en la Web. Es entusiasta de .NET y redactor
de dotNetManía.
Mario del Valle e Iskander
Sierra son instructores de
programación en C# de
la cátedra de Programación e Ingeniería de Software del departamento
de Ciencia de la Computación de la Universidad
de La Habana. Son desarrolladores del grupo
WEBOO dedicados a la
tecnología .NET.
En este trabajo vamos a ver cómo definir un control personalizado pero desde cero, es decir, cuando no basta con retocar uno ya existente. El control a definir es para que haga las veces de un calendario, y puede verse como un control de edición
de valores de tipo DateTime, como el que se usa en
muchas aplicaciones de Windows pero que lamentablemente no está presente entre los controles
básicos que ofrece WPF. La figura 1 nos muestra
el gadget Calendario de Windows Vista, al cual
pretendemos acercarnos mostrando cómo se
pudiera implementar en WPF. Note que un calendario no se limita a presentar los valores enteros
que conforman un DateTime, sino que visualiza
todos los días del mes de dicha fecha y los distribuye por días de la semana, lo que nos propor-
ciona mayor utilidad y funcionalidad en el trabajo con fechas.
En la jerarquía de tipos básicos de WPF no
hay un tipo Calendar ni un tipo DateTimePicker,
como sí los hay en Windows Forms, con los que
poder hacer edición o selección de fechas. ¿Dónde encajar un tal Calendar dentro de la jerarquía
de WPF? Tómese un tiempo antes de seguir y
piense en una respuesta. Un tal calendario podría
considerarse como control de rango (un heredero de RangeBase) ya que, al igual que los valores
numéricos, los valores DateTime son totalmente
ordenables en un rango entre un valor mínimo y
un valor máximo. Sin embargo, lamentablemente RangeBase no es un tipo genérico (por ejemplo
definido con parámetro restringido a IComparable)
y solo está definido en base a tipos numéricos, lo
que impediría usarlo con una fecha (DateTime)
como valor componente.
Heredero de Control
Figura 1. Gadget Calendario
de Windows Vista
Por otra parte, un calendario no puede verse solamente como una figura para visualizar, ni tampoco como un panel o un decorador. Debe definirse como un control ya que debe aportar funcionalidad, pero a su vez se espera que pueda tener
diferentes apariencias, acordes con el estilo y tema
de la aplicación en que se utilice. Recuerde que
los controles en WPF (tipos herederos de Control)
<< dnm.plataforma.net
lizar en el espacio de nombres Wpf
CustomControlLibrary1 (como indica
el valor del atributo xmlns:local).
Figura 2. Creando una biblioteca de controles WPF con VS 2008
Para definir un control personalizado en VS 2008 hay que crear un
proyecto con la opción “WPF Custom Control Library” (figura 2). Esto
crea por defecto un fichero Custom
Control1.cs, que renombraremos por
Calendar.cs, en el cual se incluye una
clase parcial heredera de Control (a la
que llamaremos Calendar). Además, se
crea también un fichero generic.xaml
correspondiente al tema por defecto
de la aplicación. Este código XAML
contiene un diccionario de recursos
WPF donde aparece un estilo definido por defecto para el nuevo control
generado. El listado 1 nos muestra este
estilo.
Es conveniente detenerse aquí para
destacar algunos aspectos sobresalientes de WPF:
1. El uso del atributo especial xmlns:local
declarado en el elemento raíz le indica al compilador de XAML que cualquier elemento con un nombre que
comience con el prefijo local: (en este
caso local:Calendar) se debe loca-
en TargetType ( Calendar en este
caso).
3. La plantilla del control ( Control
Template) asignada a la propiedad
Template mediante el Setter es la que
definirá la apariencia predeterminada del control. De modo que cambiando directamente el valor de la
propiedad Template o utilizando otro
estilo para asociar al tipo Calendar,
se puede modificar la apariencia
completa del calendario. Esta característica de separar la apariencia, a
través de plantillas y estilos, de la
funcionalidad, es una de las novedades más honorables de WPF en
comparación con el resto de las API
visuales que le anteceden.
4. La extensión de marcado TemplateBinding permite enlazar propiedades
de los elementos contenidos en la
plantilla con propiedades del propio
calendario, de modo que la apariencia de lo que se visualiza esté asociada a la información del control.
<ResourceDictionary
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:local=”clr-namespace:WpfCustomControlLibrary1”>
<Style TargetType=”{x:Type local:Calendar}”>
<Setter Property=”Template”>
<Setter.Value>
<ControlTemplate TargetType=”{x:Type local:Calendar}”>
<Border Background=”{TemplateBinding Background}”
BorderBrush=”{TemplateBinding BorderBrush}”
BorderThickness=”{TemplateBinding BorderThickness}”>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Listado 1. Estilo predeterminado generado por Visual Studio para
los nuevos controles personalizados.
2. La utilización de un estilo (Style) presente en el código de generic.xaml
hace que todas las propiedades indicadas en sus correspondientes Setters
se apliquen por defecto a todos los
objetos creados del tipo indicado
Es decir, cuando usted modifique
el valor de una propiedad enlazada
en un calendario, como por ejemplo Background, el valor asignado
automáticamente se asignará también al de su propiedad enlazada, o
<<dotNetManía
tienen una propiedad Template a través
de la cual se le puede cambiar la apariencia al control.
25
<< dnm.plataforma.net
sea el Background del Border contenido en la plantilla. Estos tipos especiales de enlace hacen la magia de
mantener la apariencia del control de
mutuo acuerdo con las propiedades
del propio control y permitir que esta
apariencia pueda cambiar completamente de forma dinámica.
Pero claro, esta apariencia predeterminada que nos pone Visual Studio
cuando se define un control solo nos
muestra un rectángulo con el borde y
fondo ligados a una instancia del control, que en el caso de ser ubicado dentro de una ventana, como el caso del listado 2, los toma de la ventana, y el control se visualiza tan anodinamente como
se muestra en la figura 3.
sobre la que se concibe el calendario.
Para ello le colocaremos una propiedad Value de tipo DateTime. ¿Algo más?
Posiblemente eventos de teclado y
ratón, propiedades para configurar
accesibilidad, cultura, etc. Pero sobre
estas últimas no hay que preocuparse,
ya que son todas propiedades que se
heredan de Control.
Propiedades de dependencia
Figura 3. Apariencia
predeterminada de un control
personalizado con su plantilla
generada por VS.
<Window x:Class=”WpfApplication1.Window1”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:custom=”clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1”
Title=”Window1” Height=”300” Width=”300”>
<Grid>
<custom:Calendar Background=”LightGray” BorderBrush=”DimGray” BorderThickness=”1”
VerticalAlignment=”Center” HorizontalAlignment=”Center”
Width=”100” Height=”100”/>
</Grid>
</Window>
<<dotNetManía
Listado 2. Utilizando el calendario en una ventana
26
Claro que esto no aporta nada a
nuestro objetivo de aproximarnos a la
apariencia de la figura 1. Para ello hay
que agregar algunos elementos nuevos,
tanto en el código XAML de la plantilla como en el código C# de la clase
que define al tipo Calendar. El quid del
asunto está en saber qué ponemos en
cada parte. Es importante tener siempre presente que todo lo que sea pura
apariencia debiera estar en el código
XAML y que en el código C#1 solo se
debe poner el código que dé soporte a
la funcionalidad deseada para el control (por ejemplo, obtener todos los
días del mes para ubicarlos según los
días de la semana). Esta separación es
lo que facilita expresar que se pueda
hacer un cambio de apariencia (incluso usando terceras herramientas, como
Expression Blend) sin perturbar la funcionalidad del control.
Funcionalidad
Cuando usted vaya a diseñar cuál es la
funcionalidad que desea tenga un control, es útil que se abstraiga de la imagen visual que se pueda tener, o querer, de éste. Por ejemplo, para operar
desde C# con un tal control calendario es indispensable que éste tenga un
valor DateTime que indique la fecha
El listado 3 muestra la forma clásica de incluir una propiedad Value en la
definición de un tipo cualquiera en
NET.
public class Calendar : Control {
...
private DateTime value;
public DateTime Value {
get { return value; }
set { this.value = value; }
}
}
Listado 3. Definición de la propiedad Value
al estilo NET
Sin embargo, esta forma directa de
definir propiedades, a la que estamos
acostumbrados en la programación clásica con C#, no es suficiente en este caso
para hacer valer toda la capacidad de
WPF. Para poder aprovechar muchas
de las bondades de WPF, como es
“ligar” (binding) una propiedad con
otras propiedades (del mismo o de otros
controles) o con fuentes de datos, y
poder con ello animar el valor de una
propiedad, o establecer criterios de apariencia asociados con el valor de la propiedad (mediante triggers), es necesario
definir las propiedades como se muestra en el listado 4 .
Al definir la propiedad a través de
una variable de tipo DependencyProperty
(que en el código del listado 4 se registra en un diccionario que incluye los
controles personalizados), estamos
1 Aunque usamos C#, la implementación de controles personalizados está disponible para todos los lenguajes .NET.
<< dnm.plataforma.net
public class Calendar : Control{
...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(“Value”, typeof(DateTime), typeof(Calendar),
new PropertyMetadata(DateTime.Today));
public DateTime Value {
get { return (DateTime) GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
}
Listado 4. Definición de un DependencyProperty en WPF
[ ]
NOTA
Sí, es cierto, escribir todo esto
le puede resultar algo incómodo, pero la buena noticia
es que Visual Studio tiene un
snippet (propdp) que le ahorrará unos cuantos golpes de
tecla.
DateTime.Today). Diversas
características se pueden
indicar mediante este
parámetro, como la forma en que se comportan los enlaces
(bindings), las
animaciones,
o el repintado del control. También
es posible interceptar mediante delegados diferentes
cambios de estado de la propiedad,
como el momento en que se va a asignar un valor o el momento en que este
valor ya fue asignado, pero analizar
todas estas posibilidades se sale del espacio disponible para este artículo.
Tanto Control como la mayoría de los
tipos de WPF tienen como clase base
común a DependencyObject. Entre otras
facilidades, esta clase brinda los métodos
GetValue y SetValue, que le permiten a
sus clases herederas poder acceder directamente al valor de las propiedades de
dependencia en la forma siguiente:
DateTime dt = (DateTime)
myCalendar.GetValue(
Calendar.ValueProperty);
myCalendar.SetValue(
Calendar.ValueProperty,
DateTime.Now);
Sin embargo, para facilitar el uso desde código C# y desde XAML de la propiedad de dependencia, en el listado 4 se
agregó además la propiedad Value de
acuerdo al estilo acostumbrado en .NET.
De este modo, se puede entonces hacer:
DateTime dt = myCalendar.Value;
myCalendar.Value = DateTime.Now;
Aunque no lo crea, esto es todo lo
que hay que definir dentro del tipo
Calendar desde el punto de vista de la
funcionalidad de éste como control. El
resto queda dentro de la apariencia que
se le va a asociar a éste, y es lo que se
verá a continuación. Claro, esto no
quiere decir que no haya nada más que
escribir en código C#; nos falta también definir un “convertidor de tipo”,
pero esto se verá más adelante.
La apariencia
Para que la apariencia se aproxime a la
del gadget de Windows Vista (figura 1),
hay que sustituir entonces el código
XAML que Visual Studio ha generado
por defecto (listado 1 y figura 3). Hace
falta una plantilla que haga lucir al control como el familiar calendario, inclu-
<<dotNetManía
indicándole en este caso a WPF,
mediante los parámetros del método
Register, que todos los objetos de tipo
Calendar que se declaren en XAML
tendrán una propiedad llamada Value
(primer parámetro del método Register en el listado 4), a la cual se le pueden asignar valores de tipo DateTime
(segundo parámetro que se le ha pasado al método Register). Para esta variable, como es DependencyProperty, están
disponibles los mecanismos de binding,
animations y triggers. Aunque estos tres
parámetros usados en la llamada a
Register son suficientes en la mayoría
de los casos, hay otras sobrecargas del
método. Por ejemplo, es posible utilizar un cuarto parámetro (como en el
listado 4) que permite detallar el comportamiento de la propiedad en ejecución. El tipo PropertyMetadata es uno
de los aceptados en este cuarto parámetro, por ejemplo para indicar un
valor predeterminado a asumir (en el
listado 4 se ha utilizado la fecha actual
27
<< dnm.plataforma.net
yendo la repartición de todos los días del mes en una
tabla cuyas columnas sean los días de la semana (listado 5 y figura 4).
<<dotNetManía
Figura 4. Apariencia del calendario.
28
En el segmento (1) del listado 5 puede observarse
que se usa un Grid como panel para distribuir los elementos del calendario. En esta rejilla se definen dos
filas. Una fila es para las letras que indican los días de
la semana, los cuales han sido distribuidos uniformemente por un UniformGrid; la otra fila es un ListBox
para mostrar los días del mes, distribuidos por semanas, donde cada ítem del ListBox es un UniformGrid con
los días de cada semana.
Aunque el lector puede pensar que el Grid es el panel
ideal para representar una tabla de elementos, su principal limitante para dar la apariencia del calendario es
que en un Grid hay que indicar en qué fila y columna
se encuentra cada elemento. Esto da mucho trabajo
cuando los elementos a ubicar no se pueden indicar
explícitamente en el XAML, sino que hay que calcularlos dinámicamente en ejecución, como es el caso de
los días del mes, que hay que ubicarlos según el día de
la semana (incluyendo los días del mes anterior que forman parte de la primera semana y los días del mes
siguiente que forman parte de la última semana). Sin
embargo, hay en WPF un panel que sí resulta muy útil
para este caso y es el UniformGrid (ver en listado 5 los
segmentos (2) y (5)). Éste es un panel que, al igual que
el Grid, distribuye sus elementos en filas y columnas,
pero la diferencia radica en que para el UniformGrid no
es necesario indicar las posiciones de los elementos que
él distribuye. El propio UniformGrid, al indicarle la cantidad de columnas, reparte los elementos uniformemente, llenando primero la primera fila, poniendo un
elemento en cada columna; luego de finalizar con la
última columna de la fila, entonces el siguiente elemento se ubica en la primera columna de la segunda
<Style TargetType=”{x:Type this:Calendar}”>
<Setter Property=”Template”>
<Setter.Value>
<ControlTemplate TargetType=”{x:Type local:Calendar}”>
<Border Background=”{TemplateBinding Background}”
BorderBrush=”{TemplateBinding BorderBrush}”
BorderThickness=”{TemplateBinding BorderThickness}”>
<Border>
<Border.Background>
<LinearGradientBrush EndPoint=”1,1”>
<GradientStop Color=”#8fff” Offset=”0”/>
<GradientStop Color=”#dfff” Offset=”0.4”/>
<GradientStop Color=”#dfff” Offset=”0.6”/>
<GradientStop Color=”Transparent” Offset=”1”/>
</LinearGradientBrush>
</Border.Background>
(1) <Grid>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”Auto”/>
</Grid.RowDefinitions>
(2)
<UniformGrid Columns=”7” Margin=”0,2”>
<TextBlock Text=”D”/>
<TextBlock Text=”L”/>
<TextBlock Text=”M”/>
<TextBlock Text=”M”/>
<TextBlock Text=”J”/>
<TextBlock Text=”V”/>
<TextBlock Text=”S”/>
</UniformGrid>
<ListBox Grid.Row=”1” BorderThickness=”0” Background=”Transparent”
SelectedItem=”{Binding Value,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}” Foreground=”{TemplateBinding Foreground}”>
(4)
<ListBox.ItemsSource>
<Binding Path=”Value”
RelativeSource=”{RelativeSource TemplatedParent}”>
<Binding.Converter>
<local: DateToMonthDatesConverter/>
</Binding.Converter>
</Binding>
</ListBox.ItemsSource>
(5)
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns=”7”/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
(6)
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Name=”tb” Text=”{Binding Day}” FontSize=”9”
HorizontalAlignment=”Right” TextAlignment=”Right”/>
(7)
<DataTemplate.Triggers>
<DataTrigger Binding=”{Binding DayOfWeek}” Value=”Sunday”>
<Setter TargetName=”tb” Property=”Foreground”
Value=”OrangeRed”/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Listado 5. Estilo para el calendario.
<< dnm.plataforma.net
<ListBox SelectedItem=
”{TemplateBinding Value}” ...>
Esto provocaría que, automáticamente, cuando cambiara la propiedad
Value en el calendario la selección del
ListBox también cambiara en correspondencia, pero… ¿y a la inversa? TemplateBinding es un enlace que ocurre en
un solo sentido, el de cambiar la selección del ListBox al cambiar la propiedad
Value. Para lograr que también al cambiar la selección del ListBox se produzca
un cambio en la propiedad Value del objeto calendario es necesario indicar el enlace de manera más verbosa (segmento (3)
del listado 5). Note que el enlace se especifica mediante el uso de Binding con la
propiedad Value del elemento que se
obtiene de la fuente relativa TemplatedParent, o sea el elemento al cual se le esté
aplicando la plantilla. Hasta aquí se tiene lo mismo que con TemplateBinding.
La diferencia radica en que al hacerlo con
Binding se puede además especificar la
dirección del enlace (en este caso, decir
que es en ambos sentidos haciendo
Mode=TwoWay). O sea, de este modo al cambiar cualquiera de las propiedades Value,
sea la del propio control o la del SelectedItem del ListBox contenido en su plantilla, la otra debe actualizarse con el mismo valor.
Pero el lector puede haber notado que
está faltando algo por explicar. La propiedad Value en el control lo que tiene es
una fecha, pero los ítems con los que se
quiere rellenar el ListBox deben ser todos
los números de los días del mes de dicha
fecha, unidos a los días del mes anterior y
del mes posterior que hagan falta para
completar la primera y última semana...
Convirtiendo una fecha en
todas las fechas a poner
en el calendario del mes
La propiedad ItemsSource con la que se
“alimentan” los ítems a visualizar por el
ListBox, es de tipo IEnumerable, por tanto mediante esta propiedad se puede
“rellenar” el ListBox asociándole una
colección física, o asociándole el resulta-
do de una iteración (que es lo que haremos en este caso). Observe en el listado
5 (segmento (4)) que se ha puesto sobre
esta propiedad un Binding idéntico al que
se puso sobre la propiedad SelectedItem
(segmento (3)), solo que éste está definido de forma explícita, no se aplica en
ambos sentidos, y además tiene indicado
un convertidor (es decir, un valor asociado a su propiedad Converter). Este valor
que se asocia a la propiedad Converter es
el nombre de un método (DateToMonthDatesConverter en este ejemplo) que será
el encargado de convertir el valor de la
propiedad Value (un DateTime en este
ejemplo) en un IEnumerable, que produce en este caso los valores de tipo DateTime correspondientes a todos los días del
mes en cuestión, incluyendo los días del
mes anterior que completan la primera
semana y los días del mes posterior que
completan la última semana (ver código
C# del listado 6).
Para definir estos convertidores hay
que implementar los dos métodos Convert y ConvertBack de la interfaz IValueConverter. Estos son los que hacen
la conversión en ambos sentidos. En
este caso, ConvertBack se ha implemen-
public class DateToMonthDatesConverter : System.Windows.Data.IValueConverter {
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture) {
DateTime dt = (DateTime) value;
return GetDatesOfTheMonth(new DateTime(dt.Year, dt.Month, 1));
}
private IEnumerable<DateTime> GetDatesOfTheMonth(DateTime firstDay){
int dayOfWeek = (int)firstDay.DayOfWeek;
// Convirtiendo enumerativo en entero
DateTime current = firstDay.AddDays(-dayOfWeek - 1);
// Para poder rellenar con los días del mes anterior
int daysInMonth = DateTime.DaysInMonth(firstDay.Year, firstDay.Month) + dayOfWeek;
for (int j = 0; j < daysInMonth + 7 - (daysInMonth % 7); j++) {
current = current.AddDays(1);
yield return current;
}
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture) {
return null;
// No interesa conversión en este sentido, la práctica en WPF es devolver null
}
}
Listado 6. Conversión de una fecha en un iterador que nos dé todas las fechas del mes de esa fecha.
<<dotNetManía
fila y así sucesivamente. Observe en el
segmento (2) del listado 5 que se ha utilizado un UniformGrid con 7 columnas
para las letras de los días de la semana.
Más abajo, segmento (5) del listado 5, se
le indica al ListBox que utilice un UniformGrid, también de 7 columnas, para
ubicar cada ítem del ListBox, es decir para
que vaya ubicando todos los días por
columnas de a 7.
Una vez que ya el código XAML de
la plantilla se encarga de repartir los elementos en su lugar, solo queda finalmente
enlazar esto con la fecha representada en
la propiedad Value de nuestro Calendar.
Se ha escogido como elemento contenedor de los días del mes a un ListBox porque necesitamos usar un control que permita seleccionar un elemento entre varios
(ese elemento seleccionado es el día que
suele aparecer destacado cuando se muestra e interactúa con un calendario). Para
hacer que el ListBox tenga seleccionado
el día actual entre el resto de los días del
mes, se podía haber utilizado la extensión
de marcado TemplateBinding del modo:
29
<< dnm.plataforma.net
Conclusiones
Esta característica de separar la apariencia, a
través de plantillas y estilos, de la funcionalidad,
es una de las novedades más honorables
de WPF en comparación con el resto de
las API visuales que le anteceden
tado como que devuelve null, ya que
no se desea ninguna conversión en ese
sentido.
Para completar la apariencia del
calendario, en el segmento (6) del listado
5 se ha agregado una plantilla de datos
que define la apariencia que tendrá cada
día del mes. Observe que esta plantilla ha
sido asignada a la propiedad ItemTemplate del ListBox, lo cual indica que esta
plantilla será aplicada para cada ítem del
ListBox. Y observe también que como
cada ítem es de tipo DateTime, los enlaces
(bindings) de esta plantilla se pueden enlazar directamente con las propiedades de
DateTime (Day, DayOfWeek):
<<dotNetManía
<DataTemplate>
<TextBlock Name=”tb” Text=”{Binding Day}”
FontSize=”9”
HorizontalAlignment=”Right”
TextAlignment=”Right”/>
<DataTemplate.Triggers>
<DataTrigger Binding=”{Binding DayOfWeek}”
Value=”Sunday”>
<Setter TargetName=”tb”
Property=”Foreground”
Value=”OrangeRed”/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
30
A la plantilla se le ha incorporado
entonces un DataTrigger (segmento (7)
del listado 5) que se activa cuando la propiedad DayOfWeek de la fecha tome el valor
“Sunday”. Cuando esto ocurre, el Trigger
indica a su vez a través de un Setter que
el color (Foreground) del bloque de texto
que muestra al día (de nombre tb) debe
ser OrangeRed. De esta manera se logra
que los días que correspondan a domin-
go aparezcan distinguidos con un color
diferente en el calendario (figura 4).
Una nota final
Aunque la plantilla que define la apariencia del control Calendar se apoya en
el uso de convertidores, y éstos a su vez
se programan en C#, no se puede considerar que este código forma parte de la
funcionalidad del control. De hecho, en
este ejemplo se necesita este convertidor
debido a la apariencia que se ha escogido
para mostrar el calendario (y que quiere
mostrar todas las fechas del mes al estilo
del gadget de Windows). De haber escogido un simple TextBox para que el usuario escribiese una fecha, o incluso un TextBlock si solo se quisiese visualizar la misma, hubiese sido necesario un convertidor diferente (o puede que no hubiese
sido necesario ninguno). De momento
estos convertidores vienen a suplir una
carencia en el poder expresivo declarativo de XAML, sobre lo cual trataremos en
un próximo artículo.
Con lo expuesto hasta aquí hemos
querido darle una panorámica de
cómo se definen algunos de los elementos básicos para construir un
control personalizado desde cero.
Siempre recuerde que todo comienza por escoger la clase base más apropiada para el control. Luego, es
importante abstraerse de su parte
visual para definir las propiedades de
dependencia y demás miembros que
definen la funcionalidad que el control tendrá cuando se opere con él
desde código. Y para finalizar, se define en generic.xaml la plantilla por
defecto que tendrá el control, utilizando las novedosas bondades gráficas de WPF.
Claro que comparado con el gadget Calendario de Windows Vista de
la figura 1, este control aún está
incompleto. Habría que añadir un
espacio para mostrar y seleccionar
tanto el mes como el año y completar la funcionalidad esperada de un
calendario (en el que se puede pasar
de mes y de año). Pero no hay espacio para más. Esperamos que lo mostrado le sirva de impulso al lector para
terminar por su cuenta este calendario, continuando en este mundo fascinante que es WPF. Incluso, anímese a animarlo, colóquele un efecto de
paso de páginas del almanaque con un
efecto 3D como el que se desarrolló
en el artículo [3].
Referencias
[ 1]
Hernández Yamil, Sierra Iskander, Del Valle Mario, Katrib Miguel. Cómo definir
nuestros propios paneles personalizados en WPF, dotNetManía No. 35, marzo 2007.
[ 2]
Del Valle Mario, Sierra Iskander, Hernández Yamil, Katrib Miguel. Entrando en la tercera dimensión, dotNetManía No. 37, mayo 2007.
[ 3]
Sierra Iskander, Del Valle Mario, Hernández Yamil, Katrib Miguel. Paso de
páginas en 3D con WPF, dotNetManía No. 38, junio 2007.
[ 4]
Del Valle Mario, Sierra Iskander, Hernández Yamil, Katrib Miguel. Controles personalizados en WPF: un scroll circular, dotNetManía No. 40, septiembre 2007.
sharepoint
Gustavo Vélez
Manejadores de eventos en SharePoint
2007
Los flujos de trabajo no siempre son necesarios para hacer
que las cosas funcionen bien
Los manejadores de eventos de SharePoint 2007 son más que una herencia de la versión 2003: en WSS y MOSS 2007 han sido ampliados y enriquecidos considerablemente.Ahora pueden ser utilizados a lo largo y ancho
del sistema, y su modelo de objetos ha sido mejorado en diferentes direcciones. Los manejadores de eventos permiten realizar algunas de las tareas que los flujos de trabajo están en capacidad de ejecutar, pero de una forma mucho más sencilla y efectiva, e inclusive pueden anticiparse a eventos,
algo que es difícil de realizar con flujos de trabajo.
Qué es un manejador de eventos,
y su relación con los flujos de trabajo
Gustavo Vélez es
ingeniero mecánico y
electrónico, especializado en el diseño,
desarrollo e implementación de software (MCSD) basado en
tecnologías de Microsoft, especialmente
SharePoint. Es creador
y webmaster de
http://www.gavd.net/se
rvers, y trabaja como
senior developer en
Winvision
(http://www.winvision.nl)
Windows es un sistema operativo que funciona a
base de eventos: cada vez que un usuario interactúa
con Windows, éste lanza internamente un evento
para anunciar que algo ha ocurrido. Un desarrollador puede capturar el evento y crear software que
reaccione de una forma específica. SharePoint es un
sistema basado en tecnología Windows, y por lo tanto permite capturar eventos (un documento ha sido
subido a una librería, un elemento ha sido eliminado de una lista, etc.), permitiendo crear software que
tome las acciones apropiadas.
El concepto de manejador de evento fue introducido en la versión 2003 de SharePoint y fue utilizado
principalmente para crear flujos de trabajo. Con la aparición de Workflow Foundation y su integración con
SharePoint 2007, esta función ha desaparecido mayoritariamente; a pesar de esto, el sistema de eventos dentro de SharePoint ha sido ampliado considerablemente
y permite realizar tareas que no son posibles de implementar con los flujos de trabajo.
Los nuevos eventos permiten controlar prácticamente todas las acciones que ocurren dentro de
SharePoint: agregar, modificar o eliminar campos
en elementos de listas, librerías, Webs y sitios. Pro-
bablemente la mayor diferencia con los flujos de trabajo es que los eventos pueden ser lanzados antes de
que la acción se ejecute, lo que no es posible (o difícil de programar) con flujos; además, las modificaciones en la infraestructura de Webs y sitios no son
detectadas por Workflow Foundation pero sí por la
infraestructura de los manejadores.
Y hay una diferencia más: un manejador de eventos puede iniciar un flujo de trabajo, mientras que
lo contrario no es posible. Al otro lado de la moneda, los manejadores de eventos tienen muy pocas
posibilidades para interactuar con el usuario: son iniciados automáticamente, sin que el usuario pueda
hacerlo manualmente, no es posible detenerlos para
aceptar configuración de datos, y los desarrolladores deben tomar todas las precauciones necesarias si
algo no funciona correctamente, pues no tienen
mecanismos de protección como los que tienen los
flujos de trabajo.
Arquitectura y nuevas posibilidades
Los manejadores de eventos de SharePoint 2003
eran aplicables solamente a librerías de documentos, imágenes y formularios, y estaban restringidos
a los eventos de proteger/desproteger, copiar, eliminar, insertar y modificar o cambiar el nombre.
<< dnm.sharepoint
Como se puede observar, en los
nombres de los eventos hay dos tipos
principales:
• Eventos sincrónicos, cuyo nombre
termina en “ing”. Ocurren antes de
que la acción del evento sea implementada, suspendiendo el proceso
hasta que el código del manejador ha
sido completamente ejecutado. Esto
permite modificar la acción, por
ejemplo, para cancelar la modificación de un documento antes de que
el cambio se realice.
• Eventos asincrónicos, cuyo nombre
termina en “ed”, que ocurren después
de que la acción ha tomado efecto.
Esta era la única posibilidad con SharePoint 2003; en 2007, de igual
manera, el evento no se ejecuta inmediatamente, sino que puede tener un
retraso de hasta algunos segundos.
Note que no existen eventos para
cuando se agregan o modifican sitios o
Webs. También es importante mencio-
nar que los valores de las propiedades
Before y After de los eventos en librerías
siempre mostrarán los valores correctos
en las librerías, pero en las listas solamente es preservado el valor After.
Programación
Los manejadores de eventos para SharePoint 2007 son programados como
librerías de clases de código manejado en
.NET 2.0 o superior utilizando C# o
Visual Basic. El siguiente ejemplo (listado 1) muestra cómo crear un manejador
sencillo, que agrega un vínculo en una lista de vínculos cada vez que un documento
es añadido a una librería de documentos.
El ejemplo es solamente para mostrar la
forma de programación, y para utilizarlo como código de producción debería
ser ampliado y mejorado.
Inicialmente, debemos crear una
biblioteca de clases en Visual Studio
2005, utilizando un nombre único (por
ejemplo, CreadorVinculos), y asignar un
nombre adecuado a la clase creada por
defecto (digamos ClaseCreadorVinculos).
Asimismo, hay que agregar una referencia a Windows SharePoint Services
(Microsoft.SharePoint.dll) y es conveniente agregar la sentencia de importación correspondiente (mediante using
en C# o Imports en Visual Basic) en el
código.
La nueva clase debe heredar de una
de las clases para manejadores de eventos; en el caso del ejemplo, de SPItemEventReceiver. Todos los métodos de
la clase base pueden ser sobrescritos,
incluso más de uno si es necesario. En
el ejemplo se sobrescribe el método
ItemAdded.
El parámetro properties contiene
toda la información sobre el elemento
que ha lanzado el evento: una tabla hash
con los valores de las propiedades antes
y después del evento, el contexto de
SharePoint, información sobre el usuario (identificador, nombre, login), la lista (identificador, elemento, título), sitio
y Web.
Como los manejadores de eventos
no se ejecutan bajo el contexto de SharePoint o IIS, no es posible utilizar el
archivo web.config del sitio para guar-
using
using
using
using
System;
System.Collections.Generic;
System.IO;
Microsoft.SharePoint;
namespace CreadorVinculos
{
public class ClaseCreadorVinculos :
SPItemEventReceiver
{
public override void ItemAdded(
SPItemEventProperties
properties)
{
base.ItemAdded(properties);
}
}
}
Listado 1
dar información que pueda ser cambiada fuera del programa, como es deseable para el nombre de la lista de vínculos del ejemplo; pero el archivo machine.config sí se puede utilizar para tal
efecto. Este archivo no posee una sección AppSettings por defecto, pero es
posible agregar una si es necesario. Por
lo tanto, en el fichero machine.config
(C:\WINDOWS\Microsoft.NET\Framework\v2
.0.50727\CONFIG\machine.config) añadimos una nueva sección debajo del cierre del último elemento (</configSections>):
<appSettings file = “”>
<add key = “NombreListaVinculos”
value = “NombreLista” />
</appSettings>
El valor puede ser leído desde el
código de la forma tradicional:
base.ItemAdded(properties);
string miListaVinculos =
System.Configuration.
ConfigurationSettings.
AppSettings[“NombreListaVinculos”];
Finalmente, utilizando el parámetro properties es posible obtener una
referencia a la librería (SPList) en donde se ha lanzado el evento, y crear el
<<dotNetManía
Además, solamente un manejador de
eventos se podía utilizar en cada librería.
En SharePoint 2007 (WSS y
MOSS), hay cuatro clases que ofrecen
eventos:
1. La clase SPEmailEventReceiver, con
un evento (EmailReceived).
2. La clase SPItemEventReceiver, con
eventos para atrapar inserciones
(ItemAdding/ItemAdded), eliminaciones (ItemDeleting/ItemDeleted), cambios (ItemUpdating/ItemUpdated), adición o eliminación de archivos
adjuntos ( ItemAttachmentAdding
/Added, ItemAttachmentDeleting/Deleted), protección y desprotección
(ItemCheckingIn-Out/CheckedIn-Out,
ItemUncheckingOut/ UncheckedOut),
cambio de sitio ( ItemFileMoving/
Moved) y conversión de archivos
(ItemFileConverted).
3. La clase SPListEventReceiver, para
sucesos a nivel de campos de listas
(FieldAdding/Added, FieldDeleting/
Deleted, FieldUpdating/Updated).
4. La clase SPWebEventReceiver, para
eventos en sitios y Webs (SiteDeleting/Deleted, WebDeleting/Deleted,
WebMoving/Moved).
33
<< dnm.sharepoint
vínculo en la lista de eventos. El código completo del método sobrescrito se
muestra en el listado 2.
el problema de trasladar la información
de los errores hacia el exterior. Existen
varias formas de hacerlo: principal-
public override void ItemAdded(SPItemEventProperties properties)
{
SPSite miSite = null;
SPWeb miWeb = null;
base.ItemAdded(properties);
try
{
string miListaVinculos = System.Configuration.
ConfigurationSettings.AppSettings[“NombreListaVinculos”];
miSite = new SPSite(properties.SiteId);
miWeb = miSite.OpenWeb();
SPList miLista = miWeb.Lists[miListaVinculos];
SPListItem miVinculo = miLista.Items.Add();
miVinculo[“URL”] = properties.WebUrl + “/” +
properties.ListItem.Url + “, “ + properties.ListItem.Name;
miVinculo.Update();
}
catch(Exception ex)
{
TextWriter miEscritor = new StreamWriter(@”c:\ManejadorEventosError.txt”);
miEscritor.WriteLine(ex.ToString());
miEscritor.Close();
}
finally
{
if (miWeb != null)
miWeb.Dispose();
if (miSite != null)
miSite.Dispose();
}
}
<<dotNetManía
Listado 2
34
En el código, luego de leer el nombre de la lista de vínculos que se ha
guardado en el archivo machine.config,
se crea una instancia de SPSite usando
las propiedades del evento. Luego de
crear una instancia de la lista de eventos, se le añade un nuevo elemento y se
configura su URL para que apunte al
documento recién creado en la librería
de documentos.
Como se ha indicado al principio,
las posibilidades de interacción con el
usuario son muy limitadas. El parámetro properties tiene un método ErrorMessage que se puede utilizar solamente en eventos sincrónicos cuando el
código cancela la acción iniciada para
enviar un mensaje al usuario. Esto crea
mente escribir en el Visor de sucesos o
en un archivo. En ambos casos, es necesario tener en cuenta que el usuario
debe tener suficientes derechos para
escribir (el usuario utilizado es el que
se ha configurado en el Grupo de aplicaciones de IIS para el sitio de SharePoint). Las líneas de código en el bloque catch del ejemplo graban en un
archivo el mensaje de error cuando ocurre algo inesperado.
Los ensamblados que contienen
manejadores de eventos tienen que ser
instalados en el GAC (Global Assembly
Cache), por lo que es necesario firmarlos con un nombre seguro. Para ello,
en la pantalla de propiedades del proyecto de Visual Studio vamos a “Firma”
| “Firmar el ensamblado”, en “Seleccione un archivo de clave de nombre
seguro” seleccionamos “Nueva”, definimos un nombre en “Nombre de
archivo de clave” (por ejemplo, CreadorVinculos), deseleccionamos “Proteger mi archivo de clave mediante contraseña” y generamos el proyecto. El
ensamblado generado puede ser copiado directamente al GAC, o se puede
utilizar la herramienta gacutil para ello.
Instalación y utilización
SharePoint no dispone de pantallas de
administración para configurar manejadores de eventos, así que la forma
recomendada para instalación es utilizar una solución de SharePoint que
copie la DLL en el GAC, junto con una
característica que configure la librería
o lista. También es posible usar el
modelo de objetos de SharePoint para
configura el manejador.
Una característica para instalar el
manejador del ejemplo consta de dos
archivos: uno llamado Feature.xml, con
la definición de la característica en sí, y
otro llamado Elementos.xml para identificar sus componentes. Entonces creamos dos archivos con estos nombres
en un nuevo directorio llamado CreadorVinculosCaracteristica bajo C:\
Archivos de programa\Archivos comunes
\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES. El contenido del archivo Feature.xml se presenta en el listado 3, y el de Elementos.xml en el listado 4. En el listado
3, “GUID” debe ser sustituido por un
identificador global único, que puede ser obtenido mediante la utilidad
GuidGen.exe.
<Feature Scope=”Web”
Title=”Manejador Eventos CreadorVinculos””
Id=”GUID”
xmlns=”http://schemas.microsoft.com/sharepoint/”>
<ElementManifests>
<ElementManifest Location=”Elementos.xml”/>
</ElementManifests>
</Feature>
Listado 3
<< dnm.sharepoint
<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>
<Receivers ListTemplateId=”103”>
<Receiver>
<Name> Manejador Eventos CreadorVinculos </Name>
<Type>ItemAdded</Type>
<SequenceNumber>10000</SequenceNumber>
<Assembly>CreadorVinculos, Version=1.0.0.0, Culture=neutral,
PublicKeyToken= 96290f904372ba8a </Assembly>
<Class> CreadorVinculos.ClaseCreadorVinculos </Class>
<Data></Data>
<Filter></Filter>
</Receiver>
</Receivers>
</Elements>
Listado 4
En el listado 4, el valor de ListTemplateId es el número asignado a la lista de
vínculos por SharePoint, y se puede
encontrar en la respectiva definición
CAML de la lista (en el archivo C:\Archivos de programa\Archivos comunes\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\LinksList\ListTemplates\Links.xml, para la lis-
ta del ejemplo). El tipo de evento es el que
se ha definido en el código (ItemAdded), y
el número de secuencia indica el orden en
el que son lanzados los diferentes eventos: de 1.000 a 9.999 están reservados por
SharePoint para sus propios eventos, así
que es necesario utilizar un valor superior
al límite máximo. El elemento Assembly
es configurado con los parámetros del
ensamblado utilizado: el nombre del
ensamblado, su versión y cultura y la clave pública, que se puede encontrar con la
herramienta sn.exe de Visual Studio (utilizando el parámetro -T). Finalmente, es
necesario indicar el nombre de la clase que
se va a utilizar.
Luego de crear los dos archivos en
el directorio indicado, la característica
se puede instalar utilizando la herramienta de administración de SharePoint
con la sintaxis:
using
using
using
using
stsadm -o activatefeature -filename
CreadorVinculosCaracteristica\Feature.xml
–url http[s]://NombreServidor/NombreSitio
Como el modelo de objetos de SharePoint dispone de todas las clases y
métodos necesarios para configurar
un manejador de eventos, la segunda
forma para instalarlos es creando un
pequeño programa. Además, manejadores para Webs o sitios tienen que
ser instalados de esta manera, pues no
es posible hacerlo con características.
La aplicación de consola que se presenta en el listado 5 configura el
manejador del ejemplo en una lista
( NombreDeLista ), después de que la
DLL haya sido instalada manualmente en la GAC.
System;
System.Collections.Generic;
System.Text;
Microsoft.SharePoint;
namespace InstallTasksCleaner
{
class Program
{
static void Main(string[] args)
{
SPSite miSitio = new SPSite(“http[s]://NombreServidor”);
SPWeb miWeb = miSitio.OpenWeb();
SPList miLista = miWeb.Lists[“NombreDeLista”];
SPEventReceiverDefinitionCollection misReceptoresEventos =
miLista.EventReceivers;
SPEventReceiverDefinition miEvento = misReceptoresEventos.Add();
miEvento.Assembly = “CreadorVinculos, Version=1.0.0.0,
Culture=neutral, PublicKeyToken= 96290f904372ba8a “;
miEvento.Name = “Manejador Eventos CreadorVinculos”;
miEvento.Type = SPEventReceiverType.ItemAdded;
miEvento.SequenceNumber = 10000;
miEvento.Class = “CreadorVinculos.ClaseCreadorVinculos”;
miEvento.Update();
foreach (SPEventReceiverDefinition miDef in misReceptoresEventos)
{
Console.WriteLine(miDef.Name);
}
stsadm -o installfeature -filename
CreadorVinculosCaracteristica\Feature.xml
}
}
}
Listado 5
<<dotNetManía
Y se puede activar utilizando la pantalla de administración del sitio correspondiente, o por medio de la misma
herramienta con la sintaxis:
35
<< dnm.sharepoint
<<dotNetManía
Figura 1
36
Cada lista o librería dispone de una colección de
receptores de eventos (SPEventReceiverDefinitionCollection), a la que se le puede añadir uno del tipo SPEventReceiverDefinition, y luego configurar sus propiedades. Note la similitud entre estas líneas de código y las utilizadas en la característica; ambos procesos utilizan el mismo código básico en la máquina de
SharePoint.
Luego de instalado, un usuario no puede ver
cómo funciona el manejador de eventos, sino que
solamente puede notar sus efectos (si es que son visibles). La figura 1 muestra la librería en la que se ha
configura el manejador y el efecto en la lista de vínculos luego de agregar un documento. La configuración de la lista de vínculos por medio de machine.config es una forma fácil y rápida de cambiar la
lista cuando sea necesario. Hay que tener en cuenta
que el código del ejemplo es muy sencillo, y que tanto la librería de documentos como la lista de vínculos tienen que estar en el mismo sitio; pero modificarlo para hacerlo funcionar de cualquier modo deseado es fácil, y el modelo de objetos de SharePoint
provee todas las herramientas para programar lo que
sea necesario.
Cuando se utilizan manejadores de eventos, es muy
importante tener en cuente el impacto del código
sobre la estabilidad y rendimiento de los servidores
de SharePoint. Por ejemplo, crear un manejador que
recorra listas con grandes cantidades de elementos es
relativamente fácil de programar, pero si el evento que
lo lanza ocurre frecuentemente, se verá disminuir el
rendimiento del sistema hasta agotar los recursos de
los servidores. Cuando sea necesario utilizar un escenario de este tipo, probablemente sea mejor crear
algún mecanismo de almacenamiento en caché, o
hacer que el proceso se mantenga en estado de latencia hasta que el sistema tenga menos carga de procesamiento.
Conclusiones
Los manejadores de eventos han existido en SharePoint desde hace ya algún tiempo, y en la última
versión se han ampliado no solamente en su campo de acción, sino también en las posibilidades que
ofrecen a los desarrolladores y en el alcance de su
utilización. Los manejadores pueden sustituir en
algunos casos a flujos de trabajo, pero debido a sus
reducidas capacidades de interacción con los usuarios, su ámbito de aplicación se dirige más hacia la
automatización de tareas rutinarias dentro de SharePoint. Las posibilidades de utilización son prácticamente ilimitadas, y su facilidad de programación e instalación los convierten en una de las mejores herramientas a disposición de los desarrolladores de SharePoint.
plataforma.net
Daniel Seara
Componentes de uso general
Acceso a datos
Comenzamos aquí el desarrollo del primer componente de funcionalidad compleja. Dada la importancia que tiene a la hora de desarrollar
aplicaciones, comenzaremos con el acceso a datos, explicando según se
desarrolla los fundamentos y consideraciones en los que basa, para que
se pueda usar, modificar o repensar completamente y que os pueda ser
realmente útil.
[
Daniel Seara es mentor
de Solid Quality Mentors
y director del área de
desarrollo .NET. Es MVP
desde 2003 y ponente
habitual de INETA y
Microsoft.
NOTA
No os ilusionéis. No hay modo que
esto pueda desarrollarse en una
sola nota. Serán, espero, dos.
]
Si vamos a comenzar a hablar de componentes genéricos, es casi obligado empezar por el servicio de acceso a datos. Nada tan repetido, tan modificado, tan
“versionado”… ni tan solicitado. Y aun cuando existen muchos ejemplos completos en Internet acerca
de mecanismos y componentes de acceso a datos,
realmente es probable que ninguno cumpla exactamente las necesidades de un caso particular.
Hasta la propia Microsoft, al comenzar con su
grupo PAG, comenzó sus publicaciones precisamente con un servicio de acceso a datos, que fue
denominado DAAB (Data Access Application
Block). DAAB forma parte hoy de Enterprise
Library, que podrán encontrar navegando un poco
por los sitios de MSDN. No voy a caer en comentar que para mí está mal hecho, porque posiblemente me tiraría tierra encima, ya que fui uno de
los que aportó para la idea y el diseño, pero sí decir
que yo lo hubiese hecho algo distinto.
Como en estas publicaciones pretendo no solo
“dar las cosas casi listas para usar”, sino también llevaros por los caminos del aprendizaje, voy a montar
otro, que se parece bastante al que solemos usar.
¿Qué necesitamos?
Hagamos una lista de lo que nos hace falta para
operar adecuadamente con datos:
• Conectarnos al motor.
–Administrar las conexiones.
• Obtener datos del mismo.
–Un valor único.
–Un conjunto de valores de una sola fila.
–Un conjunto de filas.
• Actualizar información.
–Insertar.
–Actualizar.
–Eliminar.
–Ejecutar procesos.
• Operar dentro de transacciones.
Y otra lista de lo que deberíamos tener en cuenta para tener un componente que realmente sea
efectivo y completamente funcional:
• Que disponga adecuadamente de los recursos.
• Que optimice en rendimiento y escalabilidad.
• Que informe de sus acciones de ser necesario,
para permitirnos evaluar la funcionalidad de una
aplicación y detectar sus cuellos de botella.
• Que pueda operar con distintas versiones de
bases de datos.
<< dnm.plataforma.net
Consideraciones de diseño
Volvamos a ODBC
No, no. No voy a usar ODBC. Quiero que volvamos
a ODBC para considerar cómo funciona e implementar algo similar. ODBC es la primera implementación de “buenas intenciones”: permitir a desarrolladores escribir aplicaciones que interactúen con distintos sistemas propietarios.
ODBC no es más que un conjunto de estándares
para que las empresas de bases de datos implementen
ciertas funcionalidades a las cuales ODBC pueda acceder, y por el otro lado, un conjunto de llamadas estándar, para que los programadores “hablen” con las bases
de datos siempre de la misma manera que normalmente llamamos API. O sea, manteniendo una interfaz común, desentendernos de cómo se implementa
internamente; como un conector USB.
Pero hagámoslo en .NET
Este tipo de implementaciones en .NET se basan en
dos características de la plataforma: pueden ser interfaces o pueden ser clases que obligatoriamente deban
heredarse, comúnmente denominadas abstractas (MustInherit o abstract, dependiendo del lenguaje de programación).
Public MustInherit Class BaseDataServer
Protected Sub New()
End Sub
Protected ReadOnly Property Connection() As _
System.Data.Common.DbConnection
Get
End Get
End Property
Public Property Transaction() As _
System.Transactions.Transaction
Get
End Get
Set(ByVal value As System.Transactions.Transaction)
End Set
End Property
Public Function Execute(ByVal procedureName As String,_
ByVal ParamArray parameters As Object()) As Integer
End Function
Public Function GetValue(ByVal procedureName As String,_
ByVal ParamArray parameters As Object()) As Object
End Function
Public Function GetValues(ByVal procedureName As String,_
ByVal ParamArray parameters As Object()) As Object()
End Function
Public Function GetTable(ByVal procedureName As String,_
ByVal ParamArray parameters As Object()) _
As System.Data.DataTable
End Function
Public Function GetReader(ByVal procedureName As String,_
ByVal ParamArray parameters As Object())
As System.Data.Common.DbDataReader
End Function
Public Sub Fill(ByVal procedureName As String, _
ByRef destination As IEnumerable, _
ByVal ParamArray parameters As Object())
End Sub
Public Function ExecuteSQL() As Integer
End Function
Public Function GetReaderFromSQL(ByVal sql As String)_
As System.Data.Common.DbDataReader
End Function
Public Function GetValuesFromSQL(ByVal sql As String)_
As Object()
End Function
Public Function GetValueFromSQL(ByVal sql As String)_
As Object
End Function
Public Sub FillFormSQL(ByVal sql As String,_
ByRef destination As IEnumerable)
End Sub
Public Function GetTableFromSQL(ByVal sql As String)_
As System.Data.DataTable
End Function
End Class
Listado 1. Miembros de la clase base abstracta.
<<dotNetManía
Claro, llegados a este punto, comienzan las discusiones
acerca de la versatilidad de este tipo de componentes, la
“generalización” del código, la funcionalidad contra
varias plataformas versus la especificidad de operar aprovechando las mejores características de un motor de base
de datos específico, etc.
Este tipo de consideraciones me persiguen desde la época de DAO (estoy hablando de la época en
que Visual Basic tenía 7 disquetes ☺) o RDO o
ADO (que todavía era huérfano, hasta que lo adoptó
.NET). Bajo esas consideraciones, mucha gente
comenzó grandes desarrollos con ODBC basados
en la premisa “funciona con cualquier motor”. Lo
cual no estaba del todo mal, pero se me hace que
es “nivelar hacia abajo”… además de que eso no es
tan cierto.
Pero, por otra parte, me recuerdo colaborando
hace años con una empresa que necesitaba codificar
un sistema para que funcionase con al menos dos de
las grandes bases de datos, pero una no retornaba
registros si se ejecutaban procedimientos almacenados, lo cual alteraba en gran medida la funcionalidad
de la aplicación.
Con esto quiero decir que generalizar es bueno,
pero sin exagerar, y que a veces, el resultado no sirve
en todos los casos.
39
<< dnm.plataforma.net
De esta manera, se puede definir toda la interfaz de
utilización (la API), a ser llamada desde las aplicaciones
que usen este componente; pero en cada caso la implementación será específica por cada clase concreta.
Diseñemos
Básicamente, lo que necesitamos en nuestra clase abstracta se muestra en el diagrama de la figura 1. Y el
detalle de las firmas de cada
miembro se presenta en el
listado 1.
Algunos comentarios
Figura 1.
Clase base abstracta
• Estoy dejando métodos
para ejecutar sentencias
SQL simplemente porque
siempre alguien se queja
que no los tiene. Lo lógico, seguro y óptimo en
cuanto a ejecución es que
todo se realice usando procedimientos almacenados.
Tanto es así, que en la versión “real” dichos métodos
están decorados con el
atributo Obsolete, como se
muestra:
<Obsolete(“Sería mejor que uses un procedimiento almacenado”)>_
Public Function ExecuteSQL() As Integer
End Function
• Las propiedades Connection y Transaction son
accesibles solo por esta clase base y aquellas que
la hereden; de esta forma, nadie externamente
accede “en directo” a la base de datos.
Protected mConnectionString As String
Ahora, dependiendo de qué motor de bases de datos
se trate, podremos utilizar diferentes objetos Connection (SqlConnection, OracleConnection, OleDbConnection, etc.). Entonces nuestra clase abstracta manipulará
la conexión como System.Data.Common.DbConnection, y
le encargará a quienes hereden de ella que se responsabilicen de la creación de la instancia. Eso se logra con
un método que tenga definición diferida (o sea, que
deba definirse en las clases que heredan de ésta). Dicho
método se declara con MustOverride (listado 2).
Protected MustOverride Function InternalCreateConnection() As _
System.Data.Common.DbConnection
Private mConnection As System.Data.Common.DbConnection = Nothing
Protected ReadOnly Property Connection() As _
System.Data.Common.DbConnection
Get
If mConnection Is Nothing Then
mConnection = internalCreateConnection()
End If
Return mConnection
End Get
End Property
Listado 2
Algo similar, pero sin depender de las clases herederas, haremos con la transacción del listado 3.
Private mTransaction As System.Transactions.Transaction
Public ReadOnly Property Transaction() As _
System.Transactions.Transaction
Get
If mTransaction Is Nothing Then
mTransaction = New System.Transactions.CommittableTransaction
End If
Return mTransaction
End Get
End Property
Codificando lo abstracto
Comencemos pues a codificar lo que implementa la
clase base.
<<dotNetManía
La cadena de conexión
40
Vamos a obtener la misma a partir de dos posibles orígenes: o el programador especifica la cadena
de conexión cuando crea una instancia, o indica el
nombre de la entrada correspondiente en el archivo
de configuración.
Dado que esta es una clase abstracta, no puede
crearse una instancia directamente. Ese trabajo será
de las clases que hereden de ella. Sin embargo, sí podemos almacenar dicha cadena en esta clase base.
Listado 3
[
NOTA
Este tipo de manejo transaccional es óptimo siempre que estemos tratando con
bases de datos que entiendan el espacio
de nombres System.Transactions, como
es el caso de SQL Server 2005. En otros
casos, tal vez deberá utilizarse los objetos
Transaction propios de cada clase de conexión a base de datos, o implementar EnterpriseServices, si se requiere manipular distintos orígenes de datos.
]
<< dnm.plataforma.net
[
NOTA
Si no se necesita manipular la transacción, sino simplemente
utilizar la que exista en el entorno (como ocurriría en el
caso de componentes de tipo ‘reglas de negocio’ que controlen por ellos mismos la transacción), en lugar de crear
una instancia de CommitableTransaction se puede usar la que
se maneja automáticamente, utilizando en el método de lectura la siguiente instrucción:
mTransaction = System.Transactions.Transaction.Current
]
Cada uno de los demás métodos utilizará entonces el miembro GetCommand.
Como un ejemplo, veamos el método
Execute:
Public Function Execute(_
ByVal procedureName As String, _
ByVal ParamArray parameters As Object())_
As Integer
Using c As DbCommand = _
GetCommand(procedureName, parameters)
Return c.ExecuteNonQuery
End Using
End Function
De los comandos a ejecutar
Public Class DbCommandCollection
Inherits Solid.Tools.SpecialCollection( _
Of String, System.Data.Common.DbCommand)
End Class
Nuestra clase abstracta expondrá
una instancia de esta colección, como
una propiedad que solo ella y aquellas
que la hereden puedan utilizar:
Cuando se requiera hacer algo con
la base de datos, o sea, cuando se necesite un objeto Command, se buscará en
dicha colección. En caso que el comando aún no esté, la clase hija deberá crear la instancia y obtener los parámetros
que le correspondan.
Ahora bien, una de las diferencias
entre los motores de bases de datos es que
cada uno maneja los parámetros de distintas maneras. Por ello, asignar valores
a dichos parámetros puede diferir entre
motores. Entonces, cuando hay diferencias, que cada quien se haga cargo de lo
que le toca. Nuestra clase abstracta exigirá que sus hijas implementen un método que retorne un objeto comando listo
para usar. Como además la forma de obtener los parámetros, etc. puede cambiar,
también las clases hijas serán responsables de manipular la colección.
Nuestra clase abstracta solo exigirá la
definición del método, y hará uso de él.
Protected MustOverride Function _
GetCommand( ByVal procedureName As String,_
ByVal ParamArray parameters() As Object)_
As System.Data.Common.DbCommand
En los casos de los métodos que
obtienen valores, el código de ejecución será algo distinto (listado 4).
Public Function GetValue(_
ByVal procedureName As String, _
ByVal ParamArray parameters As Object())_
As Object
Using c As DbCommand = _
GetCommand(procedureName, parameters)
Return c.ExecuteScalar
End Using
End Function
Public Function GetValues(_
ByVal procedureName As String, _
ByVal ParamArray parameters As Object())_
As Object()
Using c As DbCommand = _
GetCommand(procedureName, parameters)
With c.ExecuteReader( _
System.Data.CommandBehavior.CloseConnection)
.Read()
Dim retValues(.FieldCount-1) As Object
.GetValues(retValues)
Return retValues
End With
End Using
End Function
Listado 4
Al igual que cuando deba retornar
readers o tablas (listado 5).
Los métodos que utilizan sentencias SQL (mal hecho, insisto)
harían cosas similares, con la excepción que, al no haber posibilidad de
estar seguros de que son los mismos
comandos que en la llamada anterior,
habrá que crear el comando cada vez.
Entonces, nuestra clase abstracta exigirá que exista un creador de coman-
<<dotNetManía
Uno de los temas importantes acerca de
la utilización de los comandos de ejecución para procedimientos almacenados es que existen distintas formas de
crearlos. En una de ellas, se va a la base
de datos a buscar cuáles son los parámetros que dicho procedimiento almacenado utiliza. Dinámico, simple de
codificar…, pero que consume muchos
recursos del motor de base de datos.
Conceptualmente, este componente de
acceso a datos se basa en ese mecanismo, ya que recibe siempre el nombre
del procedimiento almacenado, con lo
cual este componente debe encargarse
de investigar acerca de sus parámetros.
Por ello, y para disminuir los “viajes” al servidor de datos para simplemente obtener metadatos, implementaremos un mecanismo de persistencia
de objetos comando, que almacene los
mismos con todos sus parámetros. La
primera vez que se utiliza un comando,
se investigan sus parámetros y se guarda el objeto Command correspondiente en
caché.
Aquí podemos entonces utilizar la
colección especializada de nuestra
entrega anterior, utilizándola como base
de una clase específica para nuestros
objetos comando:
Protected mColCommands As _
DbCommandCollection
Protected ReadOnly Property _
CommandColection() As DbCommandCollection
Get
If mColCommands Is Nothing Then
mColCommands=New DbCommandCollection
End If
Return mColCommands
End Get
End Property
41
<< dnm.plataforma.net
como propiedades u otras funcionalidades especializadas.
De momento, solo me queda espacio para sentar las bases. Primero,
nuestra clase comando. Definimos
una clase nueva, que implemente System.Data.IDbCommand.
Public Function GetTable(ByVal procedureName As String, _
ByVal ParamArray parameters As Object()) As System.Data.DataTable
Dim dt As New DataTable
Using c As DbCommand = _
GetCommand(procedureName, parameters)
dt.Load( _
c.ExecuteReader( _
System.Data.CommandBehavior.CloseConnection))
End Using
Return dt
End Function
Public Class Command
Implements System.Data.IDbCommand
End Class
Public Function GetReader(ByVal procedureName As String, _
ByVal ParamArray parameters As Object()) As System.Data.Common.DbDataReader
Using c As DbCommand = _
GetCommand(procedureName, parameters)
Return c.ExecuteReader( _
System.Data.CommandBehavior.CloseConnection)
End Using
End Function
Al pulsar [Intro] en la línea que
determina la herencia, aparecerán
muchos métodos que deberemos
codificar.
Para ello, definiremos una variable
de tipo DBCommand, y utilizaremos los
mismos miembros de dicha variable,
por ejemplo:
Listado 5
dos a partir de sentencias SQL y hará
uso de él (listado 6).
can” entre sí, y que podamos, por
ejemplo, manipular los parámetros
Private mCommand As _
System.Data.Common.DbCommand
Public Sub Cancel() Implements _
System.Data.IDbCommand.Cancel
mCommand.Cancel()
End Sub
Protected MustOverride Function CreateCommand( ByVal sql As String) As DbCommand
Y así con el resto, que espero
podáis completar para el próximo
número.
Luego, en nuestra clase de acceso a
datos, agregamos variantes de los mismos métodos que reciban esta clase como
primer argumento (figura 2).
<Obsolete(“Sería mejor que uses un procedimiento almacenado”)> _
Public Function ExecuteSQL(ByVal sql As String) As Integer
Using c As DbCommand = CreateCommand(sql)
Return c.ExecuteNonQuery
End Using
End Function
Listado 6
<<dotNetManía
Haciendo las cosas
de la mejor manera
42
A veces, esto de preguntarle a la
base de datos por los parámetros
puede ser útil, pero no es la mejor
manera de hacer las cosas. Por eso,
vamos a tener los mismos métodos,
pero que reciban objetos comando
como parámetros. De esta forma,
serán los componentes que usen este
servicio quienes creen y definan los
parámetros en cada caso. Y más que
eso, nuestro servicio de datos reconocerá una clase abstracta para que
todos los objetos comando se “parez-
Figura 2. Diagrama de clases hasta el momento
Isla VB
Guillermo «Guille» Som
Una isla para Visual Basic
en dotNetManía
O cómo hacer las cosas mejor con Visual Basic
Con el quinto año de dotNetManía estrenamos una nueva columna en la revista dedicada exclusivamente a los que gustan desarrollar con Visual Basic. No es
que antes no hubiera nada paraVisual Basic, pero ya iba siendo hora de que tuviésemos nuestro propio rincón. En esta isla tendremos ocasión de ver muchas
cosas relacionadas con Visual Basic, particularmente con la versión 9.0, que es la
que se incluye en Visual Studio 2008, aunque muchos conceptos serán válidos
también para las versiones anteriores.
Empezando por el principio (o casi)
Guillermo “Guille”
Som
Es Microsoft MVP de
Visual Basic desde 1997.
Es redactor de dotNetManía, mentor de Solid
Quality Mentors, tutor
de campusMVP, orador
de Ineta Latam, y autor
de los libros “Manual
Imprescindible de Visual
Basic .NET” y “Visual
Basic 2005”.
http://www.elguille.info.
Y qué mejor que empezar esta nueva sección con algunos consejos. No es que vayamos a tratar solo de cosas
de iniciación, pero como soy consciente que muchos
de los que se deciden a usar Visual Basic para .NET
son desarrolladores que antes han usado Visual Basic
6.0, qué mejor que empezar comentando cosas que
sirvan para ir deshaciéndose de viejas costumbres y
preparando el terreno para lo que .NET nos ofrece,
porque no debemos olvidar que Visual Basic 2008
(VB9 para los amigos) utiliza todo lo que las clases de
.NET ofrecen, así que mejor acostumbrarnos a usar
esas clases, al menos en la medida de lo posible.
Sobre nombres y versiones
Empecemos aclarando nombres y versiones, ya que
algunos se confunden con la forma de llamar al lenguaje. Visual Basic 9.0 es el nombre “oficial” del compilador que se incluye con .NET Framework 3.5,
que es el que se distribuye con Visual Studio 2008.
Esta versión de .NET Framework en el fondo
usa la versión 2.0 del runtime o motor de ejecución
(CLR), aunque añade nuevas funcionalidades en forma de librerías (ensamblados DLL), que nos permiten usar cosas como LINQ y otras de las novedades
de Visual Studio 2008 (para más información, ver el
libro que los suscriptores de dotNetManía recibirán
con el número de marzo de 2008).
Con el entorno de desarrollo de Visual Basic 2008
(ya sea desde Visual Studio 2008 o desde la versión
Express) podemos crear aplicaciones para cualquiera
de las tres versiones de .NET Framework que se basan
en el CLR 2.0, que son: .NET Framework 2.0, el mismo que se incluye con Visual Basic 2005 (o VB8); .NET
Framework 3.0, que es el que permite crear aplicaciones basadas en Windows Presentation Foundation
(WPF) y que se distribuye con Windows Vista; y finalmente, para .NET Framework 3.5.
Al crear un nuevo proyecto, podemos seleccionar
la versión de .NET que usaremos como “destino”, es
decir, qué características queremos que estén a nuestra
disposición. En la figura 1 podemos ver que al crear un
nuevo proyecto tenemos la posibilidad de elegir la versión de .NET que queremos usar; por supuesto, dependiendo de qué versión usemos, tendremos disponibles
los tipos de proyectos “soportados” por esas versiones.
<< dnm.isla.vb
El compilador de Visual Basic
9.0 sabe más que los ratones
coloraos
No, no estamos en el programa de
Canal Sur que dirige Jesús Quintero,
pero esa expresión nos viene como anillo al dedo, ya que lo que debemos saber
es que independientemente de la versión de destino, las novedades del compilador de Visual Basic 9.0 estarán a
nuestra disposición. Es decir, el que elijamos .NET 2.0 como destino no
querrá decir que solo podamos usar las
instrucciones que había en la versión
anterior de Visual Basic; lo que quiere
decir es que no podremos usar nada que
esté en las librerías que se distribuyen
con versiones posteriores.
Para que quede claro, el compilador que siempre se usa con los proyectos creados con Visual Studio 2008 es
el compilador de esta nueva versión, es
decir, el compilador de Visual Basic 9.0,
independientemente de que usemos o
no los nuevos ensamblados distribuidos
con las versiones posteriores a la elegida al crear el proyecto.
Por ejemplo, con Visual Basic 2008
(que usa el compilador de VB9) podemos
usar todo lo relacionado con la inferencia de tipos (ya veremos con detalle esto
de la inferencia, pero por ahora solo decir
que el compilador de Visual Basic usará
el tipo de datos adecuado para una variable, dependiendo del tipo que se le asig-
ne). Lo mismo es aplicable a la creación
de tipos anónimos; es decir, con Visual
Basic 2008 podemos escribir un código
como el del listado 1 y después de compilarlo, ejecutar ese programa en un Windows que solo tenga el
runtime de .NET 2.0
Dim nums As Integer() = {1, 2, 3, 4, 5, 6, 7, 8}
instalado.
¿Cómo es posible
For Each n In nums
que esto funcione en
Console.WriteLine(n)
.NET Framework 2.0?
Next
Por la sencilla razón de
Dim dnm = New With {.Nombre = “dotNetManía”, .Año = 2008}
que esas “novedades”
de Visual Basic 9.0
Console.WriteLine(“dnm.Nombre = {0}, dnm.Año = {1}”, _
están en el compilador
dnm.Nombre, dnm.Año)
y ese compilador genera el código IL (el usa- Listado 1. Código de Visual Basic 2008 que se ejecutará con .NET 2.0.
do por el runtime de
.NET para compilar el
código en tiempo de
ejecución) adecuado
para la versión de
.NET que se ha elegido como destino, (en
nuestro ejemplo el
.NET Framework 2.0),
y por tanto, el código
funcionará en cualquier
equipo que solo tenga
instalado el runtime de
la versión 2.0.
Aclarar que el código del listado 1 utiliza
Option Strict On; es
Figura 2.Visual Basic 2005 no reconoce
decir, que todas las
las novedades de Visual Basic 2008.
variables deben tener
<<dotNetManía
Figura 1. Las versiones de .NET disponibles al crear un nuevo proyecto.
un tipo de datos adecuado, y por tanto
no se permite que se asigne a una variable un valor que no sea adecuado. De
esta opción “estricta” hablaremos en un
momento.
Este código también usa Option Infer
On, que es la opción que permite al compilador “inferir” el tipo que debe tener
una variable. Por ejemplo, en el bucle For
Each se usa la variable n, que no tiene un
tipo definido, pero que el compilador
deduce (acertadamente) que debe ser de
tipo Integer, ya que se utiliza para recorrer los valores de un array de ese tipo.
Lo mismo ocurre con la asignación a la
variable dnm, en la que el valor asignado
es un valor de tipo anónimo, es decir, un
tipo de datos creado al vuelo.
Por supuesto, si el código del listado
1 lo usamos con Visual Studio / Basic 2005
no funcionará, ya que el compilador de
esa versión, aunque también use .NET
2.0, no sabe qué hacer con “esas cosas
raras”; el resultado es un montón de erro-
45
<< dnm.isla.vb
res, tal como vemos en la figura 2, empezando por la definición de Option Infer
y continuando con la variable n, o por el
uso inadecuado de With, para finalizar con
la variable dnm, ya que se intenta acceder
a miembros inexistentes de una variable
que teóricamente sería de tipo Object,
aunque, en realidad, el error producido
por el uso de With no le ha dado tiempo
al compilador de indicarnos que Option
Strict On requiere que todas las variables
se declaren usando un tipo.
Aunque VB9 sea muy listo,
no hace milagros
<<dotNetManía
Lo que no podrá hacer el compilador
de Visual Basic 2008 es usar características que no están disponibles, salvo porque haya otras librerías (o extensiones)
que le permitan usarlas. Por ejemplo,
en el listado 2 tenemos un código que
usa las extensiones de LINQ, que están
definidas en una librería que se distribuye con .NET Framework 3.5; por
tanto, ese código no podrá compilarse
para una versión de .NET anterior.
46
Figura 3. El diálogo “Agregar referencia” sólo muestra
como disponibles las librerías adecuadas para la
versión de destino de .NET Framework elegida.
pulsando en el botón de opciones
avanzadas de compilación, y eligiendo en el cuadro de diálogo
mostrado (ver la figura 4) la versión de .NET que queremos usar.
Por supuesto, si elegimos
como destino .NET Framework
3.5, el equipo en
el que vayamos a
‘ Esto no se podrá usar en .NET 2.0
usar este ensam‘ porque no están las referencias a LINQ
blado tendrá que
Dim q = From n In nums _
tener instalada esa
Where n > 3 _
Select New With {.Numero = n, _
versión del runti.Descripcion = “El número es “ & n}
me de .NET. Aunque, dependiendo
Listado 2. Un código que usa las instrucciones para LINQ.
de la alineación de
los planetas, puede que no sea necesario. En serio
Es posible que piense: vale, no pue(el VB9 no sabe nada de astrodo usar esa característica porque el compilador necesita una referencia a la librería
System.Data.Linq.dll, ¿y si la añado?
NOTA
Bueno, puede intentarlo, pero no lo permitirá, tal como vemos en la figura 3, en
En el código de ejemplo que
la que se nos indica que esa librería no es
acompaña al artículo, el procompatible con la versión de .NET que
yecto dnm.vb.console2 utilihemos elegido como destino.
za .NET Framework 3.5,
Por tanto, si queremos usar esas
pero también funcionará en
librerías “especiales” de .NET Frameun sistema con .NET 2.0,
work 3.5, podemos hacerlo, pero para
aunque la llamada al método
ello debemos cambiar la versión de
que utiliza características
.NET para la que queremos compilar,
específicas de .NET 3.5 no
en este caso a .NET 3.5. Ese cambio lo
funcionará.
podemos hacer en la ficha de compilación (en las propiedades del proyecto),
[ ]
nomía), el que indiquemos una versión de .NET
superior a la 2.0 solo nos
obligará a tener esa misma versión instalada en el
equipo en el que despleguemos la aplicación si
usamos alguna de las
características incluidas en
esa versión. Por ejemplo,
si compilamos el código
del listado 1 con .NET
Framework 3.5 como destino, también funcionará
en sistemas que no tengan
instalado el runtime de
.NET 3.5, ya que el código no usa ninguna característica de esa versión de
.NET Framework. Sin
Figura 4. En cualquier momento podemos cambiar
la versión de .NET que queremos usar
en nuestro proyecto
embargo, para que funcione el código
del listado 2, el equipo en el que se utilice esa aplicación deberá tener instalado el runtime de .NET 3.5.
Recomendaciones para un
buen uso de Visual Basic
Para terminar este primer artículo de
la nueva sección de dotNetManía dedicada a Visual Basic, voy a dar una serie
de consejos que nos facilitarán la programación con Visual Basic 2008 (algunas también son válidas para las versiones anteriores).
<< dnm.isla.vb
mos que se hará una conversión es que
eso nos dará pistas para saber que es posible que esa cadena no contenga en realidad un valor adecuado para un tipo
entero (para más detalles, ver mis artículos en dotNetManía 43 y 44 relacionados con la depuración en .NET).
Option Strict está desactivada
al instalar el Visual Studio
Cuando instalamos Visual Studio (o
Visual Basic Express), el valor predeterminado de Option Strict será Off
(desactivado); por tanto, recomiendo
encarecidamente que la dejemos activada para todos los nuevos proyectos.
Esa activación la haremos seleccionando “Opciones” (“Options”) del menú
“Herramientas” (“Tools”) y del cuadro
de diálogo mostrado, en la rama “Proyectos y soluciones” (“Projects and Solutions”) tendremos la opción “Valores
predeterminados de VB” (“VB
Defaults”) en el que podremos elegir el
valor On para Option Strict, tal como
vemos en la figura 5, que está capturada de una instalación en inglés de Visual
Studio 2008, ya que a la hora de escribir este artículo la versión en español
aún no está disponible.
Una vez modificada esta opción,
cada vez que creemos un nuevo proyecto se usará el valor On de forma predeterminada.
Usar adecuadamente Option
Strict (y el resto de opciones)
Una de las ventajas que tiene Visual
Basic es que estas opciones las podemos
personalizar a nivel de fichero de código. Es decir, si en nuestro proyecto
tenemos activada Option Strict (o cualquier otra de las opciones mostradas en
la figura 5) y necesitamos usar una de
esas opciones de forma desactivada en
un fichero concreto (por ejemplo, en
una clase que use COM –ver dotNetManía número 22–, y que por las circunstancias queramos usar esos objetos
COM mediante lo que se conoce como
enlace tardío –late binding–), podemos
utilizar la instrucción Option Strict Off
en ese fichero en concreto; de esta forma, “todo” el código que usemos en ese
fichero de código tendrá desactivada la
comprobación estricta.
[ ]
NOTA
Si queremos “mezclar” código
que use diferentes valores de
Option Strict, lo podemos hacer
creando clases parciales, de forma que el código que use el
valor desconectado (Off) esté
en un fichero independiente,
con idea de que no perdamos
las ventajas de usar esa opción
en modo On.
Figura 5. Predeterminar Option Strict On para los nuevos proyectos
<<dotNetManía
Una de las recomendaciones que
siempre hago es que dejemos activada
la opción de comprobación estricta del
código, es decir, dejar siempre en On la
opción Option Strict. Al usar Option
Strict On en nuestro código, el compilador de Visual Basic hará ciertas comprobaciones de buen uso de las variables y las conversiones que realicemos.
Algunos verán que tener activada
esta opción es... ¡un peñazo!, ya que nos
obliga a pensar un poco antes de hacer
las cosas. Con esa opción estricta activada, tendremos que declarar todas las
variables con un tipo de datos adecuado, además de que al realizar las conversiones entre tipos diferentes de datos
siempre tendremos que hacer la conversión (cast, que dice la gente que prefieren usar lenguajes de la familia C)
adecuada. Pero en realidad esto no es
un impedimento, y a la larga saldremos
ganando, particularmente porque nos
evitaremos quebraderos de cabeza en
errores (bugs) que en el otro caso serían
difíciles de detectar.
Cuando Option Strict está desconectado, el compilador hará las conversiones que estime oportunas, que
algunas veces pueden ser erróneas. Pero
esa no es la peor parte, ya que si definimos una variable sin un tipo específico, el compilador usará el tipo Object
como tipo de datos (siempre que no
tengamos activado Option Infer), con
lo cual el rendimiento final puede que
no sea el mejor.
En cualquier caso, el entorno de trabajo de Visual Basic (IDE) utiliza lo que
se conoce como compilación en segundo plano; es decir, cada vez que escribimos una línea de código, el IDE comprueba si esa línea de código es correcta, y en caso de que no lo sea, nos muestra opciones para rectificarla. Por ejemplo, si queremos asignar a una variable
de tipo entero el valor de una variable (o
constante) de tipo cadena, nos avisará de
que Option Strict no lo permite, y nos
ofrecerá una alternativa, que no es otra
cosa que la conversión de la cadena en
un entero, por medio de la función CInt.
Vale, muy bien, pero eso mismo es lo
que hará el compilador en tiempo de ejecución. Sí, pero la ventaja de que sepa-
47
<< dnm.isla.vb
Sobre la inferencia automática de tipos (Option Infer)
Como hemos visto en el código de los
listados mostrados anteriormente,
Visual Basic 9.0 es capaz de “adivinar”
el tipo de datos que tendrá una variable dependiendo del valor que le asignemos. Esto es posible solo si tenemos
activada Option Infer, que es el estado
por defecto que tendrán todos los proyectos creados con Visual Basic 2008.
Esto supone que si por olvido (o comodidad) no indicamos el tipo de datos de
una variable, el tipo será el que el compilador crea que debe ser.
Por ejemplo, si declaramos esta
variable:
<<dotNetManía
Dim saludo = “Hola, Visual Basic”
48
El tipo de datos que tendrá la variable saludo será String, ya que es eso lo
que estamos asignando, una cadena.
La inferencia automática de tipos es
independiente del valor que tenga
Option Strict, y solo la podemos usar
si usamos Option Infer On. En cualquier
caso, no debemos abusar de la inferencia automática de tipos, y mi recomendación es usarla solo en casos muy concretos, como puede ser el uso de variables en bucles o cuando estemos haciendo pruebas; pero no es recomendable
usarla en todas las ocasiones, ya que la
lectura de nuestro código se puede complicar más de lo deseado.
Como excusa o justificación, decir
que siempre nos queda el recurso de
pasar el cursor del ratón sobre una
variable y averiguar de qué tipo de datos
esa variable es, tal como vemos en la
figura 6, donde a pesar de estar desactivada la comprobación estricta de tipos,
el tipo de la variable es String y no el
que tendría de forma predeterminada
( Object) si no tuviésemos activado
Option Infer.
Lo que sí debemos saber es que la
inferencia automática de tipos solo se
aplica a variables locales, es decir, a las
variables declaradas “dentro” de un
procedimiento (método, propiedad,
constructor, etc.). Por lo tanto, no
podremos usar esta característica para
ne la clase Process (y que Visual Basic
siempre importa automáticamente).
Figura 6. La inferencia automática
de tipos es independiente del valor
de Option Strict.
los parámetros de esos procedimientos
ni como valor devuelto por los mismos,
y tampoco podremos declarar variables
“inferidas” a nivel de módulo.
En este último caso, si tenemos
desactivada Option Strict, la variable
será de tipo Object, y si tenemos activada la comprobación estricta, recibiremos un error indicándonos que eso
no es aceptable, ya que todas las variables deben declararse con la cláusula As.
Como recomendación, yo siempre
procuro indicar en cada fichero qué
opciones uso, independientemente de
cómo las tenga configuradas en las
opciones del proyecto (o del IDE), así
las opciones estarán claras para todos
los que lean mi código. También procuro añadir las importaciones de los
espacios de nombres que uso en cada
fichero, pero esto son más bien manías
mías..., aunque en muchos casos me
facilita la lectura del código, particularmente el que he escrito tiempo atrás;
esa es otra de las características que
siempre ha tenido Visual Basic para
.NET, la de importar automáticamente los espacios de nombres que el compilador “cree” que debemos usar en
nuestros proyectos. Y si después quiero reutilizar ese fichero de código en
otro proyecto que no tiene la importación adecuada, pues... no es que pase
mucho, ya que el IDE de Visual Basic
2008 me “asiste” y me da la opción de
agregar la importación del espacio de
nombres adecuado; al menos si eso es
posible, tal como podemos ver en la
figura 7, en la que en el proyecto no
tengo agregada de forma automática la
importación del espacio de nombres
System.Diagnostics, que es el que defi-
Figura 7. El IDE de Visual Basic 2008
permite agregar las importaciones
que necesitemos.
Por supuesto, para que esta asistencia funcione, debemos tener agregada la
referencia correspondiente; es decir, si
queremos usar la clase MessageBox desde una aplicación de consola, solo podremos hacerlo si previamente hemos agregado una referencia al ensamblado System.Windows.Forms.dll, ya que el editor
de Visual Basic 2008 es bueno, pero,
como dije antes, no hace milagros.
Conclusiones
Y esto es todo para este primer
encuentro con la nueva sección dedicada exclusivamente a Visual Basic.
Quisiera aclarar que aunque el código que mostraré en estos artículos
será para Visual Basic 2008 (o VB9),
en la medida de lo posible también
crearé proyectos para C# que usen lo
que trate en estos artículos; así los que
han seguido mi sección “Inicio” en
esta revista (desde que se inició, en el
número 16, de Junio de 2005) no se
sentirán abandonados. Por supuesto,
muchas de las cosas que veremos
usarán características propias de
Visual Basic; en esos casos es posible
que no haya código equivalente para
C#, pero siempre nos quedará el
recurso de crear un ensamblado de
Visual Basic y usarlo desde otro proyecto de C#, que esa es una de las
ventajas de la interoperabilidad de
.NET.
Lo importante es que... ¡nos seguimos viendo en dotNetManía!
todonet@qa
Dino Esposito
es mentor de Solid
Quality Learning. Es
ponente habitual en
los eventos de la
industria a nivel
mundial.Visite su
blog en: http://weblogs.
asp.net/despos.
(todotNet.QA@
dotnetmania.com)
Cachés globales y Silverlight
En este artículo cubriremos las características relacionadas con la configuración de
un sistema global de caché que abarca todas las máquinas de una granja de servidores Web y desvelaremos un sencillo truco para detectar la versión del plug-in de
Silverlight instalado, para construir páginas Silverlight dependientes de la versión.
Recientemente, hemos escalado una aplicación Web grande a múltiples servidores Web, organizados en una granja. La mayoría de las páginas hacen uso intensivo de la caché de ASP.NET. En la
nueva configuración, experimentamos algunos problemas menores relativos a la caché. Era como
si los mismos datos fueran descargados y puestos en la caché varias veces y no siempre aparecieran en sincronía. Después de alguna investigación, hemos determinado que se debe a la nueva arquitectura multi-servidor, donde la caché no parece estar compartida entre los servidores.
La pregunta es ¿cuál es la mejor forma de crear un sistema global de caché en ASP.NET?
El objeto Cache de ASP.NET es específico del
Dominio de Aplicación, y, por supuesto, no puede ser compartido entre múltiples CPU y servidores. Las técnicas de caché en ASP.NET pierden mucho cuando la aplicación se escala a un
modelo de jardín de servidores (un servidor y
múltiples CPU) o de granja (múltiples servidores y una CPU cada uno).
En ASP.NET, se crea una instancia de Cache
para cada aplicación y cada aplicación se asocia a
un Dominio de Aplicación en su proceso. La clase Cache se implementa como un wrapper (envoltorio administrado) en torno a una clase interna
que es un contenedor del tipo IEnumerable. La
clase real usada para implementar el objeto Cache
varía dependiendo de las CPU implicadas. Si solo
hay una disponible, el sistema usa una clase interna llamada CacheSingle; en otro caso, utiliza la
clase CacheMultiple. De cualquier manera, se
almacenan ítems de datos en una tabla hash (una
estructura de datos extremadamente rápida en su
acceso, y con un tiempo de acceso prácticamente constante). Existirá una tabla hash por cada
CPU. En su operativa, lo que sucede es que
CacheSingle opera sobre una sola tabla hash,
mientras que CacheMultiple maneja un array de
tablas hash.
Asumido este modelo, no sorprende que en
una máquina multiprocesador en la que se ha vinculado más de una CPU con el proceso
ASP.NET, cada procesador acaba teniendo su
propia copia del objeto Cache para cada dominio
de aplicación (léase, aplicación ASP.NET) gestionado. Estos objetos Cache no están sincronizados. En un jardín no puede garantizarse que
los usuarios harán sus peticiones a la misma CPU
(y proceso) en distintas solicitudes de páginas. Así
que el estado de la caché no garantiza una coherencia con lo que la última página hizo en la última petición.
<<dotNetManía
[email protected]
Dino Esposito
49
<<dotNetManía
[email protected] [email protected]
<< dnm.todonet@qa
50
Lo mismo es válido para granjas de servidores. En
un escenario así, cada servidor Web tiene su propio
objeto Cache por Dominio de Aplicación. Pero no
puede asumirse que los usuarios volverán al mismo
servidor en peticiones subsiguientes. Y si una petición que debe consumir datos alcanza un servidor
donde no hay datos en la caché, se necesita una nueva lectura. Como consecuencia adicional, cualquier
cambio realizado a un dato en el servidor A no será
visible en el B.
Mientras que habrá ocasiones en que todo parece ir bien, se acabará produciendo una falta de sincronía entre los datos de diferentes servidores que
puede originar anomalías en algunas páginas de la
aplicación. Esto es difícil de abordar y debe ser resuelto de una forma u otra. Así que la pregunta es: ¿existe un objeto similar a Cache que funcione a través de
una arquitectura múltiple? ¿O existe alguna configuración que permita al objeto Cache soportar escenarios remotos? La respuesta, desafortunadamente, es
que no, y si necesitamos uno, tenemos que construírnoslo nosotros mismos.
Para construir un contenedor global de datos que
funcione en estos escenarios, necesitamos recurrir
a un recurso remoto y compartido, tal como una instalación de Microsoft SQL Server (u otra base de
datos). Alternativamente, podemos considerar la creación de una capa de servicios (por ejemplo, un servicio WCF o un Servicio Web) que almacene los
datos en una copia local de la base de datos, o use
su propia memoria para almacenarlos. En otras palabras, se necesita replicar el modelo de extensibilidad que Microsoft ha creado para el estado de la
sesión.
El acceso a datos en caché de forma remota requiere serialización y deserialización y es una operación
sujeta a los efectos de latencia de red. Francamente,
no puede esperarse obtener el mismo nivel de respuesta que se obtiene en un escenario simple. El corolario de esto es que el modelo general para una caché
global y multiservidor es lo suficientemente complejo como para invalidar las ventajas obtenidas del uso
de la caché.
La dicotomía a estudiar, a efectos de este problema, es la del acceso a datos semipreparados en contraposición a la obtención de nuevos datos mediante
la ejecución de otra consulta. ASP.NET ofrece una
infraestructura efectiva de caché en servidor simple,
porque eso es lo que se necesita en la mayoría de las
ocasiones. Extender la infraestructura para soportar
otros escenarios es decisión propia, pero puede guardar desagradables sorpresas en el rendimiento.
Dicho esto, ¿qué puede hacerse? Reescribir la aplicación no es una opción. Puedo imaginar que la mayor
parte de los datos en caché son de solo lectura, o, al
ASP.NET ofrece una
infraestructura efectiva de caché
en servidor simple, porque eso
es lo que se necesita en la mayoría
de las ocasiones
menos, que cambien con poca frecuencia. Esa la razón
de su uso, la mayor parte de las veces. También asumo que la aplicación tiene la facultad de rellenar la
caché si encuentra que está vacía. El comportamiento del objeto Cache asegura que cada servidor de la
granja obtiene sus datos de la fuente original y los
ubica en la caché local. Esto quiere decir que se realizan varias consultas para rellenar las cachés de todos
los servidores. Para este comportamiento, no se necesitan cambios en el código.
A mí no me importaría acceder a la base de datos
directamente siempre que se necesite. Manejar ficheros XML requiere algún trabajo de administración
con el que podría ser complicado operar. Y la pregunta clave aquí es ¿cómo puedo notificar a otros servidores que ha tenido lugar un cambio en los datos
almacenados en la caché de un servidor concreto?
En un escenario de granja de servidores, aprovecharía el mecanismo de dependencia del objeto
Cache de ASP.NET: añadimos los datos consultados
al objeto Cache usando dependencia de ficheros. De
esta forma, cuando el sello temporal (timestamp) del
fichero se modifica, el contenido de la caché es invalidado y se carga nuevamente en el siguiente acceso. Si se utiliza un fichero ubicado en una zona compartida de red, se pueden invalidar simultáneamente todas las cachés de todos los servidores. La
siguiente petición lanzará una nueva consulta sobre
el servidor solicitado. Si el cambio que invalida la
caché se refleja inmediatamente en la base de datos,
no hay problema. Si el cambio está limitado a la
caché del servidor donde sucede la petición, y se persiste a la base de datos posteriormente, entonces
la que los datos expiraron: usando esta información
podemos discernir si es necesario rellenar la caché a
partir de la base de datos, porque es el primer acceso, o acceder al recurso temporal, dado que algunos
datos han cambiado.
Estoy haciendo una aplicación en Silverlight 1.0 para nuestra Intranet. A causa del soporte limitado de
WPF en esta versión, estoy usando un montón de Javascript para añadir capacidades de introducción de
datos y un mínimo de posicionamiento en pantalla. Tenemos planes de migrar esta primera aplicación a
Silverlight 2.0 tan pronto como podamos. ¿Hay forma de introducir algún tipo de control de versión en
el código de una aplicación Silverlight? ¿Se puede escribir código para las dos versiones y discriminar la
versión instalada?
Cualquier página Web equipada con una versión de
Silverlight debe enlazar el fichero Silverlight.js,
que es parte actual del SDK. No se puede decir
demasiado acerca del futuro, pero, actualmente, este
fichero es el mismo para las versiones 1.0 y 1.1 (que
se denominará 2.0 en la versión final). En ese fichero se encuentra un objeto llamado Silverlight con
algunos métodos estáticos. El más típico es createObject, que se usa para instanciar el motor de Silverlight en una página Web. Otro método interesante, que es justo lo que buscas, es isInstalled.
Este método determina si una versión concreta del
producto está actualmente instalada en la máquina
del usuario:
if (!Silverlight.isInstalled("1.0"))
alert("Please, install version 1.0.");
El número de versión consta de 4 valores: versionMajor.versionMinor.buildNumber.revisionNumber. Sin embargo, normalmente, tú solo usarás versionMajor.versionMinor. El método devuelve ver-
dadero igualmente si la versión instalada es superior a la comprobada. Así que, en el ejemplo anterior, la pregunta real es ¿tienes al menos la versión
1.0 instalada?
Claramente, este método está diseñado para permitir deshabilitar algunas características en una
página que requiera una nueva versión del plug-in
de Silverlight. Es interesante notar que, sin embargo, no hay una forma directa de saber –a partir del
complemento– de qué versión se trata, ni puede
leerse directamente la versión mínima que fue solicitada por la página. El siguiente fragmento de código muestra una forma simple de averiguar cuál es
la versión instalada. La figura 1 muestra un ejemplo en acción cuando se implementa esta característica.
Figura 1
var results = "Unknown";
var versionToCheck = "2.0";
var v = Silverlight.isInstalled(versionToCheck);
if (v)
results = versionToCheck;
else
{
versionToCheck = "1.1";
v = Silverlight.isInstalled(versionToCheck);
if (v)
results = versionToCheck;
else
{
versionToCheck = "1.0";
v=Silverlight.isInstalled(versionToCheck);
if (v)
results = versionToCheck;
}
}
Traducido al castellano por Marino Posadas
<<dotNetManía
puede ser necesario crear un fichero (o tabla) temporal en la ubicación compartida, y modificar el código existente para rellenar la caché para que utilice
este recurso. El mecanismo de dependencia informa
al código que hace la llamada acerca de la razón por
[email protected] [email protected]
<< dnm.todonet@qa
51
Octavio Hernández
Laboratorio.net
Visual Guard .NET
El reciente caso aparecido en la televisión nacional, donde una factura recibida por un
usuario mostraba los apellidos de éste cambiados por palabras ofensivas, ha puesto
en evidencia una vez más la importancia de que las aplicaciones a través de las cuales
los empleados manipulan los datos con que las empresas operan realicen una correcta autenticación y registro de actividad de sus usuarios. Este mes presentamos Visual
Guard .NET, un cómodo y útil marco de trabajo que permite gestionar de una manera eficiente y centralizada los usuarios, roles y permisos de una aplicación y asegurar
el acceso de los usuarios a cada uno de los elementos de la misma.
Ficha técnica
Nombre: Visual Guard .NET
Versión: 2.6
Fabricante: Novalys
Sitio Web: http://www.visual-guard.com
Categoría: Marcos de trabajo, seguridad
Precio: solicitar cotización a través de la
página Web (ddescuento del 15% a
lectores de dotNetManía)
¿Qué nos ofrece Visual Guard?
Visual Guard simplifica enormemente tareas como
las siguientes:
Gestionar los usuarios y roles de una aplicación y
sus posibilidades de acceso
Octavio Hernández es
Mentoring Team
Leader de Plain
Concepts, editor
técnico de
dotNetManía y tutor
de campusMVP.
Es MVP de C# desde
2004, MCSD y MCT.
El producto permite realizar la autenticación
de usuarios (creados especialmente o provenientes de un Directorio Activo o una base de datos
de SQL Server u Oracle) y su autorización para
el acceso a una aplicación o partes de ella en base
a un conjunto de roles y permisos creados por
nosotros y almacenados en una base de datos de
cualquiera de los tipos anteriores o en un fichero
encriptado. Toda esa información de seguridad se
almacenará en un repositorio que podrá o no compartirse entre diferentes aplicaciones. El formulario de autenticación puede ser personalizado
según nuestros deseos.
Permitir o impedir el acceso a aplicaciones o partes de ellas.
En base a los datos suministrados durante la
fase de autenticación, el motor de Visual Guard
autorizará o no el acceso del usuario a una aplicación o a partes específicas de ella, como menús o
formularios.
Filtrar y proteger los datos confidenciales
En dependencia de la identidad del usuario,
ciertos elementos de la aplicación que muestren
datos confidenciales podrán ser ocultados o hechos
de solo lectura para impedir su visualización y/o
modificación.
Personalizar la interfaz de usuario
También en función de la identidad del usuario, será posible (y muy fácil) modificar la interfaz de usuario de los formularios que componen
la aplicación, por ejemplo mostrando u ocultando botones, campos, pestañas de un cuaderno,
etc.
<< dnm.laboratorio.net
Figura 2. Diálogo de autenticación
estándar
Figura 1. Consola de administración
Parametrizar la lógica de negocio de la aplicación
¿Cómo funciona Visual Guard?
Visual Guard consta de dos componentes fundamentales:
• La Consola de administración de Visual Guard (figura 1), una herramienta para la edición visual de los
usuarios, mecanismos de autenticación a utilizar, roles,
permisos, acciones a llevar a cabo en casos de que un
Ensamblado
Contenido
Novalys.VisualGuard.Security
Las clases principales de Visual Guard. La referencia a este
ensamblado es obligatoria.
Novalys.VisualGuard.Security.File
Clases necesarias para acceder a un repositorio almacenado en
un fichero.
Novalys.VisualGuard.Security.Oracle
Clases necesarias para acceder a un repositorio almacenado en
una base de datos de Oracle (8i o superior).
Novalys.VisualGuard.Security.SQLServer
Clases necesarias para acceder a un repositorio almacenado en
una base de datos de SQL Server (2000 o superior).
Novalys.VisualGuard.Security.WebForm
Clases necesarias para integrar
Visual Guard en una aplicación o servicio ASP.NET.
Novalys.VisualGuard.Security.WinForm
Clases necesarias para integrar
Visual Guard en una aplicación Windows Forms.
Tabla 1. Ensamblados que componen el motor de Visual Guard
<<dotNetManía
usuario no tenga ciertos permisos, etc. La Consola
de administración permite actuar sobre un repositorio de seguridad, en el que se almacena toda esa información para una aplicación o grupo de aplicaciones
específico. Este repositorio podrá almacenarse en
una base de datos SQL Server u Oracle o en un fichero encriptado.
• El motor de ejecución de Visual Guard, un conjunto de ensamblados a los que harán referencia las
aplicaciones y que modificará el comportamiento
de éstas en función de la identidad del usuario actual
y de los permisos que tenga asignados en el repositorio de seguridad de la aplicación. Como parte del
motor se incluye un proveedor de membresía (membership), mediante el cual los desarrolladores podrán
gestionar programáticamente los usuarios y roles.
La tabla 1 muestra los ensamblados que componen
el motor.
Otra cosa que puede ser necesaria y que Visual
Guard hace muy sencilla es la parametrización de la
lógica de negocio en función de los usuarios y roles.
Por ejemplo, es común que un vendedor “corriente”
tenga fijado un importe máximo de pedido inferior al
de sus jefes. Visual Guard ajustará la regla de validación correspondiente en función del usuario actual.
53
<< dnm.laboratorio.net
El motor de ejecución de Visual
Guard modificará el comportamiento
de las aplicaciones en función de la
identidad del usuario
Figura 3. La aplicación de ejemplo, utilizada
por un administrador
visibles los clientes británicos, y no se permite al
usuario la inserción o borrado de clientes.
El proceso de integración
<<dotNetManía
Figura 4. La aplicación de ejemplo, utilizada por un
empleado de recursos humanos británico
54
En tiempo de ejecución, el motor de Visual
Guard:
1. Gestiona la autenticación del usuario. La figura 2 muestra el diálogo de autenticación estándar, utilizado en la aplicación de ejemplo que
acompaña al producto. Como hemos comentado anteriormente, usted puede suministrar su
propio diálogo, si lo prefiere.
2. Se conecta al repositorio y recupera los permisos del usuario.
3. Ajusta dinámicamente la aplicación en función
de esos permisos. Por ejemplo, cuando se abre
un formulario, el motor de Visual Guard oculta controles y filtra datos según sea necesario.
Las figuras 3 y 4 muestran la aplicación de ejemplo mientras está siendo utilizada por un administrador y un empleado del departamento de
Recursos humanos de la oficina del Reino Unido,
respectivamente. En el segundo caso, solo están
El proceso de integración del motor de Visual
Guard dentro de cualquier proyecto que estemos desarrollando constará típicamente de los siguientes pasos:
1. Agregar los ensamblados de Visual Guard al proyecto y activar la seguridad.
2. Implementar el formulario de autenticación de
Visual Guard (o definir uno propio).
3. Crear un repositorio de seguridad y registrar el
proyecto dentro de ese repositorio.
4. Los desarrolladores, utilizando la Consola, añaden al
repositorio los permisos asociados al proyecto.
5. El proyecto es compilado y desplegado.
6. Una vez desplegado el proyecto, el administrador:
a) Define roles y les asocia permisos de entre los
existentes en el repositorio.
b) Crea usuarios y los asocia a roles específicos.
Observe que no se requieren conocimientos o habilidades técnicas especiales para administrar la seguridad.
Conclusiones
A lo largo de este artículo hemos intentado mostrar las principales posibilidades que nos ofrece
Visual Guard para ayudarnos a crear aplicaciones
seguras y personalizables en función de la identidad del usuario que las utiliza en cada momento. Se
invita al usuario a descargar la versión de evaluación y probar las aplicaciones de ejemplo que se
incluyen con el producto.
Referencias
[ 1]
Sitio Web de Visual Guard: http://www.visual-guard.com
biblioteca.net
Silverlight 1.0 Unleashed
Adam Nathan
Editorial: Sams Publishing
Páginas: 272
Publicado: octubre de 2007
ISBN: 978-0672330070
Idioma: inglés
Ya hemos hablado en ocasiones anteriores del autor dentro de esta sección; la última,
a propósito de su “WPF Unleashed”, considerado uno de los mejores libros en su temática. Hay que añadir que Nathan es Senior Software Development Engineer en Microsoft Redmond y también el arquitecto jefe de Popfly, el primer producto construido directamente sobre Silverlight. No necesita, pues, más presentación en cuanto a su conocimiento del tema.
Esta es una obra que, abordando todo lo necesario para la construcción de páginas
en Silverlight, se limita a la versión actual en producción: la 1.0. No hay referencias a la
próxima versión (todavía en fase alfa). Pero la cobertura es excelente, los ejemplos sencillos y directos de utilizar, y los tips o trucos propios del SDK, de un valor excepcional.
Muchos problemas cotidianos que se presentan durante el trabajo con esta versión se
resuelven a través de estas ayudas. Hay mejores introducciones, no obstante, pero ésta es
absolutamente recomendable.
Silverlight 1.0
Devin Rader, Jason Beres, J. Ambrose Little y Grant Hinkson
Editorial: Wrox
Páginas: 288
Publicado: octubre de 2007
ISBN: 978-0470228401
Idioma: inglés
Lo ideal sería tener –al menos hasta que aparezcan otras obras en preparación– la
obra anterior junto a la que presentamos aquí. En esta ocasión, hay que resaltar dos aspectos que no son abordados –o no lo son con esta profundidad– por el libro de Nathan: la
introducción y explicación de la parte estructural y arquitectónica en la que se basa Silverlight, junto al uso correcto de las herramientas para desarrollar en esta versión y, especialmente, la parte de Silverlight 1.1 (que se llamará 2.0, cuando se produzca su aparición oficial).
novedades
Los ejemplos son muy explicativos de la funcionalidad ofrecida por el SDK, y no hay
parte de éste que no se encuentre citada en la obra. Hay, además, un capítulo interesante sobre el CLR y Silverlight 1.1 que sirve para vislumbrar las inmensas posibilidades que
ofrecerá la nueva versión, y otro dedicado a explicar un caso de ejemplo, muy ilustrativo
del abordaje de una aplicación.
Microsoft ASP.NET 3.5 Developer Reference
Dino Esposito. Editorial: Microsoft Press. Páginas: 992. Publicado: febrero de 2008. ISBN:
978-0735625273. Idioma: inglés.
Pro Silverlight 1.1
Matthew McDonald. Editorial: APress. Páginas: 400. Disponible: abril de 2008. ISBN: 9781590599495. Idioma: inglés.
TEXTO: MARINO POSADAS
comunidad.net
AndorraDotNet
<<dotNetManía
Grupo de usuarios .NET de Andorra
56
AndorraDotNet nace como el primer
grupo de usuarios de .NET en Andorra,
el pequeño país de los pirineos. La idea
empezó a formarse en mi cabeza durante
el MVP Summit realizado en Seattle en
2005, entre sesiones técnicas, barbacoas
y alguna que otra visita a la Company
Store. Allí, en medio de todo ese gentío
empecé a pensar en el gran espíritu de la
comunidad que flotaba por allí, y en que
lo realmente bonito de estos eventos es
el altísimo nivel de comunicación entre
la gente y la pasión que trasmiten todos
y cada uno de ellos.
Esta pasión por las ganas de aprender,
de enseñar, de poner lo mejor de cada
uno en hacer las cosas bien, de transmitir conocimientos… ¡Qué diablos!,
me dije, ¿por qué no iba a tenerla en
casa?, ¡al fin y al cabo frikis amantes del
desarrollo hay en todas partes!
Después de hablarlo con Pep Lluís
Baño, fundador de Spain.Net y por
aquel entonces compañero de viaje (y
de habitación) empecé a verlo más claro,
y gracias a su ayuda inicial y a la de otra
mucha gente, al final este proyecto se
ha hecho realidad: el próximo día 1 de febrero se
realizará el primer evento del grupo de usuarios,
en el que a petición popular hablaremos de SharePoint como plataforma de servicios para el desarrollador.
Desde entonces hasta aquí ha habido un largo
camino, ya que la creación de un grupo de usuarios tal vez no parezca gran cosa, pero os aseguro
que conlleva mucho trabajo. Primeramente debemos encontrar gente que tenga los mismos intereses y esté dispuesta a compartir el trabajo, hay que
definir unos estatutos, buscar patrocinadores y colaboradores, crear el sitio portal del Web del grupo,
visitar universidades y escuelas, y no hay que olvidarnos de la planificación de los eventos… Sin
embargo, cuando existen ganas e ilusión en tirar
un proyecto hacia adelante, no hay trabajo que
valga, y si por ende contamos con miembros de lujo
como Jorge Serrano (MVP ex-residente en el país),
Carlos Segura (MVP fundador del Navarra User
Group), el propio Pep Lluís Baño, o Miquel Viladrich (profesor en la universidad de Andorra), la
verdad es que todavía resulta mucho más sencillo.
Así pues, el objetivo de AndorraDotNet es el
de realizar eventos periódicamente, en los que los
<< dnm.comunidad.net
AndorraDotNet
•
•
•
•
•
•
miembros del grupo (y todo
el que quiera mientras no
tengamos problemas de
aforo) nos reuniremos para hablar de
lo que mueve nuestra pasión: el desarrollo de software y todo lo relacionado con él. Desde arquitectura
hasta metodologías de gestión de
proyectos, pasando por nuestros lenguajes favoritos de .NET Framework, innovaciones tecnológicas, y
ubicación: Andorra
fecha de fundación: octubre 2007
fundador: Lluís Franco
miembros: 20
página web: http://www.andorradotnet.com
email de contacto: [email protected]
cualquier cosa que se nos pase por la
cabeza.
Todo el mundo es bienvenido.
Tanto si eres un profesional consolidado como si todavía estás estudiando, da lo mismo que residas en el
país, en las cercanías, o simplemente
estés de paso porque has venido a
sacar brillo a los esquíes. ¡Lo realmente importante es que sientas esa
pasión!
Lluis Franco
Eventos de OnobaNET
El pasado 14 de diciembre, Bruno Capuano y Juan Luis Guerrero visitaron Huelva para un evento. Bruno presentó MS Robotics y Lego Mindstorms, y mostró las cosas que se pueden hacer con ellos. Por su parte,
Juan Luis Guerrero mostró algunas de las novedades que trae el nuevo
Visual Studio 2008. Este evento contó con gran afluencia de público (50
asistentes), entre los que destacaron dos pequeñines que vinieron a ver
cómo funcionaba el robot :-).
El 16 de enero de este nuevo año, nos visitó Eladio Rincón, del grupo
de usuarios GUSENET, quien dió una magnífica charla sobre
rendimiento de SQL Server 2008, junto con Miguel Rodríguez de
OnobaNET, que realizó varias demos de Inteligencia de Negocio en
MOSS (Form Server, Excel Services y KPI).
Ambos eventos acabaron con preguntas a los ponentes acerca de los
temas expuestos. Luego, para terminar los eventos, “unas tapitas” en el
bar de la amiga Elvira, mientras su dueña conversaba con los ponentes y algunos asistentes.
eventos.eventos.eventos.eventos.eventos
desván
Marino Posadas
Más allá de Windows Vista
<<dotNetManía
Stephen Sinofski, Windows Senior VicePresident ha anticipado recientemente algunas novedades sobre el sistema operativo que
seguirá a Vista. Inicialmente nombrado como
BlackComb y posteriormente como Vienna, parece que estas nomenclaturas vuelven
a un estado de pureza y se habla de Windows
7. Y se dice que no estará disponible hasta
2010 (aunque ha surgido últimamente alguna voz indicando la segunda mitad de 2009). Dispondrá de dos
versiones de procesador: 32 y 64 bits. Mientras tanto, los grandes
Service Pack para Vista serán Windows Vista Service Pack 1
(actualmente en beta pública) y un nuevo tipo de actualización
que se denomina Microsoft Desktop Optimization Pack, que es
más bien un mecanismo de optimización del sistema, configurable por el usuario.
58
Respecto al diseño y aspecto visual del
sistema, el éxito obtenido en Office 2007
ha movido a Microsoft a reclutar a Julie
Larsen-Green, una de las artífices principales del cambio de aspecto y modo operativo de la suite, para repensar –especialmente— “el modo en que a los usuarios les
gustaría utilizar el sistema”. Caben esperar
grandes cambios, a tenor de su labor para
la actual versión de Office. Pero, ¿habrá grandes cambios en
la arquitectura interna del sistema? Se dice que no. Que la
calidad y el rendimiento serán el objetivo primordial. Pero
también hay quien apunta ideas de primera mano salidas de
la propia casa central (o eso afirman): todas las aplicaciones
ejecutándose como no-Administrador, nueva estructura de
drivers gráficos (para evitar las caídas por esta vía, ya que la
queja por parte de Microsoft es que las compañías son muy
proclives a cuidar al máximo el rendimiento de sus drivers
gráficos, pero no su estabilidad), y la imposibilidad de que
cualquier servicio del sistema tenga la facultad de crear una
interfaz de usuario. Es llevar el concepto de ejecución en
máquina virtual hasta las últimas consecuencias en aras de la
seguridad. Otras características anunciadas son la posibilidad
de afinar la instalación para que cada fabricante o similar pueda personalizar el sistema según sus necesidades (Component
Delivery Platform), y StrongBox, mecanismo ideado para
minimizar el impacto que algunas aplicaciones tienen sobre
otras. De cara al usuario, Windows Live estará tan integrado con el sistema, que simplemente será como una extensión
natural de éste. Y es que Redmond se ha dado cuenta de una
gran verdad: si el usuario de una aplicación no se siente cómodo con ella, si su uso supone una pesadilla en lugar de un placer, o si tiene que leer largos manuales para empezar a ser
productivo, de poco sirve que la infraestructura y arquitectura sean excelentes. Al usuario no le interesa el código fuente, le interesa su propia experiencia (de usuario).
noticias.noticias.noticias
documentos en la red
Configuring Visual Studio to Debug .NET Framework
Source Code. Es un excelente artículo sobre cómo podemos cambiar la configuración del IDE de forma que podamos ver cómo se ejecuta el propio código fuente de las
librerías de .NET Framework. Algo más que una curiosidad, cuando encontremos algún bug que se resista. Ver el
blog de Shawn Burke (http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx), no es menos recomendable. (Gracias
a Daniel Seara por el enlace).
Visual Studio 2008 Learning Guide. ¿Quiere ponerse al
día en las novedades de VS 2008, y no tiene tiempo para una
formación adecuada?
Puede intentar descargar los documentos disponibles en WinDevelopment, bajo el epígrafe “Visual Studio 2008 Learning Guide” (http://searchwindevelopment.techtarget.com/generic/0,295582,sid8_gci1280711,00.html?track=NL-150&ad=
612250&asrc=EM_USC_2568652&uid=6264165). Comprendemos que no tenga muchas ganas de teclear todo ese
enlace. Así que quizá prefiera buscarlo en http://searchwindevelopment.techtarget.com.
sitios del mes
El blog de David Salgado. Trepidante. En constante cambio, como los service packs. Aparte de buenos y profundos comentarios sobre una de sus
especialidades (la depuración a bajo nivel),
veremos noticias, trucos, anuncios de eventos de desarrollo,
y hasta un diario-gadget muy “á-la-mode”. Disponible en
http://blogs.msdn.com/davidsalgado.
Developer Fusion. Un sitio excelente, ubicado en el Reino Unido, y con una cantidad ingente de información sobre desarrollo (no solo en .NET). Me gustaría recalcar un artículo sobre
Silverlight, escrito por un buen amigo (Dave Wheeler, del equipo de desarrollo del SDK de NewsReaders, en Redmond). Con
montones de código fuente y artículos sobre programación
(http://www.developerfusion.co.uk).
utilidades del mes
ClipX. Para los que –muchas veces- hemos echado de
menos utilidades extra asociadas al comportamiento del
Portapapeles de Windows. Ocupa más o menos 100K, es
gratis, y permite funcionalidades extendidas como hacer
búsquedas en Internet sobre el contenido del Portapapeles, o comandos para abrir una sesión nueva del navegador con la URL contenida en él. Descargable de
http://www.bluemars.org/clipx.
Microsoft TechDays
{The Evolution Show}
Y el 26 y 27 de febrero en Madrid
Palacio Municipal de Congresos
(Campo de las Naciones)
Porque tú eres nuestro verdadero protagonista, no puedes faltar.
Ven a
{The Evolution Show}, todo un acontecimiento y una experiencia inolvidable
donde te presentaremos las nuevas versiones de Windows Server 2008, Visual Studio 2008
y SQL Server 2008. Premier técnica, demos, laboratorios, Steve Ballmer en directo desde
Los Ángeles,... ¡No te lo puedes perder!
Regístrate ya en www.microsoft.es/lanzamiento2008
Mucho más que una evolución. Una revolución…
Con la colaboración de:

Documentos relacionados