Autenticación y autorización en - Tecnología, Tips y Programación

Anuncio
www.dotnetmania.com
nº 55 enero 2009 6,50 €
Visual Basic • C# • ASP.NET • ADO.NET • AJAX • Silverlight • .NET Framework
dotNetManía
dedicada a los profesionales de la plataforma .NET
Autenticación y autorización en
Servicios Web
entrevista
Michael Howard y
Adam Shostack
Senior Security Program Managers
Microsoft Corp.
SQL Server
Agregando inteligencia a mis aplicaciones mediante SQL Server Data Mining
ALManía
Personalizando nuestras builds
Isla VB
Visual Basic ¿lenguaje dinámico?
TodotNet@QA
Un vistazo a Entity Framework
Aplicación del patrón de diseño Acción. Definición de componentes en ASP.NET • HttpHandlers y HttpModules para
SharePoint 2007 • Silverlight 2.0 Toolkit. Controles, visualización de datos y mucho más (I)
editorial
dotNetManía
Dedicada a los profesionales de la plataforma .NET
Vol. III •Número 55 • Enero 2009
Precio: 6,50 €
Cumplimos 5 años
Editor
Paco Marín
([email protected])
Redactor jefe
Marino Posadas
([email protected])
Redacción
Dino Esposito, Guillermo 'Guille' Som, Luis
Fraile, Luis Miguel Blanco y Miguel Katrib
(Grupo Weboo)
Empresas colaboradoras
Alhambra-Eidos
Krasis
Plain Concepts
Raona
Solid Quality Mentors
Además colaboran en este número
Enric Forn, Francisco González, Gustavo
Vélez, Jeffrey Álvarez, Juan Luis Ceada y
Magda Teruel.
Diseño y maquetación
Silvia Gil (Letra Norte)
Atención al suscriptor
Pilar Pérez
([email protected])
Edición, suscripciones y publicidad
.netalia
c/ Robledal, 135
28522 - Rivas Vaciamadrid (Madrid)
www.dotnetmania.com
Tf. (34) 91 666 74 77
Fax (34) 91 499 13 64
Imprime
Gráficas MARTE
ISSN
1698-5451
Depósito Legal
M-3.075-2004
Bienvenido al número 55, de enero de
2009, de dotNetManía.
Con el ejemplar que tiene ahora en
sus manos, terminamos nuestro quinto
año de publicación. Estamos orgullosos
de esto, pero también somos conscientes de que la única forma de mantenerse —caso de que la haya— es seguir trabajando duro, manteniendo la tensión y
esforzándonos en dar lo mejor de nosotros mismos, en definitiva, con el mayor
respeto a los lectores y patrocinadores
de esta revista. Cada mes debemos
empezar de nuevo con la ilusión del primer número, pero con la experiencia de
estos cinco años.
En esta ocasión, hemos tenido la suerte de poder entrevistar a Michael
Howard y Adam Shostack, Senior Security Program Managers en Microsoft
Corp. Michael y Adam conversaron con
nosotros acerca de la seguridad del código que se desarrolla con las herramientas de Microsoft hoy en día y del que
desarrollaremos en el futuro también.
Jeffrey Álvarez Massón y Miguel
Katrib nos muestran las ventajas que el
uso del patrón de diseño Acción ofrece
para el desarrollo de componentes
ASP.NET en el artículo “Aplicación del
patrón de diseño Acción. Definición de
componentes en ASP.NET”.
Tenemos nuestra dosis de SharePoint con Gustavo Vélez, que en su
artículo “HttpHandlers y HttpModules para SharePoint 2007” describe las
posibilidades de los manejadores y
módulos HTTP, hasta el momento no
demasiado explotados por los desarrolladores. Aprovecho la ocasión para
recomendarle la revista online totalmente gratuita que Gustavo ha creado y que
publica junto con otras personas en
http://www.gavd.net/servers/compartimoss/compartimoss_main.aspx.
El artículo de portada de este mes,
“Autenticación y autorización en servicios Web con cabeceras y extensiones
SOAP”, de Juan Luis Ceada, nos muestra cómo interceptar las llamadas a nuestros servicios Web para tener control
sobre los accesos a ellos y mejorar no
solo la seguridad, sino también la calidad del servicio. Así podremos decidir
quién, a dónde y cuántas veces puede
acceder a nuestros servicios.
Marino Posadas complementa la
información publicada en su libro “Programación en Silverlight 2.0” con su
artículo “Silverlight 2.0 Toolkit. Controles, visualización de datos y mucho
más (I)”, primero de una serie de dos,
que describe el nuevo paquete de herramientas y controles que complementa a
las ya incluidas en el SDK del producto, y que se distribuyen bajo licencia
pública de Microsoft (Ms-PL), código
fuente incluido, en CodePlex.
Además, encontrará nuestras secciones habituales SQL Server, ALManía e
Isla VB. Espero que todo esto sea de su
agrado.
Paco Marín
sumario 55
Entrevista a Michael Howard y Adam Shostack
10-12
Michael Howard y Adam Shostack, reconocidos expertos en temas relacionados con la seguridad,
pasaron por Barcelona con motivo del reciente Tech-Ed 2008, que tuvo lugar a mediados de
noviembre. Además de impartir algunas sesiones, tuvieron un rato para entrevistarse con
dotNetManía y hablarnos sobre ese aspecto tan importante para el software de hoy.
Aplicación del patrón de diseño Acción. Definición de componentes en ASP.NET
14-19
En este artículo se propone un nuevo enfoque para la representación de acciones como componentes
en aplicaciones visuales, y se muestran las múltiples ventajas que este enfoque proporciona a través
de su aplicación práctica al desarrollo de formularios Web ASP.NET.
HttpHandlers y HttpModules para SharePoint 2007
20-24
Este artículo describe las posibilidades que ofrecen los manejadores HTTP (HttpHandlers) y los
módulos HTTP (HttpModules) de ASP.NET, y cómo pueden utilizarse estos mecanismos para
implementar funcionalidades avanzadas en sitios de SharePoint 2007.
Autenticación y autorización en servicios Web con cabeceras y extensiones SOAP
26-35
En ocasiones es necesario tener un control exhaustivo de los accesos que se producen a nuestros
servicios Web (quién accede, a dónde y cuántas veces), tanto por seguridad como para mantener la
calidad del servicio. En este artículo veremos cómo podemos cumplir estos requisitos interceptando las
llamadas realizadas por los clientes a nuestra plataforma de servicios Web.
Silverlight 2.0 Toolkit. Controles, visualización de datos y mucho más (I)
36-39
En paralelo con la presentación de la versión final de Silverlight 2.0, se anunciaba en las webs
“oficiales” de la plataforma la intención de mejorar el desarrollo mediante la publicación paulatina
de nuevos controles y herramientas que potencien las posibilidades de creación de aplicaciones RIA
con Silverlight, al tiempo que se anticipaban algunas características de la versión 3.0, que según
Scott Guthrie estará disponible a finales de 2009. Vamos a revisar aquí algunas de las posibilidades
que ofrece el último paquete de herramientas, publicado a primeros del pasado mes de diciembre.
Agregando inteligencia a mis aplicaciones mediante SQL Server Data Mining
40-43
La minería de datos se puede utilizar para analizar información y realizar predicciones. En este
artículo voy a ilustrar el uso de la minería de datos en una aplicación Web. Vamos a tomar los datos
de venta de un portal Web y cierta información de nuestros clientes para analizar qué productos
ofrecer a determinados perfiles de clientes, realizar campañas publicitarias u ofrecer productos que
sean comprados conjuntamente cuando un cliente agrega un producto a la cesta de la compra.
Personalizando nuestras builds
44-48
En muchas ocasiones, en el momento en que generamos la versión de nuestra aplicación nos dejamos
el último ensamblado añadido, la modificación del fichero de configuración, o los PDB generados se
encuentran en modo Debug. Team Foundation Build nos ayuda a simplificar estas tareas,
mejorando el versionado de nuestros proyectos.
Visual Basic ¿lenguaje dinámico?
50-53
En la próxima versión de .NET Framework (la 4.0) se incluirá lo que se conoce como DLR
(Dynamic Language Runtime), que viene a ser el motor de ejecución de los lenguajes dinámicos de
.NET. De esa forma, se permitirá al CLR (y por extensión a los lenguajes como VB y C#) el acceso
de forma dinámica a los miembros de los objetos que haya en memoria, algo parecido a lo que
siempre se ha conocido como late binding... o casi...
dnm.todotnet.qa
54-56
Un vistazo a Entity Framework
dnm.biblioteca
57
ADO.NET Entity Framework. Aplicaciones y servicios centrados en datos
Application Architecture Guide 2.0: Designing Applications on the .NET Platform
dnm.desvan
58
<<dotNetManía
noticias noticias noticias noticias
noticias
6
Microsoft da pasos concretos hacia
la interoperabilidad
La empresa promueve la transparencia publicando las notas de implementación
de ODF y Open XML
Para promover una mayor interoperabilidad entre las aplicaciones de productividad, Microsoft publicó este 16 de
diciembre la documentación que detalla su implementación
del soporte para OASIS Open Document Format (ODF)
versión 1.1 en Microsoft Office 2007 SP2, actualmente en
fase beta y prevista para su liberación el próximo año. Notas
similares relativas a la implementación de Open XML (Ecma
376 Edición 1) en Office aparecerán en las próximas semanas. Esta información se seguirá actualizando en la medida
en que los productos cambien a lo largo del tiempo y a partir de las sugerencias de los usuarios.
Estas notas de implementación ofrecen una guía completa de cómo Microsoft está implementando ODF y Open
XML dentro de la suite Office. Las notas, disponibles gratuitamente en el sitio Web de la Document Interoperability Initiative (DII), en http://www.documentinteropinitiative.org, serán de suma utilidad a los desarrolladores que busquen mejorar la interoperabilidad de sus soluciones con los
productos de Microsoft, e igualmente constituirán un interesante recurso de aprendizaje. Las notas contienen:
•Detalles sobre decisiones de implementación. Al
implementar un estándar, el implementador puede encontrar el texto ambiguo o más permisivo de lo que sería
apropiado para una implementación particular. En tales
casos, el implementador debe tomar la decisión que mejor
satisfaga sus necesidades. Este tipo de información permite a los desarrolladores ver qué dirección está siguiendo un fabricante y tomar decisiones informadas sobre sus
propios esfuerzos de interoperabilidad.
•Detalles sobre datos adicionales incorporados a los
ficheros. Los estándares de formatos de ficheros típicamente permiten almacenar en los ficheros información
adicional específica de las aplicaciones (por ejemplo, ciertas personalizaciones). Suministrando esta información,
los fabricantes permiten a los desarrolladores interpretar correctamente esos datos adicionales.
•Detalles sobre las desviaciones en la implementación. En cualquier aplicación se pueden presentar casos
en que un implementador no puede seguir exactamente
el estándar por una u otra razón. En tales casos, es importante que los fabricantes documenten exhaustivamente
su enfoque, de manera que otros fabricantes puedan tomar
decisiones informadas sobre cómo enfocarán su implementación.
La estandarización es un primer paso importante hacia
la interoperabilidad, pero se necesita más trabajo adicional
por parte de los fabricantes para alcanzar ese objetivo:
•Seguimiento compartido de la evolución de los estándares por parte de los cuerpos correspondientes. Microsoft tiene el compromiso de participar activamente en la
evolución de los estándares ODF, Open XML, XPS y
PDF; ha contribuido a ODF en OASIS y colabora en el
mantenimiento de Open XML en ISO/IEC.
•Transparencia. Los fabricantes deben ser transparentes
al implementar estándares en sus propios productos. Publicando estas notas de implementación, Microsoft está ayudando a otros desarrolladores y fabricantes a tomar decisiones informadas a la hora de crear sus productos.
•Colaboración. Los fabricantes deben colaborar con otros
fabricantes para identificar y resolver las "colisiones del
mundo real" que surjan entre implementaciones, y crear
herramientas y soluciones para mejorar la interoperabilidad a lo largo del tiempo. Microsoft llevará a cabo alrededor del mundo sesiones de trabajo de DII y otras actividades para promover la colaboración entre fabricantes
y, en definitiva, el intercambio efectivo de datos entre
implementaciones de estándares de formatos de datos.
Concurso “Inspire al mundo con solo 10K”
Con el objetivo último de promover el desarrollo de aplicaciones basadas en las últimas
tecnologías de interfaz de
usuario de Microsoft, los
organizadores del conocido
evento MIX han creado un concurso bajo el lema “Inspire al mundo con solo 10K”. Se trata de desarrollar
una aplicación Silverlight o WPF para navegador cuyo
código fuente y recursos embebidos no sobrepasen en
total los 10 KB. El ganador obtendrá un pase gratuito
para el evento MIX ’09 que se celebrará en Las Vegas
entre el 18 y el 20 de marzo, además de tres noches de
hotel y una tarjeta Visa con 1.500 dólares.
Para más información y las bases del concurso, visite http://2009.visitmix.com/MIXtify/TenKGallery.aspx.
<< dnm.directo.noticias
Se libera conjuntamente con módulos destinados a
simplificar los despliegues RFID
Hace unos días, Microsoft liberó una
beta pública de BizTalk Server 2009,
conjuntamente con módulos destinados a simplificar los despliegues RFID.
Se trata de la primera versión pública
para pruebas de la plataforma de integración basada en Arquitecturas orientadas a servicios (SOA) de Microsoft.
Se espera que la versión definitiva sea
lanzada durante la primera mitad de
2009, según Burley Kawasaki, Director de la División de Sistemas Conectados de Microsoft.
"Es una versión completa en lo que
respecta a características", dijo Kawasaki. "Estamos buscando recibir mucho más
feedback sobre el producto como parte de
su terminación". La beta está disponible
para su descarga para los clientes actuales de BizTalk suscritos al programa Software Assurance.
BizTalk Server 2009 soporta los
productos más recientes de la plataforma Microsoft, principalmente la versión de Windows Communications
Foundation (WCF) incluida en .NET
Framework 3.5 SP1, además del soporte completo para Visual Studio 2008
SP1 y las ediciones más recientes de
SQL Server y Windows Server.
Además, soporta nativamente HyperV y ofrece clustering mejorado, mejoras en la tolerancia a fallos y adaptadores e interfaces de integración con host
adicionales. Igualmente se brinda
soporte para un nuevo registro basado
en las especificaciones de UDDI 3.0.
Para las organizaciones dedicadas al
desarrollo, BizTalk Server 2009 ofrece
nuevas posibilidades para la gestión del
Ciclo de vida de las aplicaciones mediante el soporte para Team Foundation Server, que permitirá a los equipos de programadores aprovechar la gestión de
código, seguimiento de fallos e integración de builds que éste ofrece. Los desarrolladores que lleven a cabos desarrollos
a medida basados en .NET podrán
conectarse a BizTalk y mapear cualquiera de los artefactos que BizTalk gestiona
en sus aplicaciones, como si de código
fuente se tratara.
Como parte de la versión liberada
hoy, Microsoft también ha liberado BizTalk RFID Standards Pack y RFID
Mobile. El primero es un módulo de servidor de BizTalk que soporta los principales estándares RFID, incluyendo Rag
Data Translation (TDT) y Low Level
Reader Protocol (LLRP). El segundo
funciona bajo Windows Mobile y dispositivos basados en Windows CE. RFID
Mobile ofrece una API común para todos
los dispositivos que ejecuten Microsoft
.NET Compact Framework y para la gestión remota de esos dispositivos.
Finalmente, Microsoft ha liberado
también una CTP de la versión actualizada de Enterprise Service Bus Guidance 2.0, que incluye nueva documentación y prácticas recomendadas para el
desarrollo de aplicaciones basadas en
SOA. "Estamos aprovechando algunas de
las nuevas posibilidades de Visual Studio
y añadiendo nuevas herramientas visuales que permitan definir y actualizar topologías de bus de servicios dentro de Visual
Studio", dijo Kawasaki. También ha
entrado en funcionamiento un nuevo
portal Web "que permite a los desarrolladores agregar publicadores o suscriptores al bus sin necesidad alguna de desarrollo personalizado. Es un modelo de
autoservicio".
Disponible actualización para
.NET 3.5 SP1
El pasado día 20 fue puesta a disposición del público una actualización
para .NET Framework 3.5 SP1. Esta
actualización corrige problemas
detectados en .NET 2.0 SP2, .NET
3.0 SP2 y .NET 3.5 SP1 desde su
aparición. Puede descargar e instalar
los paquetes correspondientes
(específicos para las distintas combinaciones de procesador y sistema operativo) desde http://support.microsoft.com/kb/959209.
Nuevo portal sobre capacitación
tecnológica de Alhambra-Eidos
Como parte de la línea de continuo
reforzamiento de su área de Formación,
Alhambra Eidos pone en marcha su
nuevo portal temático sobre capacitación tecnológica en las líneas tecnológicas que son de su especialidad: desarrollo de software, sistemas avanzados,
comunicaciones y telefonía, así como
sobre los distintos aspectos de seguridad comunes a todas ellas.
El acceso a dicho portal puede realizarse a través de www.formaciontic.com.
En él se podrá encontrar datos relativos a la oferta de formación de la compañía, información sobre novedades
tecnológicas y anuncios de interés para
aquellos que deseen mantener al día sus
capacidades técnicas.
Entre las primeras informaciones
relevantes que pueden consultarse se
encuentran las relativas a los nuevos
cursos y seminarios de alta especialización sobre desarrollo seguro, experiencia de usuario, Visual Studio 2008,
virtualización, etc. Los interesados también encontrarán allí todo lo relativo al
plan de formación subvencionada para
partners de Microsoft, ya que Alhambra Eidos ha sido una de las compañías
seleccionadas para impartir dicho plan
durante el curso 2008-2009.
<<dotNetManía
Microsoft libera primera beta
de BizTalk Server 2009
7
<< dnm.directo.noticias
Disponible SP3 de SQL Server 2005
Desde el pasado 16 de diciembre está
disponible el Service Pack 3 (SP3) de
SQL Server 2005, así como la Actualización acumulativa (Cumulative
Update) 11 para SQL Server 2005
SP2. Según la compañía, el SP3 incluye mejoras en el motor de bases de
datos, así como en los servicios de
replicación, Notification Services y
Reporting Services; adicionalmente,
contiene todas las actualizaciones de
seguridad y corrección de errores aparecidas anteriormente. Para aquellos
clientes que opten por no aprovechar
las nuevas posibilidades, la Actualización acumulativa contiene únicamente los hot fixes.
La versión más general del SP3 de
SQL Server 2005, aplicable a las ediciones Enterprise, Developer, Standard
y Workgroup, puede descargarse desde: http://www.microsoft.com/downloads/details.aspx?FamilyID=ae7387c3348c-4faa-8ae5-949fdfbe59c4.
Por otra parte, SQL Server 2005
SP3 Express está disponible aquí:
http://www.microsoft.com/downloads/detai
ls.aspx?familyid=3181842A-4090-4431ACDD-9A1C832E65A6.
Y SQL Server 2005 SP3 Express
with Advanced Services aquí:
http://www.microsoft.com/downloads/detai
ls.aspx?familyid=B448B0D0-EE7948F6-B50A-7C4F028C2E3D.
Al mismo tiempo, Microsoft ha
liberado versiones actualizadas al nivel
SP3 de las extensiones opcionales que
forman parte del Feature Pack para
SQL Server 2005. Puede descargar
esas extensiones aquí: http://www.microsoft.com/downloads/details.aspx?FamilyID=536fd7d5-013f-49bc-9fc777dede4bb075.
<<dotNetManía
Microsoft libera Oxite para los
desarrolladores
8
A principios
de diciembre,
el equipo que
se encarga de
los sitios para
desarrolladores Channel 8, 9 y 10
liberó el motor de blogs y gestión de
contenidos conocido como Oxite, que
puede obtenerse en el sitio de CodePlex http://www.codeplex.com/oxite. Oxite fue desarrollado originalmente para
el sitio Web del evento MIX
(http://www.visitmix.com) y se apoya,
como cabría esperar, en ASP.NET
MVC y SQL Server. Esta herramienta viene a suplir, según sus creadores,
la ausencia hasta el momento de ejemplos de gran calado basados en
ASP.NET MVC, y se suministra con
código fuente bajo el modelo de licencia Ms-PL, ofreciendo así a los desa-
rrolladores el derecho a incorporar
Oxite en sus propios productos.
El proyecto, deliberadamente, no
está orientado a usuarios finales, sino
a desarrolladores. Aunque Oxite ofrece todas las características que un sistema de blogs debe soportar (feeds RSS,
moderación de comentarios, pingbacks,
etc.) carece de las características de instalación y configuración sencillas que
requiere el software para usuarios finales, utilizando en vez de eso Visual Studio Web Developer Express para esas
tareas. La idea de Microsoft es que los
desarrolladores se basen en Oxite para
crear sus propias aplicaciones de blogs
o CMS. Se trata, sin embargo, de un
proyecto de la comunidad, por lo que
si ésta lo convierte en un producto más
orientado a los consumidores, Microsoft no interferirá.
Liberado IronPython 2.0
A principios de diciembre, Jason
Zander anunció la disponibilidad de
IronPython 2.0, una implementación
del lenguaje Python diseñada para
ejecutarse sobre la plataforma .NET,
poniendo todas las librerías de .NET
a disposición de los programadores
Python y manteniendo al mismo
tiempo compatibilidad total con la
versión estándar del lenguaje.
La novedad esencial incorporada
en esta versión es que IronPython
funciona ahora sobre el Dynamic
Language Runtime (DLR), un motor
de ejecución genérico para lenguajes
dinámicos que se ejecuta sobre el
CLR y hace posible la interoperabilidad de múltiples lenguajes dinámicos a nivel del sistema de tipos.
Para más información y descargas (incluyendo el código fuente), visite http://www.codeplex.com/IronPython.
Presentada Galería de diseños
de ASP.NET MVC
Hace unos días, Microsoft publicó
una nueva galería de diseños para
aplicaciones basadas en la arquitectura ASP.NET Model-ViewController. Esta galería aloja plantillas de diseños de sitios Web que
el usuario puede descargar y utilizar en sus desarrollos. Cada plantilla de diseño incluye un fichero
Site.master , una hoja de estilos
CSS y, opcionalmente, un conjunto de recursos y código de
soporte.
Cualquiera puede “subir”
nuevos diseños a la galería, que
funciona bajo licencia bajo licencia Creative Commons. Visítela
en http://www.asp.net/mvc/gallery/
default.aspx.
entrevista
Magda Teruel y
Luis Fraile
entrevista a
Michael Howard y Adam Shostack
Senior Security Program Managers en Microsoft Corp.
Magda Teruel
es Team Leader de
Raona. Magda es
MCPD Windows
Developer.
http://www.magda.es.
Luis Fraile es MVP de
Team System y colabora activamente en
MAD.NUG (Grupo
de usuarios de .NET
de Madrid). Actualmente es director
técnico en Multidomo Networks. Puede consultar su
blog en
www.lfraile.net.
Michael Howard y Adam Shostack,
reconocidos expertos en temas relacionados con la seguridad, pasaron
por Barcelona con motivo del
reciente Tech-Ed 2008, que tuvo
lugar a mediados de noviembre.Además de impartir algunas sesiones,
tuvieron un rato para entrevistarse
con dotNetManía y hablarnos sobre
ese aspecto tan importante para el
software de hoy.
¿Qué opináis del panorama actual del software
que se hace actualmente? ¿Es suficientemente
seguro?
Michael Howard: En lo que respecta a Microsoft, y con la incorporación de SDL (Secure Development Lifecycle), sí. A través de SDL, tenemos
desde 2004 procesos estrictos de seguridad, para
todos y cada uno de los productos expuestos a Internet o bien productos destinados a empresas. De
todas maneras, ahora es más fácil aplicar prácticas
de seguridad y privacidad a nuevos productos porque no hay que preocuparse de dar un soporte heredado. En mi opinión, y respondiendo a vuestra pregunta, los nuevos productos de Microsoft son
mucho más seguros que los antiguos.
¿Y a nivel de la industria?
Michael: La industria tiene un gran
camino por recorrer. Hoy en día el
foco de ataques está en los productos
de terceros, y estos ataques provocan
grandes pérdidas a las empresas. Para
ayudar en esto, estamos externalizando nuestro modelo de automatización.
SDL nos ha servido a nosotros en
nuestros productos (SQL Server, Office, Windows), por lo que lo ofrecemos
a la industria como herramienta para
que sus productos sean también más
seguros.
En cuanto a los productos de Microsoft que requieren desarrollo por
parte de los partners (BizTalk, SharePoint), ¿cuál es la estrategia?
Michael: La postura es clara: Microsoft y Bill Gates nos dicen “Lo haremos, no importa cuánto cueste”, pero
no sabremos lo que harán los partners.
Para ponérselo más fácil, externalizamos nuestras buenas prácticas, recomendaciones y las lecciones que hemos
aprendido. Y además les damos una
herramienta para hacerlo.
Recientemente se está haciendo
mucho hincapié en campos como la
UX. ¿No estamos olvidándonos de
la seguridad?
Adam Shostack: No. Estamos
empezando a aprender todos. Antes, la
seguridad era cosa de especialistas solamente. Obviamente, la experiencia de
usuario es importante, si la gente no
quiere usar nuestro software, tenemos
un problema. Pero poco a poco la seguridad (en unos dos años) empezará a
tener un papel relevante, y se hablará
de seguridad como se habla ahora de
interfaces de usuario.
¿Y qué está haciendo Microsoft para
popularizar la seguridad?
Michael: Ciertamente, hoy por
hoy la seguridad es una materia de
expertos, pero no debería serlo, tiene
que formar parte del proceso. Ahora
que subimos a la nube, y todo el mundo pone su software al alcance de
todos, es importante introducir la
seguridad como parte importante de
la metodología.
¿Qué hay del software en la nube?
Sin duda, lanza nuevos retos en
cuanto a seguridad.
Michael: Sí, son numerosos y distintos los retos que, por ejemplo, Windows Azure debe afrontar respecto a
Windows 7. Cada uno de ellos ha pasado por SDL, pero tenemos requisitos
específicos confeccionados para cada
producto, así como elementos comunes como el modelado de amenazas
(threat modeling), aplicables tanto a
Windows Azure como a Windows 7.
¿Y hay algo en concreto que haya
recibido una especial atención?
Adam: Sí, sin duda. Desde 2006, SDL
ha incluido requerimientos específicos de
seguridad y privacidad para los servicios
online. De hecho, los requerimientos de
seguridad de SDL comprenden y se
expanden a lo largo de múltiples fases del
desarrollo, y están diseñados para mitigar problemas comunes de las aplicaciones Web, como por ejemplo la inyección
de SQL o las vulnerabilidades XSS.
Michael: También el modelado de
amenazas se considera absolutamente
crítico en tecnologías como Windows
Azure y Live Mesh.
Ahora con VS2010 tenemos nuevas
herramientas de testing, como
Camano, que nos facilitan las tareas relacionadas con las pruebas
(fallos no reproducibles, etc.). ¿Se
está pensando en herramientas que
permitan realizar pruebas de seguridad relacionadas con la inyección
de SQL u otros ataques?
Michael: No, de momento solo se
dispone de herramientas de terceros. Las
pruebas son importantes, pero son solo
una parte de la solución. Hemos hecho
grandes progresos para construir algún
tipo de herramienta de pruebas de aspectos de seguridad, como fuzz testing (un
tipo de prueba que consiste en proveer
el sistema con datos aleatorios), y hemos
publicado código fuente para que los
desarrolladores puedan generar este tipo
de pruebas. Algunas partes del testeo de
seguridad pueden ser automatizadas,
pero hoy en día el estado del arte es todavía muy inmaduro.
Hay mucho movimiento respecto a
ALM (metodologías, buenas prácticas, etc.). ¿Cómo veis la integración
de SDL en este contexto?
Michael: Es completamente necesario que los fabricantes de software traten
las amenazas de seguridad y privacidad
convenientemente. Construir y preservar una mayor confianza en el mundo de
la informática significa que todos los fabricantes de software deben incorporar
requisitos de seguridad y privacidad en
sus productos para mitigar las amenazas.
Adam: Para la industria del software, las buenas prácticas y la formación
ayudan, pero la clave para mejorar la
seguridad y la privacidad es implementar procesos repetibles que aporten
avances medibles. Se necesitan procesos así para minimizar el número de vulnerabilidades de seguridad en diseño,
código y documentación, y para detectar y eliminar esas vulnerabilidades tan
temprano en el ciclo de vida como sea
posible. Y la necesidad es mayor para
el software de empresa o consumo que
procesa datos recibidos de Internet,
para controlar sistemas críticos con peligro de ser atacados o para procesar
información personal identificable.
Michael: En Microsoft, es muy
importante que añadamos herramientas
de seguridad y prácticas a los métodos
actuales de desarrollo, y éste es el foco de
nuestro grupo. Pero todavía estamos en
un proceso temprano, y necesitamos
invertir más tiempo y esfuerzo.
Falta madurez en el proceso,
entonces.
Adam: Mejorar la seguridad de las
aplicaciones implica muchos componentes, desde comprender las amenazas,
requerimientos de diseño, herramientas
de desarrollo, herramientas de pruebas
y reducir la superficie de ataque. No hay
una fórmula mágica. Para cumplir con
todos estos requisitos, Microsoft forma
a todos sus desarrolladores, testers, y program managers en el desarrollo de código más seguro, y siempre trata de mantener el número de vulnerabilidades de
seguridad al mínimo a través del proceso de SDL.
<<dotNetManía
<< dnm.directo.entrevista
11
<< dnm.directo.entrevista
Michael Howard
<<dotNetManía
Michael: Cuando preguntan cuántos expertos en seguridad tenemos en
Microsoft, la respuesta es 6.500. Es
decir, cada ingeniero posee los conocimientos y habilidades necesarios para
la seguridad, y esto va en aumento: cada
vez nuestro conocimiento es mayor.
Adam: Y aunque cada vez sabemos
más, es importante poder prescindir del
rol de experto en seguridad, y que cada
ingeniero sea capaz de tener una madurez mínima en cuanto a seguridad.
¿Entonces vamos a integrar SDL
con el resto de herramientas de
desarrollo?
Michael: De momento no, quién
sabe si en un futuro… Por ahora, y como
primer paso, vamos a proporcionar herramientas cómodas que faciliten la integración de la seguridad. Para ello hemos
creado la herramienta Threat Modeling
Tool (http://msdn.microsoft.com/enus/security/dd206731.aspx).
12
Siempre está cuestionada la seguridad de los productos de Microsoft.
Como parte del equipo de seguridad, ¿cuál es vuestra percepción?
Michael: ¡Estoy de acuerdo! Hemos
hecho increíbles progresos en los últimos años, y ahora estamos compartiendo nuestra experiencia para que
todo el mundo pueda aplicar nuestras
prácticas. Si se mira una gráfica temporal, el número de vulnerabilidades va
disminuyendo sustancialmente en cada
versión.
¿Entonces en unos años no habrá
vulnerabilidades?
(risas) Michael: Para ser honestos, la
cota de cero vulnerabilidades es inalcanzable. Pero la tendencia es a la baja, sin
duda. Por ejemplo, las vulnerabilidades
de red están ahí, y están para todos los
sistemas, pero hemos conseguido transformarlas de críticas a solamente importantes. SDL pretende reducir el número
de vulnerabilidades en nuestro software,
y está demostrado que introducir la seguridad y la privacidad en el código desde
los inicios nos ha permitido mejorar notablemente nuestro software. Es algo de lo
que estamos muy orgullosos.
Adam Shostack
Al menos, hay que agradecer que el
tiempo de reacción sea corto.
Michael: Sí, aunque hay que mirar
la foto completa. Es muy fácil detectar
un bug y alarmarse.
Siempre hay el dedo que señala.
Adam: Sí, y queremos evitar los
dedos acusadores. En Microsoft se ha
apostado por hacer una inversión real
en seguridad. De hecho, la gran mayoría de los anuncios recientes están
orientados a informar de que se presta
gran atención a resolver los problemas
de seguridad.
Para finalizar, habladnos del futuro
de SDL.
Michael: Últimamente me preguntan esto a menudo. Yo soy un eterno
optimista. Y esto es crítico cuando trabajas en seguridad para Microsoft (risas).
El último informe de Security Intelligence (http://www.microsoft.com/security/portal/sir.aspx) indica que hay que
dar un paso más, que la industria debe
cambiar su forma de pensar. Cada vez
lo hacemos mejor, sacamos más y más
versiones y aunque no son perfectas, son
cada vez más buenas. Si me hubieran
preguntado hace cinco años, no hubiera pensado que íbamos a hacer el progreso que hemos hecho, y creo que vendrán todavía más mejoras en los próximos cinco años.
¿Hacia dónde va la tendencia?
Michael: Vamos a ver un mayor
movimiento destinado a proveer más
soporte específico para la Web. Ya
hemos hecho mucho con respecto a
esto, pero es un panorama bastante
incierto, y vamos a poner más recursos en esta área. También van a aparecer muchas más herramientas. Y si
tuviera que desear una sola cosa, me
encantaría ver la seguridad como parte habitual de la entrega de software
en todos los proveedores. En esta misma línea, me gustaría ver que fuera de
Microsoft los equipos empiezan a
implementar SDL en sus organizaciones. Con los ataques dirigiéndose hacia
la capa de aplicación, es incluso más
crítico que los desarrolladores de software protejan a sus clientes embebiendo seguridad y privacidad en sus
productos.
Hablando con clientes y partners,
hay un interés bastante significativo en
adoptar SDL. Algunas compañías ya
han implementado procesos alineados
con los de SDL, y con nuestro esfuerzo para compartir nuestras herramientas con la industria, confío en que cada
vez más se irán añadiendo.
plataforma.net
Jeffrey Álvarez Massón
Miguel Katrib
Aplicación del patrón de diseño Acción
Definición de componentes en ASP.NET
En este artículo se propone un nuevo enfoque para la representación
de acciones como componentes en aplicaciones visuales, y se muestran
las múltiples ventajas que este enfoque proporciona a través de su aplicación práctica al desarrollo de formularios Web ASP.NET.
Reducir al mínimo el código fuente
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 redactor de
dotNetManía y asesor de
la empresa DATYS Tecnología y Sistemas.
Jeffrey Álvarez Massón es
estudiante de la Maestría
en Ciencia de la Computación de la Universidad de la
Habana y colaborador del
grupo WEBOO. Es desarrollador .NET de la
empresa DATYS Tecnología y Sistemas.
Hasta el momento, las tecnologías de componentes
se han dirigido a la implementación de funcionalidades generales que no dependen de las reglas de
un negocio en particular. Una vez que el programador entiende cómo utilizar un componente, establece un “contrato” con él y debe ser capaz de adaptarlo a sus necesidades propias. Este artículo se centra en el desarrollo de un tipo de componentes para
ASP.NET que interactúan con otros ya existentes
para darles un significado semántico. Esto se hace a
partir del patrón de diseño Acción o Comando.
El primer ejemplo en el que se utiliza el patrón
de diseño Comando (Command), también común-
mente llamado Acción (Action), apareció en un
artículo de Lieberman en 1985. MacApp, ET++,
InterViews y Unidraw definen clases que siguen
este patrón; para más detalles, ver [1]. Chris Lasater explica el patrón y ofrece una implementación
en C# [2], y Alex Homer [3] lo usa en ASP.NET,
aunque no desde el enfoque de componentes.
Este patrón (figura 1) consiste en encapsular
como un objeto la solicitud de ejecutar cierta funcionalidad, permitiendo parametrizar a los clientes con peticiones diferentes, poner en cola las peticiones y soportar operaciones de deshacer [1]. La
principal utilidad de este patrón consiste en que
muchas veces es necesario realizar una operación
cuya implementación, invocador y receptor pue-
Figura 1: Diagrama del patrón Acción o Comando. Tomado de [1].
<< dnm.plataforma.net
Acciones contra
manejadores de eventos
Teniendo en cuenta este patrón y las ventajas que ofrece para el desarrollo de
componentes la tecnología ASP.NET
[4], en el presente trabajo se considerará
la implementación de una acción como
un componente visual que tendrá asociado una funcionalidad específica (una
petición) cuya ejecución se desembocará
a través de un evento. Por ejemplo: en
una página Web, se desea hacer una pregunta de sí o no al usuario a través de
que éste haga clic en un determinado
botón. Si el usuario responde sí, se le
redirecciona a otra página. Si la respuesta
es no, permanece en la página actual.
Una implementación típica incluiría una
función script en la página Web y una
invocación de la función. Si tenemos que
hacer muchas preguntas de esta naturaleza, habrá que incluir la función, modificar parámetros y adicionar manejadores de eventos cada vez. Sin embargo, si
se cuenta con un control de ASP.NET
que se encargue de ello mediante la
generación automática de JavaScript en
el cliente, previa configuración de propiedades, se acelera considerablemente
el trabajo.
La acción no debe considerarse un
control de usuario (user control). Su objetivo no es personalizar una interfaz de
usuario, sino asociar operaciones a los
eventos de controles que ya tienen una
interfaz definida; se deja a cargo del
programador de la acción definir a qué
evento(s) se asociará la ejecución de la
acción; por ejemplo, al evento Click de
algún botón.
El proceso de adicionar una acción
en el diseñador Web de Visual Studio
o de cualquier otro ambiente de desarrollo debe ser el siguiente:
1. Se busca en las acciones existentes
en las bibliotecas de acciones para
comprobar si existe alguna con la
funcionalidad deseada. En caso afirmativo, la acción encontrada se
arrastra del cuadro de herramientas
hacia el área de diseño donde se
encuentran los demás componentes.
2. Se establecen —siempre en tiempo
de diseño— las propiedades de la
acción necesarias para que ésta funcione correctamente.
3. Se garantiza que la acción sea ejecutada en algún evento de la aplicación
(inicio de sesión, ocurrencia de un
error), de un control (clic en un
botón, cambio de selección en un
combo), de la página (Load, Init), etc.
4. Se colocan en orden las acciones en la
página, ya que si se asignaran dos o más
acciones al evento Click del mismo
botón, podría ser importante tener en
cuenta que la acción que aparece antes
en la página se ejecutará primero.
Al convertir el patrón Acción en un
componente para ASP.NET, se crea una
entidad declarativa, visiblemente semejante a un caso de uso. A través de ella,
se pueden relacionar actores, operaciones y receptores, tanto en tiempo de
diseño como en ejecución. Esto ofrece
mayor flexibilidad para cambiarlos en
el momento necesario.
Implementación del patrón
Acción
Se llamará A ctionBase (listado 1) a la clase base de todas las acciones, que consta de los siguientes miembros:
• Método público Execute. Como su
nombre indica, ejecuta la petición,
operación o lógica programada en la
acción.
• Método público virtual Undo. Deshace la operación realizada. Si no es posible deshacer, se lanza una excepción
NotSupportedException (éste es el comportamiento predeterminado).
using System;
using System.ComponentModel;
namespace Weboo.Web.UI.WebControls {
public abstract class A ctionBase : Control {
public A ctionBase() : base() { }
public sealed void Execute() {
CancelEventHandler be = BeforeExecute;
if (be != null) {
CancelEventA rgs args = new CancelEventA rgs();
be(this, args);
if (args.Cancel)
return;
}
InternalExecute();
if (A fterExecute != null) {
A fterExecute(this, new EventA rgs());
}
public virtual void Undo() {
throw new NotSupportedException();
}
protected abstract void InternalExecute();
public event CancelEventHandler BeforeExecute;
public event EventHandler A fterExecute;
}
}
Listado 1: La clase ActionBase
<<dotNetManía
den cambiar en tiempo de ejecución.
Por ejemplo, se tiene una tabla con datos
producidos por una consulta SQL y se
desea ocultar columnas u ordenar por
una de ellas. El invocador puede ser el
manejador de un evento de botón o de
casilla de verificación, el receptor es la
columna de la tabla que se desea ocultar o por la que se va a ordenar, y la
acción puede ser ocultar u ordenar.
15
<< dnm.plataforma.net
• Método protegido y abstracto InternalExecute. Debe ser implementado
por las clases herederas para proveer al control de su funcionalidad
correspondiente.
• Evento BeforeExecute. Se dispara antes
de ejecutar la acción. A través de este
evento, el programador puede cancelar la ejecución de la acción en caso
de que ello sea conveniente.
• Evento A fterExecute. Se dispara después de ejecutar la acción. Mediante este evento se puede hacer algún
tratamiento posterior a la ejecución
de la acción, como deshacer o incorporar lógica adicional.
using
using
using
using
using
namespace Weboo.Web.UI.WebControls {
public abstract class ButtonA ction : A ctionBase {
public ButtonA ction() : base() {}
[Description("ID del botón que ejecutará la acción."),
DefaultValue(""),
TypeConverter(typeof(WebControlIDConverter)),
WebControlIDFilter(typeof(IButtonControl))]
public string ButtonID {
get {
string o = ViewState["ButtonID"] as string;
return (o == null) ? String.Empty : o;
}
set {
ViewState["ButtonID"] = value;
}
Las acciones que hereden de A ctionBase no pueden reemplazar al método
Execute. El implementador de una
acción concreta lo que debe es heredar
de A ctionBase y redefinir el método abstracto InternalExecute, que como es protected no puede ser llamado directamente por un cliente, sino solo a través
de Execute.
Aunque un código cliente de un tipo
derivado de A ctionBase podrá invocar
explícitamente al método Execute, esto
no es lo que se pretende. Una vez que
se han establecido correctamente las
propiedades de una acción en tiempo
de diseño, ésta debe ser capaz de registrar sus propios métodos en un evento
de cualquier control, ya sea un clic de
un botón, un cambio de selección en
un control de lista, etc. Es el código
manejador del evento el que debe llamar entonces a Execute.
}
protected void SetClientClick(WebControl button) {
if (!(button is IButtonControl))
throw new A rgumentException("El control con ID = '" + ButtonID +
"' no implementa la interfaz IButtonControl.");
Type buttonType = button.GetType();
PropertyInfo propClientClick =
buttonType.GetProperty("OnClientClick");
string functionCode = "javascript:" + GetClientEventScript() +
((!this.ContainsServerCode) ? "; return false;" : "");
try {
if (propClientClick== null)
button.A ttributes["onclick"] = functionCode;
else
propClientClick.SetValue(button, functionCode.ToString(),
new object[] { });
}
catch (Exception ex) {
throw new InvalidOperationException(
"La propiedad OnClientClick del control " +
ButtonID + " no se pudo cambiar. ", ex);
}
}
protected virtual string GetClientEventScript() {
return null;
}
<<dotNetManía
Eventos en el cliente y en el
servidor
16
En el desarrollo de componentes
Web ASP.NET, una de las características más importantes a tener en cuenta
es que tenemos dos tipos de eventos: los
de cliente (navegador) y los de servidor.
Por un lado, los scripts o segmentos de
código interpretado (JavaScript, VBScript, etc.) son los encargados del funcionamiento de los controles en el navegador sin provocar llamadas al servidor;
y por el otro, a través de envíos de infor-
System;
System.ComponentModel;
System.Web.UI.WebControls;
System.Web.UI;
System.Reflection;
protected void SetServerClick(WebControl button) {
if (!(button is IButtonControl))
throw new A rgumentException("El control con ID = '" +
ButtonID + "' no implementa la interfaz IButtonControl.");
IButtonControl ib = (IButtonControl) button;
ib.Click += new EventHandler(HandleClick);
}
protected virtual void HandleClick(object sender, EventA rgs e) {
this.Execute();
}
}
}
Listado 2: Implementación en C# de una acción asignable a un botón de ASP.NET
<< dnm.plataforma.net
mación convenientemente oculta en la
página, se reportan vía HTTP como
eventos al servidor [5].
El código del listado 2 muestra una
implementación para una acción asignable a un botón de una página Web
ASP.NET (note que la acción es a su
vez abstracta, porque no se ha dado ninguna implementación particular al
método InternalExecute).
Para mayor brevedad, las implementaciones del convertidor de tipo (type
converter) WebControlIDConverter y del atributo WebControlIDFilterA ttribute han sido
omitidas. Un convertidor de tipo, en
pocas palabras, permite convertir un
objeto de tipo X en una representación
de tipo Y. Por ejemplo, existen convertidores para transformar números a cadenas y viceversa. Asociando un convertidor de tipo a través del atributo TypeConverterA ttribute a una propiedad de un
control (Windows Forms o ASP.NET)
se pueden obtener valores posibles para
asignar a la propiedad cuando ésta se configura en la rejilla de propiedades de
Visual Studio. En el paso 3 de la figura
2, puede notarse cómo el usuario ha elegido “Button1” de una lista de valores
posibles de la propiedad ButtonID. WebControlIDConverter permite obtener una
lista de los ID de controles presentes en
la página Web, mientras que WebControlIDFilterA ttribute le indica al converti-
Figura 2: Pasos para adicionar y configurar la acción Limpiar en Visual Studio .NET
Una acción para borrar
el contenido de formularios
Web
Como ejemplo de aplicación de la
propuesta de este artículo, presentaremos una acción real para limpiar
(poner en blanco el contenido de cuadros de texto y anular la selección en
los controles de selección como DropDownList, ListBox, etc.) un formulario
Web. Como se muestra en la figura 2,
tal acción se arrastra desde el cuadro
de herramientas al área de diseño de
la página, y se le asocia un botón para
ejecutarla; en este caso, habrá también
que asociarle el control contenedor
(por ejemplo, un panel) cuyo contenido se quiere limpiar (vaciando los
controles que éste contiene). Por último, se decide si la acción se ejecutará
en el cliente o en el servidor (propiedad ServerSide).
Como se puede observar, en este
caso es en el método OnLoad donde se
llama a los métodos encargados de
registrar la acción en el evento Click del
<<dotNetManía
La posibilidad de ejecutar la acción tanto en el
cliente como en el servidor y el registro automático
en los eventos del objeto invocador son ventajas
de esta implementación
dor de qué tipos deben ser los controles
para ser incluidos en dicha lista.
El método SetClientClick permite
incluir en el elemento HTML del botón
que se usará para ejecutar la acción el
atributo onclick cuyo valor será la llamada a la función JavaScript (obtenida
mediante GetClientEventScript), que
deberá ser implementada en una cadena con el código de la función y registrada a través del método Page.Client
Script.RegisterClientScriptBlock por los
herederos de esta clase.
Por su parte, el método SetServerClick, según la forma tradicional en C#
para registrarse a eventos, incluye una
llamada a Execute en el evento Click del
botón.
Como se puede apreciar, algunas de
las ventajas de esta implementación son
la posibilidad de ejecutar la acción tanto en el cliente como en el servidor y
el registro automático de los métodos
de la acción en los eventos del objeto
invocador.
17
<< dnm.plataforma.net
<<dotNetManía
Hasta el momento, en
ASP.NET las acciones se
habían implementado como
objetos a los que se hacían
peticiones a través de un
método como Execute
18
botón. Si además el evento se procesa
en el cliente, se llama al método RegisterScriptCode para registrar el código
JavaScript que garantizará la operación.
En este caso InternalExecute solo se ejecutará si la propiedad ServerSide es true.
Note que es este método quien invoca
al método RecursiveClear para limpiar
los controles.
Se ha hecho también una redefinición (override) de GetClientEventScript para personalizar la llamada a la
función script registrada con el ID del
contenedor a limpiar. Por ejemplo, si
FunctionName es igual a Clear y ContainerID es Panel1, este método devolverá
Clear('Panel1').
Por último, tenga en cuenta que
el método FindControl de la clase Control busca en el contenedor de nombres actual (naming container) un control con el ID especificado como
parámetro [4]; sin embargo, en
muchas ocasiones esto no es suficiente
para encontrar un control, así que la
clase Util (que no se ha incluido por
motivos de espacio, pero puede descargarse del sitio Web de dotNetManía) incluye una versión estática
de FindControl que si no encuentra el
control en su naming container sube
un nivel hacia arriba en la jerarquía
de contenedores, repitiendo la búsqueda hasta llegar al nivel de la instancia de Page. Si a pesar de todo el
control no se encuentra, el método
devuelve null.
using
using
using
using
using
using
System;
System.Text;
System.Web.UI;
System.ComponentModel;
System.Web.UI.WebControls;
System.Drawing;
namespace Weboo.Web.UI.WebControls {
[DefaultProperty("ContainerID"),
ToolboxBitmap(typeof(A ctionBase), "A ction.bmp")]
public class A ctionClear : ButtonA ction {
public A ctionClear() {
ViewState["FunctionName"] = "Clear";
this.ServerSide = false;
}
[Description("Indica si los controles se limpian " +
"actualizando sus propiedades en el servidor (true) " +
"o en el cliente (false)."),
DefaultValue(false)]
public bool ServerSide {
get {
return (bool)ViewState["ServerSide"];
}
set {
ViewState["ServerSide"] = value;
}
}
[Description("ID del control contenedor en el que se encuentran " +
"los controles que se limpiarán."),
DefaultValue(""),
TypeConverter(typeof(A ssociatedControlConverter))]
public string ContainerID {
get {
string o = ViewState["ContainerID"] as string;
return (o == null) ? String.Empty : o;
}
set {
ViewState["ContainerID"] = value;
}
}
[Description("Nombre de la función script cliente " +
"que ejecuta la acción de limpiar."),
DefaultValue("Clear")]
public string FunctionName {
get {
string o = ViewState["FunctionName"] as string;
return (o == null) ? String.Empty : o;
}
set {
ViewState["FunctionName"] = value;
}
}
protected override void OnLoad(EventA rgs e) {
base.OnLoad(e);
Control button = Util.FindControl(this, this.ButtonID);
if (button == null)
return;
if (ServerSide)
SetServerClick(button);
else {
SetClientClick(button);
RegisterScriptCode();
}
}
<< dnm.plataforma.net
protected override void InternalExecute() {
Control control = Util.FindControl(this, ContainerID);
if (control == null)
throw new InvalidOperationException(
String.Format(
"Control con ID = {0} no encontrado.", ContainerID));
RecursiveClear(control);
}
private void RecursiveClear(Control control) {
if (control is TextBox)
((TextBox)control).Text = String.Empty;
else
if (control is ListControl)
((ListControl)control).ClearSelection();
else
foreach (Control current in control.Controls)
RecursiveClear(current);
}
private void RegisterScriptCode() {
Type pageType = Page.GetType();
if (!Page.ClientScript.IsClientScriptBlockRegistered(
pageType, FunctionName)) {
Page.ClientScript.RegisterClientScriptBlock(pageType,
FunctionName, String.Concat(
"<script language=\"javascript\">",
"function ", FunctionName, "(id) {",
" var c = document.getElementById(id);",
" for (i = 0; i < c.all.length; i++)",
"
if ((c.all.item(i).tagName == \"INPUT\" &&",
"
c.all.item(i).type == \"text\") || ",
"
c.all.item(i).tagName == \"TEXTA REA \")",
"
c.all.item(i).value = \"\"; ",
"
else if (c.all.item(i).tagName == \"SELECT\" &&",
"
c.all.item(i).options.length > 0)",
"
c.all.item(i).options[0].selected = true; ",
"}</script>")
);
}
}
protected override string GetClientEventScript() {
string idControl = this.ContainerID;
if (ServerSide) {
Control container = Util.FindControl(this,
this.ContainerID);
if (container == null)
throw new A rgumentException("El control con ID = '" +
ContainerID + "' no se encuentra.");
idControl = container.ClientID;
}
return String.Format("{0}('{1}')", FunctionName, idControl);
}
}
}
Listado 3: Acción que limpia el contenido de un formulario Web.
Conclusiones
Hasta el momento, en ASP.NET las
acciones se habían implementado como
instancias de objetos a las que se hacían
peticiones a través de un método como
Execute. Los parámetros, como el receptor, se asignaban a propiedades desde
el código. Con este nuevo enfoque de
la acción en forma de componente de
ASP.NET se obtienen las siguientes
ventajas:
• Solo hay que colocar el código
imprescindible –es decir, el que es
propio para cada página- en code
behind. Todas las funcionalidades de
la página se programan una sola vez
en las acciones, lo cual conduce a una
mayor facilidad de mantenimiento
del código fuente.
• El funcionamiento de la página puede definirse completamente en tiempo de diseño.
• Mayor modularidad, reusabilidad y
extensibilidad para incorporar nuevas funcionalidades a las páginas.
• Facilidad para indicar que las acciones se ejecuten en el navegador, en
el servidor o en ambos.
• La creación de páginas Web
ASP.NET desde Visual Studio puede realizarse sin muchos conocimientos de la tecnología.
La aplicación de este enfoque a
otros patrones de diseño, como Observador (Observer) o Publicación-Suscripción (Publish-Subscribe) [3], así
como Fábrica Abstracta (Abstract Factory), Constructor (Builder) [1] y otros
pueden aumentar las capacidades de
desarrollo para definir y utilizar componentes en ASP.NET.
Bibliografía
[ 2]
Lasater, Christopher G. CodeProject. Design Patterns: Command Pattern. Free source code and programming help. En
http://www.codeproject.com/KB/books/DesignPatterns.aspx, 2006.
[ 3]
Homer, Alex. Design Patterns for ASP.NET Developers. Part 3: Advanced Patterns. En http://www.devx.com/dotnet/A rticle/34220/1763, 2007.
[ 4]
[ 5]
Microsoft Developer Network for Visual Studio 2005. Microsoft, 2005.
MacDonald, Matthew y Szpuszta, Mario. Pro ASP.NET 2.0 in C# 2005. Apress, 2005. págs. 67-69.
<<dotNetManía
[ 1 ] Gamma, Erich, et al. Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley Longman, 1998.
19
Sharepoint
Gustavo Vélez
HttpHandlers y HttpModules
para SharePoint 2007
Este artículo describe las posibilidades que ofrecen los manejadores
HTTP (HttpHandlers) y los módulos HTTP (HttpModules) de ASP.NET,
y cómo pueden utilizarse estos mecanismos para implementar funcionalidades avanzadas en sitios de SharePoint 2007.
Gustavo Vélez es ingeniero mecánico y electrónico,
especializado en el diseño,
desarrollo e implementación de software (MCSD)
basado en tecnologías de
Microsoft, especialmente
SharePoint. Es creador y
webmaster de
http://www.gavd.net/servers, y trabaja como senior
developer en Winvision
(http://www.winvision.nl)
En el principio de los tiempos, solamente existía
HTML. HyperText Markup Language (HTML)
fue rápidamente aceptado, y constituye hoy en día
la base de todo tipo de aplicaciones Web. Pero
HTML solamente permite mostrar contenido
estático, lo que rápidamente fue visto como una
limitación seria para el desarrollo de tecnologías
Web. Los desarrolladores necesitan mecanismos
para que las aplicaciones Web sean dinámicas y
permitan generar contenido a partir de bases de
datos o siguiendo las preferencias de los usuarios.
Por esta razón, los fabricantes de servidores Web
comenzaron a crear tecnologías complementarias
para garantizar el desarrollo dinámico en la Red:
Microsoft creó la Internet Server API (ISAPI) para
su Internet Information Services (IIS), que también fue adoptada por Apache, y Netscape desarrolló NSAPI (Netscape Server API) con el mismo objetivo.
ISAPI consta de dos mecanismos principales:
las extensiones y los filtros:
• Las extensiones no son más que aplicaciones
normales que se pueden hacer ejecutar mediante una solicitud Web. La parte más conocida
de las extensiones ISAPI es la cadena de consulta (query string) que aparece al final de un
URL en la forma de un signo de interrogación seguido de al menos una asociación parámetro-valor, éstos últimos separados entre sí
mediante el símbolo “&” (por ejemplo,
http://Servidor/default.aspx?param1=valor1&
param2=valor2).
• Los filtros son lo que la palabra indica: algo
que destila y modifica la información entre
la solicitud y la respuesta Web.
Trabajar programáticamente con ISAPI nunca ha
sido fácil por su complejidad: hay que utilizar directamente los compiladores de la familia Win32, y el desarrollo tradicionalmente solo ha sido posible con C/C++.
Para aliviar este problema, ASP.NET ofrece los manejadores HTTP (HttpHandlers) y los módulos HTTP
(HttpModules):
• Los manejadores HTTP pueden ser vistos
como un equivalente de las extensiones ISAPI, y a nivel de programación son componentes que implementan la interfaz System.Web.IHttpHandler.
• De forma similar, los módulos HTTP pueden ser comparados con los filtros ISAPI,
e implementan la interfaz System.Web.IHttpModule.
El funcionamiento de SharePoint 2003 se
basaba completamente en un filtro ISAPI especialmente diseñado para manejar el enrutamiento
de las solicitudes Web. Esto producía algunos
efectos colaterales, como por ejemplo que el servicio IIS estaba totalmente “secuestrado” por
SharePoint, impidiendo el funcionamiento de
<< dnm.servidores.sharepoint
HttpHandlers para
SharePoint 2007
Para crear un manejador HTTP para
SharePoint 2007, comience por crear un
nuevo archivo con la extensión .ashx en
el directorio C:\A rchivos de programa\A rchivos comunes\Microsoft Shared\Web server extensions\12\TEMPLA TE\LA YOUTS. El código de ejemplo que se
presenta en el listado 1 (basado en una
presentación de Ted Pattison) escribe
en pantalla un texto establecido en el
contexto de la página.
Después de agregar una referencia
al ensamblado de SharePoint y heredar
de la interfaz IHttpHandler, se implementan la propiedad IsReusable y el
método ProcessRequest de la interfaz.
En éste último se crean objetos SPSite
y SPWeb basados en el contexto para mostrar un texto informativo. El método
IHtttpHandler.ProcessRequest recibe
como parámetro el HttpContext de la
página, de tal forma que la propiedad
Response de éste pueda ser utilizado para
escribir en la pantalla.
Este es un ejemplo muy sencillo, pero
útil para mostrar el funcionamiento de
un manejador HTTP. El tipo MIME de
la respuesta que se va a generar (ContentType) es “text/plain” en el ejemplo,
pero podría utilizarse cualquier otro tipo,
como XML, flujos binarios (por ejemplo para devolver imágenes), Adobe PDF
o cualquier tipo de documento de Office. La extensión .ashx es reconocida por
defecto por IIS como correspondiente a
un manejador HTTP, pero se puede utilizar cualquier otra extensión que se
desee, siempre que se la registre como
tal en la sección httpHandlers de web.config o machine.config.
<%@ WebHandler Language=”C#” Class=”HolaHttpHandler” %>
<%@ A ssembly Name=”Microsoft.SharePoint, Version=12.0.0.0,
Culture=neutral, PublicKeyToken=71e9bce111e9429c” %>
using System;
using System.Web;
using Microsoft.SharePoint;
public class HolaHttpHandler : IHttpHandler
{
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
SPWeb miSitio = SPContext.Current.Web;
context.Response.ContentType = “text/plain”;
context.Response.Write(“HolaHttpHandler desde el sitio “ +
miSitio.Title + “ en “ + miSitio.Url);
}
}
Listado 1
SharePoint se encarga de compilar
el código en el momento de ser utilizado, por lo que no es necesario generar ni instalar DLL alguna. El archivo
tampoco es guardado en memoria, por
lo que tampoco es necesario ejecutar
un IISRESET después de modificarlo.
El ejemplo mostrado podría haber
sido desarrollado prácticamente con el
mismo código usando una página .aspx
tradicional. La ventaja de un manejador
HTTP reside en la posibilidad de hacer
reconocer extensiones propias en IIS, y
de interpretarlas y mostrarlas en pantalla
utilizando un tipo específico de transformación (definido por la propiedad ContentType). De esta manera es posible, por
ejemplo, enviar directamente al navegador documentos PDF o implementar
algún tipo de contenido propio.
HttpModules para
SharePoint 2007
Los módulos HTTP permiten implementar una funcionalidad más general
que la de los manejadores HTTP. La
diferencia fundamental entre ellos dos
radica en que los módulos se ejecutan
para todas las solicitudes, sean del tipo
que sean, sin importar la extensión concreta de la URL que se esté solicitando ni el manejador HTTP que será utilizado para satisfacerla. Esto abre las
puertas a crear código que siempre realice alguna actividad en el sistema.
Formalmente, la interfaz IHttpModule que deben implementar los módulos consta solamente de dos métodos,
Init y Dispose. En Init se implementa
la inicialización del módulo, y el método recibe como parámetro una referencia al contexto (objeto HttpA pplication) que representa a la aplicación Web
en ejecución. Típicamente, en este
método se “enganchan” manejadores
para los eventos globales de la aplicación, como BeginRequest, EndRequest,
A cquireRequestState, A uthenticateRequest
o A uthorizeRequest. Normalmente, los
eventos más interesantes son BeginRequest y EndRequest, que permiten actuar,
respectivamente, sobre la solicitud del
usuario antes de que SharePoint la pro-
<<dotNetManía
otras aplicaciones Web en el mismo
servidor. En la versión 2007 de SharePoint, el filtro ISAPI ha sido sustituido por manejadores y módulos,
garantizando de esta manera la compatibilidad con ASP.NET y liberando
el servicio IIS. Otra gran ventaja es
que ahora disfrutamos de un modelo
abierto: el desarrollador puede crear
sus propios módulos para implementar tareas específicas de un determinado portal utilizando C# o Visual
Basic.
21
<< dnm.servidores.sharepoint
cese, y sobre la respuesta una vez que
está lista para ser enviada de regreso.
El ejemplo más sencillo de módulo HTTP que se puede pensar es uno
que genere la misma respuesta para
todas las solicitudes al sistema. Por
supuesto que éste es un ejemplo bastante poco útil en la vida práctica, pero
que podría utilizarse para, por ejemplo, presentar una página de aviso
cuando el portal esté en mantenimiento. Recuerde que el módulo se
ejecutará para todas las solicitudes, sin
importar el tipo de URL que utilice
cualquier usuario; la respuesta siempre será la página de mantenimiento.
El código de este módulo se muestra
en el listado 2.
El ensamblado resultante de compilar este proyecto (de tipo “Class Library”)
deberá ser firmado con un nombre seguro y copiado al directorio Bin de la aplicación Web respectiva en IIS (por ejemplo, C:\Inetpub\wwwroot\wss\VirtualDirectories\80\bin). En realidad, podría
instalarse también en la GAC; pero para
limitar el alcance de un ensamblado a una
determinada aplicación Web es preferible situarlo en el directorio Bin. Para hacer
que SharePoint reconozca el módulo, la
línea que se muestra en el listado 3 (sustituyendo los valores adecuados para el
nombre, tipo y clave pública) debe ser
agregada al archivo web.config de la aplicación Web en IIS, bajo la sección HttpModules.
using System;
using System.Web;
namespace HttpModulo_01
{
public class Class1 : IHttpModule
{
public void Init(HttpA pplication context)
{
context.BeginRequest += new EventHandler(EmpezarSolicitud);
}
private void EmpezarSolicitud(object sender, EventA rgs e)
{
HttpContext.Current.Server.Transfer(
“/_layouts/mantenimiento.html”, false);
}
public void Dispose()
{
}
}
}
<<dotNetManía
Listado 2
22
Como se puede observar, en el método de inicialización hemos añadido al
evento BeginRequest del contexto del
módulo un delegado asociado al método
EmpezarSolicitud, que se deberá ejecutar
cuando dicho evento se dispare. En el
cuerpo de EmpezarSolicitud se transfiere
la llamada a nuestra página de mantenimiento. El método Dispose, por supuesto, es indispensable de ser implementado, y deberá contener el código necesario para liberar cualesquiera recursos que
pudieran haber sido adquiridos en Init.
El orden de los elementos de
la sección HttpModules de
web.config es esencial para el
correcto funcionamiento de
SharePoint
El orden en que se coloquen los elementos de esta sección es esencial para
el funcionamiento de SharePoint (la
autenticación tiene que ocurrir antes
que la autorización, y ésta última antes
de poder asignar roles), y debe ser
mantenido, a riesgo de alterar el funcionamiento interno de SharePoint.
Normalmente, un módulo propio se
debe registrar al final de la sección,
pero no es una regla obligatoria: en el
caso de la página de mantenimiento,
es posible que se decida que la autenticación y autorización no son necesarias, pues el sistema de todas formas
no estará en funcionamiento, y por lo
tanto el módulo HTTP se podría colocar al principio de la sección.
Otra aplicación típica de los módulos es utilizar el evento A fterRequest para
modificar la respuesta que SharePoint
envía al usuario para mostrar cierta
información en todas las páginas del
portal (un pie de página o un texto mostrando las condiciones de uso), como
se muestra en el listado 4.
<add name=”HttpModulo_01” type=”HttpModulo_01.Class1, HttpModulo_01,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=97bc1af85e70ceb9” />
Listado 3
Como podrá observar, en la sección
HttpModules del archivo web.config Sha-
rePoint ya tiene configurados algunos
módulos por defecto: caché, autenticación, autorización y manejo de roles.
En este ejemplo, se está agregando
un manejador al evento EndRequest del
módulo para modificar el código
HTML que SharePoint ya ha generado. El método TerminarSolicitud a su
vez suministra, mediante HttpResponse.WriteSubstitution, un delegado asociado al método EscribirTexto, que es
quien genera el texto necesario. El
resultado se puede ver en la figura 1.
Con respecto al funcionamiento del
módulo, hay que señalar que el pie de
página estará situado detrás de las etiquetas </BODY></HTML> del código
HTML generado. Para el objetivo de
using System;
using System.Web;
namespace HttpModulo_02
{
public class Class1 : IHttpModule
{
public void Init(HttpA pplication context)
{
context.EndRequest += new EventHandler(TerminarSolicitud);
}
private void TerminarSolicitud(object sender, EventA rgs e)
{
HttpA pplication miHttp = (HttpA pplication) sender;
miHttp.Context.Response.WriteSubstitution(
new HttpResponseSubstitutionCallback(EscribirTexto));
}
private static string EscribirTexto(HttpContext context)
{
return “Este es un pie de página”;
}
public void Dispose()
{
}
}
}
Listado 4
Figura 1: Texto de pie de página en todas las páginas del portal
un pie de página, el resultado es el esperado; pero aunque los navegadores
modernos podrán mostrar el texto sin
problemas, este código no es conforme
a las especificaciones de w3.org. Probablemente la mejor solución sea obtener toda la respuesta HTML a través
de un flujo, modificarla por medio de
una concatenación o una expresión
regular y enviar la respuesta modificada. El propósito del ejemplo es mostrar cómo utilizar un módulo en SharePoint; los detalles de implementación
pueden ser especificados de acuerdo
con las necesidades particulares. También hay que tener en cuenta que el texto del pie de página debería ser almacenado fuera del módulo, de manera de
que cuando se desee modificar el texto
no sea necesario recompilar el código.
Aunque los eventos BeginRequest y
EndRequest sean los más “populares”,
hay otros eventos que pueden ser utilizados, y a veces es obligatorio usarlos.
Es el caso de que se quiera cambiar
dinámicamente la página maestra: en
esta situación, es imprescindible utilizar el evento PreRequestHandlerExecute,
que se dispara precisamente antes de
que ASP.NET empiece a generar la
página; si se utiliza otro evento, la página maestra ya habrá sido mezclada con
el contenido y no será posible cambiarla. Un ejemplo de esto se presenta
en el listado 5.
Note que las posibilidades de este
módulo son realmente extensas: en una
instalación por defecto, SharePoint permite definir una sola página maestra por
colección de sitios, y dicha página es configurada para todos los usuarios de la
colección. Los temas son una forma de
crear alguna personalización de páginas
dentro de la colección, y permiten personalizar la configuración por cada usuario; pero los cambios que se pueden hacer
con los temas están limitados a las modificaciones a realizar mediante estilos de
CSS. Con un módulo HTTP de este
tipo, se puede modificar radicalmente las
páginas en base a grupos de usuarios o
inclusive usuarios individuales, permitiendo que cada grupo tenga una interfaz completamente diferente, no solo
visual, sino también funcionalmente.
<<dotNetManía
<< dnm.servidores.sharepoint
23
<< dnm.servidores.sharepoint
using System;
using System.Web;
using System.Web.UI;
namespace HttpModulo_03
{
public class Class1 : IHttpModule
{
public void Init(HttpA pplication context)
{
context.PreRequestHandlerExecute += new EventHandler(CambiarSolicitud);
}
private void CambiarSolicitud(object sender, EventA rgs e)
{
Page Page miPagina = HttpContext.Current.CurrentHandler as Page;
if (miPagina != null)
miPagina.MasterPageFile = “~/Master1.master”;
}
public void Dispose()
{
}
}
}
<<dotNetManía
Listado 5
24
Continuando con los eventos que
pueden ser utilizados, otro ejemplo de
módulo HTTP que puede mejorar el
funcionamiento de SharePoint es uno
que permita generar una página con
mejor información para el usuario
cuando ocurre un error en el sistema.
SharePoint muestra por defecto una
página que indica solamente que ha
ocurrido un error, sin dar mayor información al respecto. Un módulo, por el
hecho de ejecutarse en todas las consultas que pasan a través de IIS, está en
capacidad de interceptar cualquier
error que pueda ocurrir y actuar en
consecuencia, como se muestra en el
listado 6.
En el manejador de eventos MiError
del módulo se recorren una por una
todas las excepciones que se han producido, creando entradas en el Visor
de sucesos de Windows. Luego se eliminan los errores en el contexto y se
redirige a una página especial. Esta
página puede mostrar los mensajes de
error, por ejemplo, e indicar que acción
a realizar, si es necesario. Para el registro se generan aquí entradas muy sencillas, pero por supuesto en la vida real
se debe incluir toda la información
sobre el error para facilitar su repro-
ducción y corrección. Igualmente, los
errores se podrían almacenar en una
base de datos u otro sistema de archivo (inclusive dentro de una lista de SharePoint), y se podría ejecutar otras
acciones, como enviar un e-mail al
administrador del sistema.
Conclusión
Los manejadores HTTP y los módulos HTTP nos permiten aumentar la
flexibilidad y manejabilidad de SharePoint 2007. Desafortunadamente, hasta el presente han sido relativamente
muy poco explotados, pero por su facilidad de programación y por la cantidad de situaciones en las que pueden
ser aplicados, constituyen dos herramientas que siempre hay que tener en
mente cuando se esté trabajando programáticamente con SharePoint.
using System;
using System.Diagnostics;
using System.Web;
namespace HttpModulo_04
{
public class Class1 : IHttpModule
{
public void Init(HttpA pplication context)
{
context.Error += new EventHandler(MiError);
}
private void MiError(object sender, EventA rgs e)
{
Exception[] todosMisErrores = HttpContext.Current.A llErrors;
foreach (Exception ex in todosMisErrores)
{
EventLog miLog = new EventLog ();
miLog.Log = “A pplication”;
miLog.Source = “Mi HttpModule”;
miLog.WriteEntry(“Ha ocurrido un error: “ + ex.Message);
}
HttpContext.Current.Server.ClearError();
HttpContext.Current.Server.Transfer(
“/_layouts/MiPaginaDeErrores.aspx”);
}
public void Dispose()
{
}
}
}
Listado 6
plataforma.net
Juan Luis Ceada
Autenticación y autorización en
servicios Web
con cabeceras y extensiones SOAP
En ocasiones es necesario tener un control exhaustivo de los accesos que se
producen a nuestros servicios Web (quién accede, a dónde y cuántas veces),
tanto por seguridad como para mantener la calidad del servicio. En este artículo veremos cómo podemos cumplir estos requisitos interceptando las llamadas realizadas por los clientes a nuestra plataforma de servicios Web.
Juan Luis Ceada
es Ingeniero en
Informática. Actualmente trabaja en
Arrakis Servicios y
Comunicaciones
(Grupo BT) como
Jefe de proyectos y
analista, estando a
cargo de múltiples
desarrollos y sistemas
Web que usan tecnologías Microsoft. También es autor de múltiples artículos en
revistas del sector.
Un buen día llega uno de los comerciales de la
empresa y te dice que uno de los nuevos clientes desea integrar sus sistemas con los nuestros.
La idea del cliente es automatizar todos sus procesos, teniendo en cuenta que en parte de ellos
intervendrá nuestra empresa como proveedora
de algún tipo de servicio. En estos días, la solución más acertada para hacer frente a escenarios como éste pasaría por proveer de una capa
de servicios Web, de tal forma que expongamos
a nuestros clientes parte o todos los servicios de
nuestra empresa.
Pero claro, aquí empiezan nuestros dolores de
cabeza y nos tenemos que plantear algunas cosas:
¿Cómo y con qué lo hago? ¿Cómo gestiono la
seguridad de la capa de servicios Web (autenticación, autorización, confidencialidad, integridad)?
¿Cómo puedo dar mejor soporte al cliente? Algunas de estas preguntas tienen fácil y rápida respuesta. Por ejemplo, el “cómo y con qué lo hago”.
Está claro, con ASP.NET. Con respecto a la confidencialidad y a la integridad de la información,
podemos resolverlo utilizando SSL en nuestras
comunicaciones (o haciendo uso del estándar WSSecurity), algo que hoy en día, tanto por coste
como por facilidad de implementación, es aconsejable en todos los proyectos de este tipo. En las
próximas líneas veremos cómo podemos resolver
algunas de las otras cuestiones.
¿Qué vamos a desarrollar?
El proyecto que vamos a llevar a cabo nos servirá como base para afrontar nuevos desarrollos
de servicios Web. Nos permitirá:
• Controlar los accesos: decidir quién puede
acceder y desde dónde a nuestra plataforma de
servicios Web, mediante el uso de login y password más validación de IP (sin depender del
servidor IIS).
• Controlar qué servicios Web y métodos pueden usar los clientes (autorización).
• Controlar el número de accesos a nuestra plataforma: para evitar abusos, o simplemente para
tener diferentes niveles de servicio en función
de la importancia del cliente.
• Tener la capacidad para decidir si las peticiones
que recibamos son correctas o no, y denegar el
acceso en caso de que no lo sean (para reducir
la posibilidad de ciertos tipos de ataques).
• Tener mecanismos de logging para poder dar
mejor soporte a nuestros clientes en caso de que
sea necesario.
Y todo ello, sin necesidad de tener el control
absoluto del servidor Web donde se alojen los servicios Web, puesto que nos basaremos únicamente en
un modelo de datos gestionado por SQL Server para
controlar todo lo anterior.
<< dnm.plataforma.net
Como herramienta de desarrollo se
ha optado por Visual Studio 2008 Web
Developer Express Edition, y como base
de datos, SQL Server 2005 Express Edition. No se utilizan las características novedosas de VS 2008, por lo que VS 20005
podría servir también.
El modelo de datos
Figura 1. Modelo de datos
Además, en ws_metodoswebservice tenemos un campo llamado tamanomaximoxml.
Este campo contendrá el tamaño aproximado en kilobytes del mensaje SOAP
esperado para este método. El valor de este
campo deberemos calcularlo en función
de los parámetros que cada método pueda recibir. Por ejemplo, el mensaje SOAP
de un método que reciba únicamente un
entero como parámetro no debería superar el kilobyte de tamaño. Cualquier cosa
que recibamos de más tamaño sin duda
será una petición errónea como mínimo,
pudiendo tratarse de un ataque de denegación de servicio (basado en el uso de un
XML recursivo de gran tamaño, por ejemplo), que podremos parar o mitigar simplemente rechazando la petición antes de
que sea procesada por el parser XML del
servidor. En los casos de métodos para los
que nos sea imposible prever el tamaño de
los mensajes, podemos utilizar el valor 0
que equivale a “no verificar el tamaño”
(cosa que deberíamos evitar siempre que
sea posible).
Las tablas ws_permisosusuario4webservice y ws_permisosusuario4metodo sirven
para modificar los permisos por defecto
de acceso a un servicio Web completo, o
a métodos particulares de determinados
servicios Web. Por ejemplo, podemos
hacer que un supuesto método para
enviar correos masivos (permiso denegado por defecto) del servicio clientes
esté disponible para el usuario ws_admin.
Para ello, bastará con añadir un registro
en ws_permisosusuario4metodo con los valores ('ws_admin', 'clientes', 'mandarmailmasivo', 'P'), que se impondría al valor por
defecto que se almacena en ws_metodoswebservice.
La tabla ws_controlanchobanda nos
ayudará a decidir cuándo un usuario
está abusando del servicio, o simplemente si un usuario ha superado el límite de llamadas permitidas. En este caso,
se ha decidido simplificar, de tal forma
que podemos controlar únicamente
cuántas llamadas a la plataforma se pueden hacen por unidad de tiempo. Valores válidos son “5 llamadas por segundo”, “20 al día” o “1000 al mes”. Aquí
podríamos haber complicado aún más
el esquema, haciéndolo más granular.
Por ejemplo, “20 llamadas al día al servicio Web XXX”, “3 llamadas por
segundo al método YYY del servicio
Web XXX”, pero a efectos de este artículo es suficiente con algo más genérico. El campo unidaddetiempo debe contener dos caracteres, cuyos valores coinciden con los que admite la función
dateadd de Transact-SQL (“dd” para
días, “hh” para horas, etc.)
<<dotNetManía
Para poder llevar a cabo nuestro proyecto, tendremos que apoyarnos en un modelo de datos, cuyo diagrama podéis ver en
la figura 1. Veamos para qué sirve cada
tabla. En primer lugar, la tabla ws_usuarios
almacena los logins y passwords de todos los
usuarios que podrán acceder a nuestra plataforma de servicios Web. En la tabla
ws_ipsautorizadas almacenaremos las
direcciones IP desde donde podrán acceder dichos usuarios a la plataforma. Se
admite el formato IP/máscara, con lo que
con 192.168.0.0/255.255.0.0 (por ejemplo)
estaríamos permitiendo el acceso desde
cualquier máquina de la intranet a un
usuario en particular.
Las tablas ws_webservices y ws_metodoswebservice alojan, respectivamente,
los nombres de cada uno de los servicios Web que vayamos a proporcionar
a los clientes, junto con sus respectivos
métodos. Todos y cada uno de los servicios Web que creemos, así como todos
y cada uno de los métodos que estos
posean, deberán estar registrados en
estas tablas, o de lo contrario no seremos capaces de utilizarlos (ni siquiera
nosotros: el sistema de seguridad nos lo
impedirá). Ambas tablas contienen un
campo llamado permisopordefecto que nos
permitirá decidir si un servicio
Web/método está disponible para todo
el mundo (“P” de permitido) o para
nadie (“D” de denegado) por defecto.
Por ejemplo, un método para enviar un
e-mail masivo a todos nuestros clientes
puede estar desactivado por defecto por
su “peligrosidad”, pero otro para consultar el nombre de un cliente a partir
del NIF debería estar disponible por
defecto, por ser algo “básico”.
27
<< dnm.plataforma.net
Evidentemente, para poder saber si
un usuario supera el límite de llamadas,
necesitamos un log donde registrar cuántas llamadas se han hecho. Para eso tenemos la tabla ws_estadisticas, donde almacenamos, entre otras cosas, la IP de origen, servicio Web y método accedido, así
como la fecha y hora del acceso.
Es importante recalcar que este
modelo de datos va a ser accedido con
muchísima frecuencia, por lo que conviene que sea supervisado por un administrador de bases de datos que pueda
aportar su experiencia a la hora de optimizar el rendimiento del servidor.
Procedimientos almacenados
<<dotNetManía
Para trabajar con el modelo de datos,
usaremos procedimientos almacenados
desarrollados en Transact-SQL. En
concreto, dispondremos de cinco:
• ws_validarusuario: valida las credenciales del usuario, a partir de login y
password.
28
Figura 2. Procedimiento almacenado
• ws_validartamanomensaje: comprueba si para un servicio Web y método en particular se está superando
el tamaño de mensaje XML esperado.
Al hilo de este artículo, me gustaría comentaros mi experiencia con la integración de nuestros clientes. Llevo ya algunos años ayudando a terceros a integrarse con nuestra plataforma, y he visto casi de todo: gente que no ha tenido el más mínimo problema, otros a los que
les ha costado algo más, y algunos con los que durante algunos momentos he llegado a pensar en tirar la toalla. Pero al final todo han sido finales felices. Poder interceptar lo que los
clientes envían (el XML en bruto), así como llevar un registro de las excepciones producidas ayuda (y no sabéis cuanto, sobre todo cuando aparecen los temidos problemas de interoperabilidad).
Tener la mente abierta ayuda también: no os cerréis a dar soporte solo a la integración entre
determinadas plataformas. Algunos clientes usarán .NET, y por tanto el soporte a la integración
debería ser total. Otros usarán Java, que tampoco debería dar problemas. Pero otros usarán PHP,
Ruby, C++ (o cualquier otra cosa), y a lo mejor no tenéis personal con el conocimiento necesario para dar soporte. En este caso, no os neguéis a ayudar. En todo caso, advertid que no es vuestro campo, pero siempre intentad ayudar (aunque tengáis que aprender sobre la marcha, siempre
es más fácil para el “servidor” encontrar y depurar los problemas que para el “cliente”). Al final,
habréis aprendido cosas nuevas, y tendréis una base de datos de ejemplos en diferentes lenguajes
de programación que ayudarán a futuros nuevos clientes.
Otra cosa: no os olvides nunca que una vez la integración se produce, ya no hay marcha
atrás, y que cualquier problema repercutirá inmediatamente en los clientes. Por tanto la disponibilidad del servicio se vuelve importantísima, y habrá que prever con la antelación necesaria los cambios en la plataforma, manteniendo a los clientes informados, y realizando multitud de pruebas antes del paso a producción, siendo imprescindible en este caso contar con
una plataforma de integración previa al paso a producción y distinta de la plataforma de desarrollo. Y un último consejo: la comunicación por e-mail está bien, pero de vez en cuando los
clientes agradecen una llamada, aunque sólo sea para preguntar “¿cómo vais?”.
• ws_validaracceso: comprueba si un
usuario está autorizado para acceder
a un determinado servicio Web/método, teniendo en cuenta los permisos
del mismo y si ha superado el ancho
de banda asignado o no.
• ws_obteneripsusuarios: devuelve un
conjunto de datos con todas las IP
desde las que el usuario puede acceder a la plataforma.
• ws_guardarestadistica: almacena los
accesos que los usuarios van haciendo a la plataforma.
De todos ellos, el que tiene mayor
complejidad (nada del otro mundo) es
ws_validaracceso, del que podéis ver una
parte en la figura 2.
Para poder utilizar estos procedimientos, hemos desarrollado un par de
clases auxiliares (fichero WSA uxiliar.cs).
La clase IPMask nos ayudará a la hora de
comprobar si la IP desde la que accede el
usuario coincide con alguna de las que
tenemos almacenadas en la base de datos
(teniendo en cuenta la máscara). Otra clase, llamada WSA uxiliar (dividida en capa
de negocios y capa de acceso a datos) nos
permitirá utilizar los procedimientos antes
descritos. El único método que contiene
algo de código adicional es ValidarA cceso, y solo porque además de llamar al pro-
<< dnm.plataforma.net
cedimiento ws_ValidarA cceso también llama a ws_ObtenerIpsUsuario para obtener la
lista de IP validadas y verificar si alguna
coincide con la de origen (ver listado 1).
credenciales de usuario. O las clases A uthExtension y A uthExtensionA ttribute, que
son la base de todo el sistema. Pero
vamos por partes.
El servicio Web WSBase
La propiedad Credenciales
Una vez analizado el modelo de datos,
pasemos a ver cómo lo utilizaremos
en nuestra plataforma de servicios
Web. En primer lugar, hemos creado
un servicio Web que hereda directamente de System.Web.Services.WebService, y al que hemos llamado WSBase.
Como su nombre indica, este servicio Web será la base de toda nuestra
plataforma. Por tanto, todos y cada
uno del resto de los servicios Web
deberán descender de WSBase; esto es
imprescindible para el correcto funcionamiento del sistema.
Pero, ¿qué hace tan especial a WSBase? Pues varias cosas, en realidad. En
primer lugar, en él se definen ciertas
estructuras de datos que heredarán/utilizarán el resto de servicios Web. Por
ejemplo, un objeto de la clase WSRequestHeader, que define el formato de las
Como hemos comentado, todos los
servicios Web, al descender de WSBase,
heredan la propiedad Credenciales de
tipo WSRequestHeader, que a su vez desciende de SoapHeader [1]. Al hacerla descender de SoapHeader, lo que estamos
definiendo es una clase que usaremos
como cabecera SOAP, y que será obligatorio proporcionar en todas y cada
una de las llamadas a nuestra plataforma para poder realizar la validación
del usuario. Afortunadamente, si se
desarrolla la aplicación cliente también
en .NET , bastará con asociar una única vez la cabecera SOAP en el código
para que esta sea enviada en cada llamada automáticamente (en otros lenguajes es necesario pasar explícitamente dicha cabecera en cada una de
las llamadas a métodos como un parámetro más).
Frente a esta forma de proceder,
en la que se comprueban las credenciales en cada petición, tenemos la
posibilidad de validar las credenciales una única vez, de tal forma que no
sea necesario pasar de nuevo por este
proceso en sucesivas peticiones,
ahorrándonos accesos a la base de
datos. El problema es que esto nos
obligaría a guardar cierta información
en variables de sesión, y en el caso de
que optemos por sesiones in-process
esto significaría que el balanceo de
carga (si existe) no sería tan eficiente, por tener que ligar cada sesión a
un servidor particular. Y si se decide
usar sesiones out-off-process, basadas
en SQL Server, pues simplemente
estaríamos trasladando los accesos a
una base de datos distinta.
La clase WSRequestHeader contiene
solamente dos propiedades: login y
password. Por tanto, en cada llamada a
un método el cliente nos debe proporcionar estos datos dentro de la cabecera SOAP del mensaje. Una vez recibidos, buscaremos en la base de datos si
dichos login/password están registrados
public static void ValidarA cceso(string ip, string webservice, string metodo, string login)
{
System.Collections.Generic.List<IPMask> lipm = WSA uxiliarDA L.ObtenerIpsUsuario(login);
bool encontradaip = false;
if (lipm != null)
{
foreach (IPMask ipm in lipm)
{
if (!encontradaip) encontradaip = IPMask.ValidaIP(ip, ipm);
}
}
if (!encontradaip)
{
throw new Exception(“No se puede acceder a la plataforma de WS desde la IP “ + ip);
}
Listado 1: Código del método WSAuxiliar.ValidarAcceso
<<dotNetManía
// una vez analizada la IP, vemos si le concedemos o no acceso al WS, teniendo
// en cuenta factores como los permisos o las últimas estadísticas de acceso
WSA uxiliarDA L.ValidarA cceso(webservice, metodo, login);
29
<< dnm.plataforma.net
El uso de cabeceras SOAP para la autenticación tiene
ventajas frente al método tradicional, puesto que podemos
“exigir” datos adicionales como números de licencia sin
tener que complicar la interfaz de los métodos
y son válidos. Como toda clase, WSRequestHeader podría admitir muchas más
propiedades. Por ejemplo, podría
incluir algún tipo de token pre-generado, número de licencia, o cualquier otro
literal que sirva para garantizar la autenticación, y que los clientes nos deberán
proporcionar.
Pero, ¿cómo indicamos a las aplicaciones clientes de nuestro servicio
Web que deben enviar una cabecera con
credenciales al llamar a todos (o solo
algunos) de los métodos existentes?
Veamos el servicio Web Clientes (que,
por supuesto, hereda de WSBase), implementado en Clientes.cs. Contiene dos
métodos bastante simples: Consultar y
Borrar. El código del método Consultar
se presenta en el listado 2.
información se incluye en el fichero
WSDL, lo que permite a los entornos de
desarrollo conocer las necesidades del
servidor para poder generar el proxy cliente adecuado. Podríamos perfectamente
tener varios tipos de cabeceras (unas más
simples, otras más complejas), y hacer que
cada una se asocie a un método distinto
en función de nuestras necesidades.
La clase AuthExtension
La clase A uthExtension desciende de
SoapExtension [2], y nos permitirá tener
acceso a los mensajes SOAP que se intercambian entre cliente y servidor antes de
que éstos lleguen a su destino final. Podremos analizarlos, y si es necesario, modificarlos. Y por supuesto, es posible recha-
[WebMethod, A uthExtension(), SoapHeader(“Credenciales”)]
public string Consultar(string dni) {
return “Obtenidos los datos del cliente con dni “ + dni;
<<dotNetManía
Listado 2. El método Consultar del servicio Clientes
30
Como se puede apreciar, mediante
atributos del método estamos indicando
que éste se va a exponer a través de Web
(WebMethod) y que va a llevar asociada una
cabecera de nombre “Credenciales”. Esta
zar peticiones si lo que estamos recibiendo desde el cliente “no nos gusta”. Esta
clase, así como la clase A uthExtensionA ttribute que veremos a continuación, se
han definido dentro de WSBase por sim-
plificar, pero nada nos impide extraer este
código a una DLL independiente que
podríamos reutilizar en otros proyectos.
Al heredar de SOA PExtension tenemos
que sobrescribir cuatro métodos, aunque
sólo el código de uno de ellos no es trivial: el del método ProcessMessage. Este
método es llamado en cuatro ocasiones
distintas por el framework ASP.NET:
• Antes de deserializar el mensaje
SOAP XML recibido en un objeto
en el servidor (SoapMessageStage.BeforeDeserialize).
• Después de deserializar el mensaje
SOAP XML recibido en un objeto en
el servidor (SoapMessageStage.A fterDeserialize). Para analizar las cabeceras hay que actuar en este punto.
• Antes de serializar la respuesta en un
mensaje XML SOAP para su envío
al cliente (SoapMessageStage.BeforeSerialize).
• Después de serializar la respuesta en
un mensaje XML SOAP para su envío
al cliente (SoapMessageStage.A fterSerialize).
Como a nosotros en principio solo
nos interesa analizar los mensajes que
el cliente envía al servidor, nuestro código únicamente actuará en los dos primeros casos, tal y como se puede apreciar en el listado 3.
Cada vez que el método ProcessMessage sea llamado, tenemos que comprobar el estado en el que se encuentra el mensaje. Cuando estemos en el
paso BeforeDeserialize, que es el primero en producirse, poco podremos
hacer, puesto que el mensaje por ahora no es más que un flujo de bytes. Pero
en este momento podemos comprobar
al menos a qué método y servicio Web
se dirige la petición y, usando el método ValidarTamanoMensaje de la clase WSA uxiliar, validar el tamaño del mensaje
que estamos recibiendo. Si es exagerado para lo que se esperaba, lanzaremos
una excepción que abortará el resto del
proceso, ahorrando así al servidor la
tarea de deserializar el mensaje XML.
<< dnm.plataforma.net
public override void ProcessMessage(SoapMessage message)
{
WSRequestHeader h;
bool credencialesrecibidas = false;
string loginrecibido = “”;
// acciones que podemos realizar antes de deserializar el mensaje recibido
if (message.Stage == SoapMessageStage.BeforeDeserialize)
{
// comprobamos que el tamaño en KBytes del mensaje recibido no supera
// el máximo permitido para un método
try
{
WSA uxiliar.ValidarTamanoMensaje(message.MethodInfo.DeclaringType.Name,
message.MethodInfo.Name,
message.Stream.Length / 1024);
}
catch (Exception ex)
{
WSA uxiliar.GuardarEstadistica(message.MethodInfo.DeclaringType.Name,
message.MethodInfo.Name,
“info no disponible”,
‘D’,
HttpContext.Current.Request.ServerVariables[“REMOTE_A DDR”].ToString(),
ex.Message);
throw;
}
}
<<dotNetManía
// actuamos justo después de obtener el mensaje XML SOA P y deserializarlo
// en un objeto,imprescindible para poder tratar la cabecera
if (message.Stage == SoapMessageStage.A fterDeserialize)
{
foreach (SoapHeader header in message.Headers)
{
if (header is WSRequestHeader)
{
credencialesrecibidas = true;
h = (WSRequestHeader)header;
// validamos la petición
try
{
loginrecibido = h.login;
WSA uxiliar.ValidarUsuario(h.login, h.password);
32
// el usuario parece ok, vamos a comprobar si tiene acceso
// al método y servicio Web deseado.
WSA uxiliar.ValidarA cceso(HttpContext.Current.Request.
ServerVariables[“REMOTE_A DDR”].ToString(),
message.MethodInfo.DeclaringType.Name,
message.MethodInfo.Name,
h.login);
// lo tiene, guardamos estadísticas
WSA uxiliar.GuardarEstadistica(message.MethodInfo.DeclaringType.Name,
message.MethodInfo.Name,
h.login,
‘P’,
HttpContext.Current.Request.ServerVariables[“REMOTE_A DDR”].ToString(),“”);
}
catch (Exception ex)
{
Además de lanzar la excepción, registraremos el acceso en la tabla de
estadísticas. En este caso, como aún no
se ha procesado el mensaje SOAP, no
tendremos acceso al contenido de la
cabecera, y por tanto no podremos
saber qué usuario está realizando la
petición, de ahí que se registre como
login “info no disponible”.
Cuando estemos en el paso A fterDeserialize (el segundo del proceso),
lo primero que tendremos que hacer
es recorrer todas las cabeceras del
mensaje SOAP (podría haber más de
una), buscando aquella que tenga el
formato de nuestra clase WSRequestHeader. Si encontramos alguna, extraemos de ella tanto el login como la password del usuario, y procedemos a validarlos. En caso de que la validación
no se lleve a cabo con éxito, o si no se
han recibido las credenciales, se lanzará una excepción que abortará el
tratamiento del resto de la petición,
y se registrará el acceso “denegado”
en el log.
Una vez verificadas las credenciales, tendremos que ver si el usuario está
autorizado para utilizar el método/servicio Web al que se está llamando
(información que podemos obtener a
través de la propiedad MethodInfo de la
variable message que recibimos como
parámetro). Además, también será
necesario verificar si se supera el número de peticiones por unidad de tiempo
contratadas. De todo eso se encarga el
método ValidarA cceso de la clase WSA uxiliar, como vimos con anterioridad.
Si todo es correcto, permitiremos el
acceso, y anotaremos el acceso “permitido” en las estadísticas.
La clase AuthExtensionAttribute
Para poder hacer uso de la clase A uthExtension, tendremos que crear nuestro propio atributo de método, creando una nueva clase que herede de SoapExtensionA ttribute a la que llamaremos
A uthExtensionA ttribute (ver listado 4). En
<< dnm.plataforma.net
}
}
}
if (!credencialesrecibidas)
{
string msg =
“Toda llamada a método de servicio debe llevar las credenciales de usuario”;
WSA uxiliar.GuardarEstadistica(
message.MethodInfo.DeclaringType.Name,
message.MethodInfo.Name,
loginrecibido,
‘D’,
HttpContext.Current.Request.ServerVariables[“REMOTE_A DDR”].ToString(),
msg);
throw new Exception(msg);
}
// aquí podríamos hacer otras cosas, como guardar el mensaje recibido
// a modo de log para su futuro estudio
}
// antes de mandar el mensaje de vuelta al cliente
if (message.Stage == SoapMessageStage.BeforeSerialize)
{
// aquí podríamos por ejemplo guardar en un log cualquier excepción
// que haya ocurrido antes de devolvérsela al cliente,
// útil para ayudar en el soporte
}
}
Listado 3: Código del método ProcessMessage.
[A ttributeUsage(A ttributeTargets.Method)]
public class A uthExtensionA ttribute : SoapExtensionA ttribute
{
int _priority = 1;
public override int Priority
{
get { return _priority; }
set { _priority = value; }
}
public override Type ExtensionType
{
get { return typeof(A uthExtension); }
}
}
Listado 4: Clase AuthExtensionAttribute
ella solo tendremos que sobrescribir dos
propiedades. La primera indica la prioridad de la “extensión”, y se utiliza cuando se usan simultáneamente varios atributos de tipo SoapExtensionA ttribute,
para decidir con qué prioridad se procesan. La segunda simplemente hemos
de modificarla para que devuelva el tipo
de la clase que se encargará de procesar
los mensajes SOAP, en nuestro caso A uthExtension.
El servicio Web Clientes
Como hemos comentado con anterioridad, se trata de un servicio Web desarrollado a modo de ejemplo para poder probar el mecanismo de control de acceso
que hemos creado. Contiene dos métodos muy sencillos en su implementación.
Por supuesto, ambos métodos, así como
el servicio Web que los aloja, han sido
dados de alta en la base de datos, que
como hemos visto es el primer paso a
afrontar a la hora de poder definir los controles de acceso. La única particularidad
a destacar es que el método Borrar lo consideramos especialmente peligroso, y por
eso por defecto todos los usuarios tienen
el permiso de acceso a él denegado, siendo necesario establecer explícitamente
que un usuario determinado tiene acceso al mismo.
Como último señalamiento, volvamos a estudiar el método Consultar (ver
listado 2). Como se puede apreciar, hay
un tercer atributo en la definición del
método que antes pasamos por alto: A uthExtension. Como habréis podido deducir, este atributo indica que toda llamada que se haga a dicho método va a
ser "supervisada" por la clase A uthExtension, tal y como vimos con anterioridad. Si no se especificasen estos tres
atributos, todo nuestro trabajo no serviría para nada. Por tanto, es muy
importante no olvidar añadir a cada
método de cada servicio Web los tres
atributos (salvo que por algún motivo
queramos que alguno de nuestros métodos no esté supervisado).
<<dotNetManía
// guardamos en log el acceso denegado al método/servicio
WSA uxiliar.GuardarEstadistica(message.MethodInfo.DeclaringType.Name,
message.MethodInfo.Name,
h.login,
‘D’,
HttpContext.Current.Request.ServerVariables[“REMOTE_A DDR”].ToString(),
ex.Message);
throw;
33
<< dnm.plataforma.net
Figura 3. Página de ejemplo
Figura 4. Excepción por falta de permisos
Consultar y otro al método Borrar ,
mientras que el tercero llamará al
método Consultar, pero con una peculiaridad: construiremos a mano el
mensaje XML, al que le meteremos
mucha “morralla” y lo enviaremos
mediante una petición HTTP POST,
ignorando por tanto el proxy que
Visual Studio ha generado a partir del
WSDL. La idea es simular un supuesto ataque de un usuario malintencionado.
El código que se ejecuta al pulsar
sobre el primer botón se muestra en
el listado 5. En él se aprecia en primer lugar como se crean sendos objetos que representan al proxy creado a
partir del WSDL y a las credenciales
de usuario. A continuación, rellenamos las credenciales, que son asignadas a la propiedad WSRequestHeaderValue del proxy. Y por último, llamamos
al método Consultar. Puesto que las
credenciales se asignan al proxy, esto
significa que solo tenemos que proporcionarlas una vez, pudiendo hacer
tantas llamadas a los métodos como
queramos, ya que en todas y cada una
de las peticiones se incluirá automáticamente la cabecera en los mensajes SOAP.
El código que se ejecuta al pulsar
el botón "Borrar" es análogo al del listado 5, mientras que el código del
botón "Enviar mensaje XML gigante"
es algo más complejo, pero tampoco
nada del otro mundo. En la figura 4 se
muestra la situación de error que se
<<dotNetManía
Las pruebas
34
Una vez presentados los principios
generales del desarrollo, pasemos a
realizar algunas pruebas. Para ello se
incluye en el proyecto una página
Web muy simple que hace uso del servicio Clientes. La interfaz de usuario
es muy sencilla y tan solo contiene
tres botones (ver figura 3). Uno de
ellos servirá para invocar al método
WSClientes.Clientes ws = new WSClientes.Clientes();
WSClientes.WSRequestHeader credenciales = new WSClientes.WSRequestHeader();
credenciales.login = “ejemplo”;
credenciales.password = “ejemplo1”;
ws.WSRequestHeaderValue = credenciales;
Label1.Text = ws.Consultar(“12345678z”)
Listado 5: Ejemplo de llamada al servicio Web
<< dnm.plataforma.net
produce por falta de permisos. De forma similar, nuestro sistema reaccionará ante la falta de credenciales, un
mensaje XML de tamaño excesivo o la
superación del límite de 5 peticiones
por hora que hemos establecido.
Conclusión
Figura 5. Excepción si no se introducen credenciales
Figura 6. Excepción por tamaño máximo superado
Con poco esfuerzo, hemos creado un
sistema que nos permitirá tener mayor
control sobre quién y cómo accede a
nuestra plataforma de servicios Web.
Además, como el sistema está basado
únicamente en base de datos, no es
necesario tener el control del servidor
para poder utilizarlo, lo que puede venir
muy bien de cara a instalaciones en hostings compartidos.
Por supuesto, el sistema admite
múltiples ampliaciones. Por ejemplo,
podríamos guardar un log de todos los
mensajes SOAP que nos llegan para
poder ayudar a nuestros clientes con
sus desarrollos (no todo el mundo usa
herramientas avanzadas, y a veces es
de gran ayuda ver qué datos estamos
recibiendo en “bruto”). O podríamos
almacenar en la base de datos todas
las excepciones que se produzcan en
la plataforma, junto con información
adicional que nos permita depurar
errores. En fin, que hay muchas posibilidades a explorar, para las que tan
solo se necesita tener algo de tiempo
y de imaginación.
Bibliografía
[ 1 ] http://msdn.microsoft.com/es-
Figura 7. Excepción por ancho de banda
[ 2]
http://msdn.microsoft.com/enus/library/system.web.services.pro
tocols.soapextension.aspx
[ 3]
Prosise, Jeff. “Build Secure Web
Services With SOAP Headers and
Extensions”, en http://www.developer.com/net/net/article.php/11087
_2192901_1.
<<dotNetManía
es/library/system.web.services.pro
tocols.soapheader(VS.80).aspx
35
Silverlight
Marino Posadas
Silverlight 2.0 Toolkit
Controles, visualización de datos y mucho más (I)
En paralelo con la presentación de la versión final de Silverlight 2.0, se anunciaba
en las webs “oficiales” de la plataforma la intención de mejorar el desarrollo
mediante la publicación paulatina de nuevos controles y herramientas que potencien las posibilidades de creación de aplicaciones RIA con Silverlight, al tiempo
que se anticipaban algunas características de la versión 3.0, que según Scott Guthrie estará disponible a finales de 2009.Vamos a revisar aquí algunas de las posibilidades que ofrece el último paquete de herramientas, publicado a primeros del
pasado mes de diciembre.
Marino Posadas es redactor jefe de dotNetMania y
Software Arquitect de
Alhambra-Eidos. Es MCP,
MCSD, MCAD, MCT y
MVP en Visual C#.
Puede consultar su página
Web en
www.elavefenix.net
El sitio oficial de descarga de los nuevos controles y herramientas para Silverlight es Codeplex (www.codeplex.com/silverlight), y es ahí donde el lector podrá encontrar el último paquete
de herramientas y controles que complementa
a las ya incluidas con el SDK del producto, y
que se distribuyen bajo licencia pública de
Microsoft (Ms-PL). Todo el código fuente está
disponible en uno de los paquetes descargables,
junto con ejemplos de cada elemento y característica soportada, y un ejemplo genérico “Sample Explorer”, que muestra en una sola página
todos los elementos nuevos. En resumen, el
paquete de diciembre de 2008 ofrece las siguientes novedades:
• Controles: nuevos controles de IU que podemos dividir en dos clases, dependiendo de su
grado de madurez: los que están considerados
como estables (stable), y los que están a un paso
de esa calificación (preview).
o En el primer grupo se encuentran A utoCompleteBox, DockPanel, HeaderedContentControl, HeaderedItemsControl, Label, NumericUpDown, TreeView y WrapPanel.
o Y en el segundo: Expander, ImplicitStyleManager y ViewBox.
• Charting: control para la visualización gráfica de conjuntos de datos. Aunque se trata igualmente de un control, su complejidad y posibilidades hacen que merezca un estudio aparte.
• Temas: soporte para temas (themes) al estilo de
ASP.NET, donde se incluye media docena de
temas de ejemplo. La clase ImplicitStyleManager se relaciona directamente con esta funcionalidad.
• Automatización (Automation Peer): soporte
para automatización de elementos de la interfaz de usuario. Especialmente interesante para
la construcción de sitios accesibles.
Desafortunadamente (en palabras del divulgador oficial de la tecnología, Jesse Liberty), la calidad del contenido de este kit de herramientas no
corre pareja con los materiales didácticos que nos
permitan aprender su funcionamiento e incorporarlo con rapidez a nuestras aplicaciones. Aparte
del fichero .chm de ayuda del SDK, lo más interesante que se incorporó en esta versión fue la solución global con ejemplos que muestran todos los
controles, junto a características de visualización
de datos y soporte de temas en una sola aplicación,
con acceso directo al código fuente en XAML/C#.
<< dnm.dnm.plataforma.net
El propio Liberty, no obstante reconocer esta situación, ha publicado ya dos vídeos explicativos del kit y
continuará con la labor de divulgación de estas novedades (ver el sitio http://silverlight.net/blogs/
La recomendación oficial es que no se utilicen más
que los controles de categoría estable para labores de
producción (y, según qué escenarios, habría que esperar a que alcanzaran la categoría de “maduros”).
jesseliberty/archive/2008/12/08/a-complex-homefor-very-some-simple-toollkit-examples.aspx).
Controles en estado preview
Nosotros vamos a presentar los fundamentos del funcionamiento de este kit y sus herramientas asociadas,
centrándonos solamente en el código fundamental de
los elementos estables, y explicando las bases del charting y el uso de temas.
Comenzamos presentando los controles actualmente en estado preview, citando simplemente su funcionalidad (sin ejemplos de código).
Expander
Controles
Antes de nada, hay que decir que si el lector quiere
probar este kit tal y como se hace con el resto de controles, desde Visual Studio, recuerde que deberá hacer
referencia a la librería que los contiene ( Microsoft.Windows.Controls.dll), que encontrará en el
directorio /binaries del paquete descargable, una vez
descomprimido éste. Nótese la diferencia de nomenclatura de la DLL con respecto a la del paquete “estándar” (System.Windows.Controls). Además, la librería
Microsoft.Windows.Controls.Input contiene el elemento NumericUpDown, así como clases base para la
construcción de elementos similares. Una vez hecho
esto, en el Cuadro de herramientas de Visual Studio
2008 aparecerán 10 elementos nuevos, tal y como se
ve en la figura 1.
Ya presente en Windows Presentation Foundation, es un control que
muestra una cabecera con
(o sin) un rótulo descriptivo, y un glifo que permite
desplegar y colapsar una
ventana en su parte inferior. Se debe tener cuidado en
el diseño para controlar la superficie que se muestra
respecto a otros controles de la interfaz.
ViewBox
Define un decorador de contenido,
que puede cambiar el tamaño y escalar
un único elemento interno hasta rellenar el espacio disponible. También está
disponible en WPF.
ImplicitStyleManager
No es un control propiamente dicho, sino una clase
sin interfaz de usuario propia que permite encapsular un
comportamiento visual que propaga sus estilos a un conjunto de controles. Está vinculado con el funcionamiento de los temas, y una de sus enormes ventajas es la posibilidad de almacenar separadamente conjuntos de estilos (en una DLL, por ejemplo), y poder aplicarla después
a distintos elementos de una interfaz dada. Hablaremos
con detalle de su funcionamiento y programación en el
próximo artículo, dedicado a los gráficos empresariales.
En realidad, esto es solo una pequeña parte del
paquete; un vistazo al Examinador de objetos nos mostrará que hay otros controles que no aparecen en la
lista, bien porque sirven para la construcción de otros,
bien porque no tienen una interfaz visual propia,
debiendo ser ésta definida por el usuario (como ButtonSpinner).
Controles (en estado stable)
A utoCompleteBox
Representa un control similar
al ComboBox, pero que permite la
búsqueda incremental en los elementos de la lista desplegable
<<dotNetManía
Figura 1
37
<< dnm.plataforma.net
según se van introduciendo datos en el control. La
propiedad que activa/desactiva las características de
búsqueda es IsTextCompletionEnabled, de tipo bool, activada de forma predeterminada. Para el ejemplo de la
figura, el código sería el siguiente:
XA ML
<controls:A utoCompleteBox Width=”120” Height=”25”
x:Name=”CajaA utoCompletar” />
C#
CajaA utoCompletar.ItemsSource = new String[] {
{ “Pedro”, “Perico”, “Petronio”, “Patricio” };
XA ML
<controls:HeaderedItemsControl
x:Name=”CajaHeaderItems”>
<controls:HeaderedItemsControl.Header>
<Image Source=”Imagenes/s18.jpg” />
</controls:HeaderedItemsControl.Header>
<controls:HeaderedItemsControl.ItemTemplate>
<DataTemplate>
<Border Background=”Beige” Width=”200”
HorizontalA lignment=”Left”>
<TextBlock Text=”{Binding}“
Margin=”10,0,0,0” />
</Border>
</DataTemplate>
</controls:HeaderedItemsControl.ItemTemplate>
</controls:HeaderedItemsControl>
HeaderedContentControl
Representa la clase base para
todos los controles que tienen
una propiedad Content y una
cabecera (contrapartida de HeaderedItemsControl, que veremos
a continuación). Es muy sencillo de utilizar y programar. Para ver su esencia, basta con el siguiente código XAML, que produce por
pantalla la imagen que acompaña estas líneas:
XA ML
<controls:HeaderedContentControl>
<controls:HeaderedContentControl.Header>
<Image Source=”Imagenes/s18.jpg” />
</controls:HeaderedContentControl.Header>
<controls:HeaderedContentControl.Content>
<TextBlock Text=”Figura 1: Tablero clásico”
FontFamily=”A rial” FontSize=”18” />
</controls:HeaderedContentControl.Content>
</controls:HeaderedContentControl>
<<dotNetManía
HeaderedItemsControl
38
Representa la clase base para
todos los controles que tienen
una propiedad ItemsControl y
una cabecera. En este ejemplo,
la propiedad utilizada para mostrar los contenidos simplemente define una plantilla para cada
ítem de la lista (propiedad ItemTemplate). Esa plantilla va necesariamente dentro de
un elemento <DataTemplate>, que admite cualquier
conjunto válido de controles. La asociación de los
datos a mostrar se realiza mediante databinding, como
puede verse en el código adjunto:
C#
CajaHeaderItems.ItemsSource = new String[]
{“1. d4, d6”,“2. Cf3, Cc6”, “3. A b5, A d2”, “4. ...”};
Label
En principio, este control
está pensado para completar las
posibilidades de TextBlock, respecto a la inclusión de otros elementos. Podemos construir etiquetas de texto con bordes, fondos, figuras laterales o en background, etc. Muy útil para utilizar como ítem de otros
elementos colectivos como cuadros combinados (combo boxes) y similares. Por ejemplo:
<controls:Label
BorderBrush=”Navy” BorderThickness=”5”
Foreground=”Maroon” Background=”A quamarine”
VerticalA lignment=”Center” Width=”150”
HorizontalA lignment=”Center”>
<StackPanel>
<Image Source=”Imagenes/s18.jpg” />
<TextBlock Text=”Partidas famosas” />
</StackPanel>
</controls:Label>
NumericUpDown
Es la versión de su homónimo de Windows Forms y WPF,
solo que permite una gran cantidad de configuraciones visuales, y además soporta la confección de estilos personalizados a través de su atributo
SpinnerStyle, al que se le puede asignar cualquier esti-
<< dnm.dnm.plataforma.net
lo definido por el usuario. El código siguiente ejemplifica su utilización:
<input:NumericUpDown
BorderBrush=”Navy” BorderThickness=”3”
Foreground=”Red” Height=”27”
FontSize=”18” FontWeight=”Bold”
Maximum=”12” Minimum=”1” DecimalPlaces=”1”
UseLayoutRounding=”True“ Value=”3” />
TreeView
los controles de Windows Forms) permite ubicar contenidos ligándolos a uno de los bordes (o todos) de su
contenedor. El segundo va situando los contenidos en
una secuencia mientras caben en pantalla, y continúa en
filaso columnas sucesivas si el contenido no cabe en el
contenedor. En el ejemplo de la siguiente figura, todos
los elementos están contenidos en un DockPanel, pero el
TreeView superior tiene asignada su propiedad adjunta
de anclaje a Top, por lo que permanece en la parte superior. Por su parte, los tres Label de la parte inferior (el
último, truncado en su salida) están incluidos dentro de
un elemento WrapPanel con valores predeterminados de
sus propiedades.
Situación similar a la
anterior, en cuanto a la funcionalidad, la capacidad de
configuración visual y la
posibilidad de persona lización del control. Admite innumerables niveles de
anidación, y cada elemento
TreeViewItem puede contener cualquier otro, con lo
que es posible la personalización a cualquier nivel,
modificando el atributo predeterminado ItemTemplate. Dispone igualmente de las propiedades de enlace a datos DataContext e ItemsSource. La figura
adjunta se corresponde con el código siguiente:
DockPanel y WrapPanel
Se trata de los dos controles contenedores que faltaban con respecto a la oferta de WPF. El primero de
ellos (recuérdese la propiedad con objetivo similar en
El código significativo que produce esta salida es:
<controls:DockPanel Width=”300” Height=”350” Background=”Blue”>
<controls:TreeView controls:DockPanel.Dock=”Top”
Background=”A ntiqueWhite” Width=”170” Height=”180” >
<controls:TreeViewItem [...]> </controls:TreeViewItem>
<controls:TreeViewItem [...]> </controls:TreeViewItem>
<controls:TreeViewItem [...]> </controls:TreeViewItem>
</controls:TreeView>
<controls:WrapPanel>
<controls:Label [...]> </controls:Label>
<controls:Label [...]> </controls:Label>
<controls:Label [...]> </controls:Label>
</controls:WrapPanel>
</controls:DockPanel>
Conclusión
Una vez presentados los controles, en la siguiente entrega de este repaso sobre Silverlight Toolkit
revisaremos los controles de charting para la representación de gráficos empresariales, el funcionamiento
de los temas y algunas peculiaridades de los procesos
de depuración y automatización.
<<dotNetManía
<controls:TreeView Background=”A ntiqueWhite”>
<controls:TreeViewItem IsExpanded=”True”
Header=”A pertura española”>
<controls:TreeViewItem IsExpanded=”True”
Header=”Variante Ruy López”>
<controls:TreeViewItem
Header=”1. d4, d6” />
</controls:TreeViewItem>
</controls:TreeViewItem>
<controls:TreeViewItem IsExpanded=”False”
Header=”Defensa siciliana”>
<controls:TreeViewItem Header=”1. d4, Cf6” />
</controls:TreeViewItem>
<controls:TreeViewItem IsExpanded=”True”
Header=”Defensa Grünfeld”>
<controls:TreeViewItem Header=”1. d4, Cf6” />
<controls:TreeViewItem Header=”1. c4, g6”
Background=”Navy”
Foreground=”Yellow” />
</controls:TreeViewItem>
</controls:TreeView>
39
SQL Server
dnm.servidores.sql
Francisco González
Agregando inteligencia a mis aplicaciones mediante
SQL Server Data Mining
La minería de datos se puede utilizar para analizar información y realizar
predicciones. En este artículo voy a ilustrar el uso de la minería de datos
en una aplicación Web.Vamos a tomar los datos de venta de un portal Web
y cierta información de nuestros clientes para analizar qué productos ofrecer a determinados perfiles de clientes, realizar campañas publicitarias u
ofrecer productos que sean comprados conjuntamente cuando un cliente agrega un producto a la cesta de la compra.
Francisco González es
es Data Platform
Architect del área de
Business Intelligence
en Solid Quality Mentors. Francisco es
ponente habitual en
eventos como BI
Conference o Tech-Ed
USA y un enamorado de la minería de
datos.
La minería de datos es la ciencia de extraer información no trivial de conjuntos de datos; éstos pueden ocupar desde varios “megas” hasta varios “teras”.
Dependiendo de la técnica que usemos, necesitaremos que el conjunto sea mayor o menor, aunque en
muchos de los casos no es tan importante el tamaño
como que los datos sean lo suficientemente representativos de lo que queremos analizar para poder
más tarde realizar predicciones.
Básicamente, cuando realizamos minería de
datos lo primero que tenemos que hacer es limpiar
los datos, para que éstos no tengan errores y no
haya ambigüedades en códigos y demás. Una vez
tenemos listos los datos, creamos una estructura
donde elegimos el algoritmo de minería que vamos
a utilizar, los atributos que seleccionamos para generar el modelo y los atributos que queremos predecir. Una vez construida la estructura, la procesamos junto con los datos, obteniendo un modelo.
Un modelo es un conjunto de reglas que nos permiten realizar predicciones. Una vez que tenemos
el modelo generado, podemos hacer consultas a
dicho modelo mediante el lenguaje de consultas de
minería de datos de SQL Server. Este lenguaje se
denomina Data Mining Extensions (DMX). A
través de ADODM (esto es, ADO para Minería de
datos), podemos conectarnos al servidor de Analysis Services donde se encuentran alojados los
modelos y ejecutar consultas expresadas en dicho
lenguaje; normalmente, éstas las realizamos ya desde nuestras aplicaciones o portales Web, implementadas en código C# o Visual Basic.
Figura 1. Proceso de minería de datos
El hecho de que haya elegido un portal de una
tienda en Internet no es casualidad. Tenemos que
pensar que cuando utilizamos minería de datos estamos realizando predicciones, y éstas se basan en
modelos estadísticos que en la mayoría de los casos
darán resultados correctos, pero en otros no. Es
decir, cuando hacemos predicciones estamos inven-
<< dnm.servidores.sql
Minería en nuestra tienda
on-line
A través de una serie de ejemplos,
vamos a explorar qué nos ofrece la
minería de datos mediante SQL Server para mejorar las ventas de nuestro
portal Web. Es conocido por todos que
un buen diseño de una página Web
hace que los clientes vuelvan una y otra
vez; mediante minería, vamos a ser
capaces de ofrecer a nuestros clientes
esos productos que están predispuestos
a comprar, o quizás justo al revés, esos
productos que nunca buscarían y quizás
si se los mostramos en un primer plano accedan a comprar, puesto que los
productos que el cliente está predispuesto a comprar van a ser buscados
por él inmediatamente.
Minería para nuestros banners o anuncios
Un banner es un medio publicitario dentro de nuestra Web que se ofrece al
cliente en las propias páginas. ¿Cómo
seleccionamos el banner a utilizar en
cada página? Pues por lo general cambiamos los banners en el tiempo siguiendo reglas de marketing, o exponiendo
los nuevos productos o los productos
estrella de nuestra tienda. Ahora, gracias a la minería de datos, podemos ir
más allá. Cuando un usuario se conecta a nuestra Web, en muchos casos se
identifica; una vez que el usuario se ha
registrado, ya sabemos quién es, pues
quizás cuando se dio de alta nos facilitó
datos como edad, sexo, ciudad, salario,
número de hijos, número de coches,
intereses, etc. Además, quizás haya comprado en nuestro portal anteriormente,
con lo que ya tenemos suficiente información para ofrecer a nuestros clientes
una campaña publicitaria eficiente.
Podemos utilizar algoritmos como el de
árboles de decisión para analizar qué
productos son comprados por el perfil
que acaba de entrar en la Web. De esta
forma, si un tipo de cliente suele comprar ciertos productos, lo que hacemos
es utilizar la información que tenemos
del cliente para determinar qué productos ofrecer en nuestros banners. Así
cuando el cliente se registra en el portal ya le aparecen banners con los pro-
ductos que el modelo ha estimado que
podría comprar. Además, podemos elegir que solo se le ofrezcan productos
que no ha comprado todavía, gracias a
que tenemos su historial de compras.
Para ofrecer esta solución, realizaríamos los siguientes pasos: utilizaríamos los datos de compra de todos nuestros clientes para crear un modelo
mediante el algoritmo de reglas de
decisión que nos estime la probabilidad
de compra, con respecto a los atributos
del cliente y de los productos de nuestro catálogo. Una vez que tenemos el
modelo generado, debemos realizar una
consulta desde la página Web al modelo, para que nos ofrezca los productos
con mayor probabilidad de compra para
el cliente que está accediendo a nuestra
Web. Descartamos los productos que ya
han sido comprados por el cliente; en
algunos casos es lógico que no vuelva a
comprar un determinado producto que
ya ha comprado anteriormente. Cuando sabemos el producto que queremos
publicitar, accedemos a la base de datos
de banners para obtener el banner y mostrarlo en pantalla.
En la figura 2 se muestra la red de
dependencia de los atributos de un
modelo construido para predecir si un
cliente es comprador de bicicletas o no.
Este diagrama nos indica qué atributos son más determinantes a la hora de
que un cliente compre una determinada bicicleta.
Figura 2. Diagrama de dependencia de atributos
<<dotNetManía
tando, estamos tratando de deducir cuál
va a ser la conducta de un usuario, o
qué tipo de clientes compran determinados productos; esto significa que el
resultado de una predicción puede ser
erróneo.
En un modelo de minería de datos,
llamamos fiabilidad al grado de seguridad en que las predicciones van a ser
correctas. Una de las técnicas que utilizamos para saber cuál es la fiabilidad de
un modelo generado es probarlo con
datos que no han sido utilizados para
generar dicho modelo. Un ejemplo de
esta técnica es el siguiente: utilizamos el
80% de los datos para generar el modelo; una vez generado éste, usamos el 20%
restante para realizar predicciones y
comprobamos si cada predicción ha sido
realizada con éxito o no. Teniendo el
número de veces que el modelo ha acertado y el número total de casos, podemos sacar un porcentaje; en este caso,
hemos supuesto que los datos contienen
el resultado del valor que vamos a predecir. Los datos para este ejemplo
podrían haber sido el perfil de clientes
y si compraron un determinado producto o no, de forma que, utilizando el
modelo, podríamos predecir si el producto será comprado en base a atributos como edad, sexo, número de hijos,
número de coches, sueldo, distancia al
trabajo, localización, etc.
41
<< dnm.servidores.sql
El código del listado 1 ilustra el lenguaje DMX para realizar consultas a un
modelo. Éste es el código que utilizaríamos para realizar una predicción
cuando un determinado cliente se
conecta a nuestra tienda online. La
siguiente consulta nos devuelve una probabilidad ajustada acerca de si el cliente en particular, para el cual hemos
introducido los datos en este ejemplo,
compraría una bicicleta o no.
una última pregunta que es si comprarían este nuevo producto. Nuestro
objetivo, en este primer paso, es obtener una población representativa de
todos nuestros tipos de clientes para
ofrecerles la encuesta; para ello, utilizamos el algoritmo de clusters que nos
define distintos grupos de clientes. De
esta forma, elegimos clientes de cada
grupo para realizar el sondeo, teniendo entonces clientes de cada uno de los
SELECT
[v Target Mail].[Bike Buyer],
PredictA djustedProbability([v Target Mail].[Bike Buyer])
FROM
[v Target Mail]
NA TURA L PREDICTION JOIN
(SELECT 25 A S [A ge],
‘02/02/1978 0:00:00’ A S [Birth Date],
‘2-5 Miles’ A S [Commute Distance],
‘High School’ A S [English Education],
‘S’ A S [Marital Status],
2 A S [Number Cars Owned],
3 A S [Number Children A t Home],
30000 A S [Yearly Income]) A S t
Listado 1. Ejemplo de consulta DMX
<<dotNetManía
Minería para nuestra campaña
de publicidad postal
42
Imaginemos ahora que acaba de entrar
un producto nuevo en nuestro stock y
disponemos de un presupuesto ajustado para realizar una campaña publicitaria, en la que vamos a enviar correo
postal con información sobre dicho
producto. En nuestra base de datos
tenemos registrados 100.000 clientes,
pero solo podemos enviar cartas a
25.000. ¿A cuáles de nuestros clientes
enviamos las cartas publicitarias? Para
contestar esta pregunta, vamos a utilizar minería de datos. Lo primero que
vamos a hacer es preguntar a nuestros
clientes acerca de si comprarían ese
producto o no. Para ello, realizamos
una encuesta donde básicamente obtenemos de nuevo la información que
tenemos en el registro de clientes, más
grupos de perfiles de nuestros clientes.
En la figura 3 se muestra el diagrama
de clusters que genera la ejecución del
modelo.
Una vez que hemos realizado la
encuesta, tenemos una fuente de datos
que nos sugiere qué clientes comprarían
dicho producto. Estos datos los utilizamos para crear un nuevo modelo donde lo que hacemos es predecir si el producto va a ser comprado o no de acuerdo a los atributos del cliente; generado
dicho modelo, podemos ejecutarlo para
cada uno de nuestros clientes en la base
de datos, seleccionando los 25.000 que
tienen una probabilidad mayor de compra. De esta manera, enviamos nuestra
publicidad a aquellos clientes con una
mayor predisposición de compra, obteniendo quizás (pues no olvidemos que
nos estamos basando en predicciones)
un mayor retorno de la inversión.
Minería para cesta conjunta
Cuando un cliente inserta un producto
en el carrito de la compra, podemos
ofrecerle productos relacionados o que
suelen comprarse conjuntamente con el
ya elegido. Es muy probable que si compramos cuchillas de afeitar, compremos
también espuma y bálsamo. Vamos a
ilustrar aún más este ejemplo: una conocida cadena de productos alimenticios
hizo un estudio, en el cual concluyó que
en un alto porcentaje de casos cuando
se compraban pañales también se compraba cerveza. Sin entrar en detalles de
Figura 3. Diagrama de clusters
<< dnm.servidores.sql
por qué esto sucede, lo que sí es cierto es que algunos productos se compran frecuentemente de manera conjunta, por lo que ofrecer al cliente, justo después de introducir un producto en la cesta de la compra, productos que suelen comprarse conjuntamente con éste, mejora la experiencia del comprador e
incrementa las ventas de nuestro portal. Vamos a utilizar minería de datos para realizar dicha tarea. En
primer lugar, disponemos del historial de compra de
cada cliente cada vez que ha visitado nuestra tienda,
por lo que disponemos de listas de productos que se
han comprado a la vez. Ésta va a ser nuestra fuente
de datos. Para obtener un modelo de estas características, utilizamos el algoritmo de reglas de asociación. Este algoritmo recibe como entrada una lista de productos y nos devuelve la probabilidad de
cada uno de los productos que son comprados conjuntamente. De forma que, cuando un producto es
añadido a la cesta de la compra, hacemos una consulta al modelo para que nos devuelva, por ejemplo,
los dos productos que tienen una probabilidad mayor
de ser comprados conjuntamente con ése, y se los
ofrecemos al cliente. Cuando el cliente añade otro
producto a la cesta, volvemos a consultar el modelo;
pero esta vez le pasamos los dos productos que acaba de añadir, de manera que el modelo nos devuelva
productos que se han comprado conjuntamente con
respecto a la lista total de productos en el carrito de
la compra.
En la figura 4 podemos observar el conjunto de
reglas que el algoritmo de reglas de asociación genera. Como vemos, las reglas contienen listas de pro-
SQL Server nos provee una
plataforma robusta para el
desarrollo de aplicaciones
inteligentes
ductos que ya han sido añadidos a la cesta de la compra y la probabilidad de que un producto nuevo sea
comprado conjuntamente con ellos.
Ciclo de vida de un desarrollo de minería
de datos
Debido a que continuamente podemos estar agregando nuevos productos a la tienda y en nuestra Web
se están procesando compras continuamente, nuestros modelos pueden fácilmente quedar desactualizados en poco tiempo. Por ello, es necesario que
apliquemos una política de actualización de los modelos en el tiempo. Una de las formas más elegantes y
productivas de realizar dicho proceso es mediante
SQL Server Integration Services. Gracias a SSIS,
podemos generar un proceso que reprocese los
modelos cada cierto intervalo de tiempo. SSIS nos
provee con tareas específicas de minería de datos.
De esta forma, podemos planificar mediante el
Agente de SQL Server la actualización de nuestros
modelos en el tiempo, obteniendo así predicciones
ajustadas a los datos actuales y no quedando nuestros modelos desfasados.
Figura 4. Probabilidades de compra conjunta mediante el
algoritmo de reglas de asociación
Los portales Web son uno de los tipos de negocios
que mejor están acogiendo la minería de datos. Esto
es debido a que, por ejemplo, en la gestión “tradicional” de publicidad no había ninguna forma de elegir un mejor banner para un determinado cliente.
Simplemente se elegía uno al azar de entre el conjunto de banners disponibles. Al utilizar minería de
datos, podemos enfocar la publicidad al cliente; pero
además, no incurrimos en riesgo alguno si nuestro
modelo falla, pues lo que teníamos sin minería era
una elección arbitraria. SQL Server nos provee una
plataforma robusta para el desarrollo de aplicaciones inteligentes.
<<dotNetManía
Conclusión
43
ALManía
Enric Forn
Personalizando
nuestras builds
En muchas ocasiones, en el momento en que generamos la versión de
nuestra aplicación nos dejamos el último ensamblado añadido, la modificación del fichero de configuración, o los PDB generados se encuentran en modo Debug. Team Foundation Build nos ayuda a simplificar
estas tareas, mejorando el versionado de nuestros proyectos.
Enric Forn es MCTS
Team Foundation Server. Actualmente, Enric
es consultor de Team
System en Raona.
A diferencia de otros productos, Microsoft Team
Foundation Server (TFS) permite una amplia configuración para la personalización y adecuación a
nuestro proceso de desarrollo. Este artículo nos
lleva a las entrañas mismas de Team Foundation
Build (puedes consultar información más detallada en http://tinyurl.com/66w39v). Team Foundation
Build (a partir de ahora, TFB) es una extensión de
TFS que se instala como un servicio. Se utiliza
para la compilación de aplicaciones e infinidad de
tareas relacionadas con la generación de una versión de una o varias soluciones. Algunas de las tareas que permite realizar son la generación de un
informe de la compilación, la revisión del código,
la publicación en servidores, entre otras.
Supongo que ya habréis leído el buen artículo de
Luis Fraile sobre TFB del ejemplar nº 50 de dotNetManía, y ya sabéis un poco como funciona.
La base de TFB es el fichero TFSBuild.proj. Este
fichero está en formato XML y contiene toda la
información necesaria para realizar el proceso de
generación (build). Por si alguien conoce el mundo del código abierto, viene a ser lo mismo que el
fichero build.xml de ANT. TFB ejecuta MSBuild,
que interpreta las tareas definidas en el fichero TFSBuild.proj. Microsoft Build Engine (MSBuild) es
la plataforma que utiliza Visual Studio para generar las soluciones (más información en http://tin-
yurl.com/6og6bo). Cuando TFB recibe una petición
de build, descarga el código definido en el entorno de trabajo (o workspace) y también el script de
build, para interpretarlo y ejecutar todas las tareas definidas.
Figura 1. Edición del fichero TFSBuild.proj
con Team Foundation Sidekicks
<< dnm.ALManía
Estructura básica
de TFSBuild.proj
Como ya he dicho anteriormente, en el
archivo TFSBuild.proj se recogen todas
las tareas a realizar para la construcción
de nuestra versión. Para conocerlo con
más detalle, vamos a dividirlo en tres
partes y comentar un poco las funciones de cada una de ellas:
• Definición general del build. En
esta sección encontramos la confi-
guración global, es decir, los parámetros que afectan a la ejecución
general del build: en qué agente se
ejecuta (un agente es la máquina donde se encuentra instalado el servicio
de TFB), los directorios de despliegue, si se ejecutan tests con su fichero de configuración, si se activa la
ejecución de análisis de código, entre
otros. Un ejemplo básico se presenta en el listado 1.
bas funcionales, y una versión
“Debug” específica para el desarrollo (listado 2).
• Destinos (targets). En esta parte es
donde se exprime realmente la
potencia de TFB, pues se pueden
realizar infinidad de tareas concretas para cubrir las necesidades de
nuestra compilación o despliegue.
MSBuild define un conjunto de targets que realizan un conjunto de
<Import Project=”$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\
Microsoft.TeamFoundation.Build.targets” />
<ProjectExtensions>
<Description>
</Description>
<BuildMachine>TEA MBUILD</BuildMachine>
</ProjectExtensions>
<PropertyGroup>
<TeamProject>Phoenix</TeamProject>
<BuildDirectoryPath>D:\Deploy</BuildDirectoryPath>
<DropLocation>\\TEA MBUILD\Deploy</DropLocation>
<RunTest>true</RunTest>
<RunCodeA nalysis>Never</RunCodeA nalysis>
<UpdateA ssociatedWorkItems>false</UpdateA ssociatedWorkItem>
<RunConfigFile>$(SolutionRoot)\Development\raona.teambuild.testrunconfig
</RunConfigFile>
</PropertyGroup>
Listado 1. Definición general del build
<ItemGroup>
<SolutionToBuild Include=”$(SolutionRoot)\Raona\project1.sln” />
<SolutionToBuild Include=”$(SolutionRoot)\Raona\project2.sln” />
</ItemGroup>
<ItemGroup>
<ConfigurationToBuild Include=”Release|A ny CPU”>
<FlavorToBuild>Release</FlavorToBuild>
<PlatformToBuild>A ny CPU</PlatformToBuild>
</ConfigurationToBuild>
</ItemGroup>
Listado 2. Configuración de la compilación
• Configuración de la compilación.
Aquí se definen cuáles son las soluciones que vamos a compilar y también las configuraciones. Se puede
dar el caso de que queramos generar
una versión “Release” para poder
desplegarla y realizar sobre ella prue-
tareas predefinidas (encontraréis
más información sobre la biblioteca de tareas predefinidas en
http://tinyurl.com/6acftf), y además
podemos definir nuestros propios
destinos. Un destino define el
momento en que él se ejecuta, y
<<dotNetManía
Para modificar las tareas a ejecutar de
una build, es necesario modificar el fichero TFSBuild.proj asociado a ella. En la versión 2005 de TFB, este fichero se encuentra ubicado en $/TeamBuildTypes dentro del
repositorio de control de código. En la
versión 2008, la ubicación de
TFSBuild.proj puede ser cualquiera; por
supuesto, siempre dentro del repositorio
del control de código fuente.
Antes de editar este fichero, es necesario desprotegerlo manualmente desde
el Explorador de control de código fuente (lo que se conoce como check-out). Si
editamos este fichero desde Visual Studio 2008 con SP1 instalado, el check-out
es automático. Una vez hemos modificado y validado el script de build, es
imprescindible proteger el fichero en el
repositorio de control de código fuente
(o lo que es lo mismo, hacer el check-in).
Para facilitar la edición de este
fichero, existen las Team Foundation
Sidekicks (puedes descargarlas en
http://tinyurl.com/623kf9). Son un conjunto de herramientas que, una vez instaladas, facilitan la administración de
un servidor de TFS. Entre las herramientas hay una nueva opción de menú
contextual, que aparece al hacer clic con
el botón derecho sobre nuestra definición de build (figura 1).
Como he comentado en el párrafo
anterior, siempre que queráis realizar
un cambio en el fichero TFSBuild.proj
debéis subirlo al control de código fuente de nuestro repositorio (check-in). Esto
hace que probar nuestras modificaciones sobre los scripts de build sea un poco
lento.
45
<< dnm.ALManía
puede contener múltiples tareas.
Todos los targets posibles se encuentran definidos en un fichero .targets ubicado en la máquina que hospeda el servicio de TFB. No es
aconsejable modificar este fichero,
ya que cualquier cambio afectaría a
todos los scripts de build que tengamos implementados (a no ser que
seamos usuarios muy experimentados). Para que podáis verlo de un
modo más gráfico, se presenta un
ejemplo en el listado 3.
la ejecución del build: justo antes o después de descargar el código (BeforeGet y
A fterGet), antes y después de compilar
(BeforeCompile, A fterCompile). Los targets
menos críticos para sobrescribir son Before* o A fter*, ya que no afectan a las tareas imprescindibles de ejecución de una
build. En cambio, es más crítico sobrescribir destinos como tareas como CoreGet
o CoreDropBuild, ya que puede afectar
negativamente a la ejecución de nuestro
build. Podéis consultar todos los targets
disponibles en http://tinyurl.com/6kczfg.
Un destino define el
momento en el que él se
ejecuta dentro del proceso
de build y puede contener
múltiples tareas
<ItemGroup>
<SourceFiles Include=”$(SolutionRoot)\Development\**” />
</ItemGroup>
<Target Name=”A fterDropBuild”>
<MakeDir Directories=”D:\TCompilacio\Development” />
<Copy SourceFiles=”@(SourceFiles)”
DestinationFolder=”D:\TCompilacio\%(RecursiveDir)” />
<Exec Command=”NET USE T: \\TEA MBUILD\TCompilacio “ />
</Target>
<<dotNetManía
Listado 3. Destinos del build
46
En el fragmento que se muestra en el
listado 3, extraído de un script de build,
podemos ver que éste se está ejecutando
en el destino A fterDropBuild, es decir, después de que TFB haya copiado todos los
ficheros de la compilación en el directorio de destino. En este momento, se realizan tres tareas: la primera es la creación
del directorio Development, mediante la
tarea MakeDir. La segunda tarea copia los
ficheros del destino definidos en el primer elemento y copia todo su contenido
en el directorio de destino. Además, realiza una copia recursiva de todos los ficheros y subdirectorios contenidos en la raíz.
Si eliminamos los “**” de la definición del
directorio de origen y también la parte
“%(RecursiveDir)” del directorio de destino, entonces solamente serían copiados
los ficheros. Por último, en la tercera tarea
se ejecuta un comando de consola. Esta
tarea es muy interesante, ya que si no
encontramos ninguna tarea predefinida
con la que llevar a cabo la acción que nos
interesa, seguramente encontraremos la
forma de ejecutarlo a través de la línea de
comandos.
Existen muchos targets que permiten
ejecutar tareas en cualquier momento de
Se puede dar el caso de que queramos modificar las acciones predefinidas de un destino. Por ejemplo, es
posible que queráis ejecutar un build
con una versión concreta de código
fuente. Una posibilidad de modificar
un target sin modificar el fichero .targets de la máquina de build es poner
el código en el propio script de build.
En el caso de la descarga del código
que acompaña a este artículo, se defi-
ne el destino CoreGet (listado 4). Con
este ejemplo, el build ejecutado no
descarga la última versión de código,
sino la versión etiquetada como
“MiBuild_20080419.7”. Aún así, para realizar este tipo de modificaciones, en
primer lugar, si podemos evitar sobrescribir targets nos evitaremos problemas. Pero si nuestras necesidades
requieren hacerlo, es importante tener
claro si ello afecta solamente a nuestro script de build o a todas las builds
ejecutadas en el servidor donde modifiquemos el target.
<Target Name=”CoreGet”
Condition=” ‘$(IsDesktopBuild)’!=’true’ “
DependsOnTargets=”$(CoreGetDependsOn)” >
<Get Condition=” ‘$(SkipGet)’!=’true’ “
Workspace=”$(WorkspaceName)”
Recursive=”$(RecursiveGet)”
Force=”$(ForceGet)”
Version=”$(VersionToGet)” />
</Target>
<PropertyGroup>
<VersionToGet>LMiBuild_20080419.7</VersionToGet>
</PropertyGroup>
Listado 4. Modificación de un target en el script de build
<< dnm.ALManía
Pero si todavía no encontráis la forma
de llevar a cabo la tarea que queréis realizar con las tareas predefinidas de
MSBuild, es posible implementar vuestra propia tarea personalizada en .NET
(podéis consultar MSDN en http://tinyurl.com/67d2yq). Vamos a crear una tarea
personalizada que simplemente necesita un parámetro que es la ruta de un
fichero plano. La tarea escribe un texto en el fichero y lo almacena. Tenemos
dos opciones:
• Implementar directamente la interfaz
ITask sobre nuestra clase. ITask está
implementada en Microsoft.Build.Framework.dll.
• Derivar nuestra clase de la clase auxiliar Task (que encontraréis en Microsoft.Build.Utilities.dll). Esta clase
implementa la interfaz anterior, y
además proporciona implementaciones por defecto de algunos de los
métodos de ITask.
En el método Execute, que tendremos que sobrescribir, es donde se implementa el código que queremos ejecutar.
Este método no necesita parámetros, y
debe devolver true si la tarea se ejecuta
correctamente, o false en caso contrario. En nuestro ejemplo (listado 5), y por
comodidad, utilizamos la clase Task.
Una vez hemos implementado el
código, será necesario configurar nuestro script de build como se muestra en
el listado 6, para que se realice correctamente la llamada. En la primera parte registramos la tarea de modo que el
script de build sea capaz de encontrar
la clase a ejecutar. Fijaros que no tie-
using
using
using
using
Microsoft.Build.Framework;
Microsoft.Build.Utilities;
System.IO;
System.Diagnostics;
namespace CustomTasks
{
public class HelloWorldTask : Task
{
private StreamWriter sw;
[Required]
protected string filename;
public string FileName
{
get { return filename; }
set { filename = value; }
}
public override bool Execute()
{
sw = new StreamWriter(Path.Combine(filename), true);
sw.WriteLine(“Hello World !!”);
sw.Flush();
sw.Close();
return true;
}
}
}
Listado 5. Código de la tarea personalizada
ne ruta; la razón es que la DLL compilada se encuentra en el control de
código fuente de nuestro repositorio,
justo en la misma carpeta donde se
encuentra nuestro script de build. Si
queréis probar este ejemplo, deberéis
añadir la DLL y realizar el check-in en
la carpeta donde se encuentra el fichero TFSBuild.proj. En la segunda parte,
solamente nos queda llamar la tarea en
el destino que nos interese, en este caso
justo después de compilar las soluciones. Este destino tiene la particulari-
<UsingTask TaskName=”CustomTasks.HelloWorkdTask”
A ssemblyFile=”HelloWorldTask.dll” />
<Target Name=”A fterCompile”>
<!—Deploy Phoenix Version—>
<HelloWorldTask FileName=” $(BinariesRoot)\HelloWorldFile.txt” />
</Target>
Listado 6. Llamada a la tarea personalizada
dad de que solamente se ejecuta si la
compilación de las soluciones se ha
realizado satisfactoriamente. Una
pequeña observación a hacer sobre la
llamada a la tarea es el paso por parámetro de la ruta del fichero. En una
tarea se pueden definir n parámetros,
eso sí, siempre como cadenas de caracteres. También comentar que la ruta
del fichero es relativa a la ubicación
de los ficheros compilados, lo que
indica la variable BinariesRoot. Además
de esta variable, existen muchas otras
que podéis encontrar en http://tinyurl.com/5l9947.
Compilación de proyectos de
Visual Basic 6.0
En algunos de nuestros proyectos conviven aplicaciones desarrolladas en distintos lenguajes. Es por esta razón que en el
script de build implementado para nues-
<<dotNetManía
Crea tu propia tarea
personalizada
47
<< dnm.ALManía
tro proyecto se compilan varios proyectos de lenguajes diferentes: C#, C++ y
Visual Basic 6.0. Los proyectos de los dos
primeros lenguajes no tienen ningún problema en ser compilados por TFB. Sin
embargo, al intentar compilar Visual Basic
6.0, la compilación fallará. Es cierto que
podríamos compilar el proyecto directamente mediante un elemento <Exec>:
Ejecución de tests sin utilizar
los ficheros .vsmdi
Otra tarea muy importante es la ejecución de los tests unitarios para validar la compilación de nuestros proyectos. Solamente daremos como realizado satisfactoriamente el build si se
ejecutan correctamente los tests uni-
<Exec Command=”C:\Program Files\Microsoft Visual Studio\VB98\VB6.exe
/MA KE "C:\LogFile.vbp.log" "C:\Project.vbp"” />
Otra tarea muy importante
es la ejecución de los
tests unitarios para validar
la compilación de nuestros
proyectos
Listado 7
En mis scripts de build utilizo
mucho el comando Exec. Lo utilizo
para mapear unidades de red, registrar librerías DLL de COM, o ejecutar cualquier comando de la mítica
plataforma MS-DOS.
Otro método para compilar proyectos de Visual Basic 6.0 consiste en utilizar un target definido por FreeToDev (lo
encontraréis en la URL http://tinyurl.com/5t57jm). Con este target se pueden agrupar todos los proyectos de VB
6.0 a compilar. También es posible asignar una ruta de destino de los nuevos ejecutables. Primero, es necesario instalar el
target en la máquina que ejecuta TFB. A
continuación, añadimos la importación
del nuevo target, mediante el elemento
<Import> (listado 8). Finalmente, es necesario indicar los proyectos de Visual Basic
a compilar, definir el target Execute y ejecutarlo después de la compilación.
<RunConfigFile>$(SolutionRoot)\Common\Teambuild.testrunconfig</RunConfigFile>
<ItemGroup>
<TestContainerInOutput Condition=”’$(SolutionToBuild)’==’Raona’ “
Include=”Raona.UnitTest.dll” />
<TestContainer Include=”$(BinariesRoot)\Release\Raona.UnitTest.dll” />
</ItemGroup>
Listado 9. Ejecución de tests unitarios
tarios. Una pequeña personalización
que tenemos a nuestra disposición
consisten en ejecutarlos prescindiendo de los engorrosos ficheros .vsmdi
(más información en http://tinyurl.com/5uvgen). En la configuración
de las propiedades de la build, es necesario indicar la ruta del fichero TestRunConfig (listado 9). Y para indicar
cuál es la DLL que contiene los tests,
es necesario indicarlo al final del
script.
<<dotNetManía
<Import Project=”$(MSBuildExtensionsPath)\BuildVB6\FreeToDev.MSBuildTasks.tasks” />
<ItemGroup>
<ProjectsToBuild
Include=”$(SolutionRoot)\Core\DevelopmentCore\ComPhoenix\ComPhoenix.vbp”>
<OutDir>$(BinariesRoot)\Release</OutDir>
</ProjectsToBuild>
</ItemGroup>
48
<Target Name=”Execute”>
<BuildVB6 Projects=”@(ProjectsToBuild)” />
</Target>
<Target Name=”A fterCompile”>
<CallTarget Targets=”Execute” />
</Target>
Listado 8. Compilación de VB6 con FreeToDev
Si observáis con atención el código
del listado 9, veréis que existe una condición, ya que si compilas múltiples
soluciones en un mismo script, y cada
solución tiene su DLL con sus respectivos tests, TFB ejecutará todos los tests
para todas las DLL. De esta forma, conseguimos ejecutar los tests exactos para
cada solución.
Conclusión
En definitiva, si conocemos bien la
herramienta y tenemos claro cómo es
nuestro proceso de despliegue de las
aplicaciones, TFB nos ahorra tiempo
tanto en la construcción del paquete
de distribución de la aplicación, como
también en la supervisión de la calidad del código, ya sea con la ejecución de test unitarios o el análisis de
código. Cada vez más, la figura del
gestor de la configuración toma
mayor importancia en un equipo de
desarrolladores, ayudando a aumentar la velocidad y fiabilidad de despliegue de las aplicaciones, y también
mejorando la calidad del código desplegado.
Isla VB
Guillermo «Guille» Som
Visual Basic
¿lenguaje dinámico?
En la próxima versión de .NET Framework (la 4.0) se incluirá lo que se conoce como DLR (Dynamic Language Runtime), que viene a ser el motor de ejecución de los lenguajes dinámicos de .NET. De esa forma, se permitirá al CLR
(y por extensión a los lenguajes como VB y C#) el acceso de forma dinámica a los miembros de los objetos que haya en memoria, algo parecido a lo
que siempre se ha conocido como late binding... o casi...
Isla solidaria
Guillermo Som ingresará los derechos de autor de
este artículo en la cuenta de Ayuda a Juanma a vivir.
Desde aquí, invita a los lectores de esta isla solidaria para que hagan sus aportaciones o participen en
las subastas que se realizan desde la Web de Juanma para recaudar fondos con el fin de ayudar en la
investigación de una cura para la enfermedad de
Alexander. http://www.ayudajuanma.es.
Dinámico, estático, ¿cuál es la diferencia?
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”, “Visual Basic
2005”, "Novedades de
Visual Basic 9.0" y
“Aprenda C# 3.0 desde
0.0 - Parte 3, lo nuevo”.
http://www.elguille.info.
En el contexto de este artículo, dinámico y estático
se puede aplicar de dos formas, uno haciendo referencia a los tipos de datos y otro a los lenguajes.
Cuando se habla de dinámico y estático haciendo
referencia a los tipos de datos, estático significa que
los tipos de datos solo soportan los elementos que ellos
definen; es decir, solamente podemos acceder a los
métodos, propiedades, etc., que estén definidos en el
tipo. Por otro lado, dinámico significa que sin necesidad de conocer de antemano el tipo de datos que
estamos usando, podamos acceder a cualquiera de los
miembros (métodos, propiedades, etc.) que ese tipo
defina (no confundamos esto con el polimorfismo, que
si bien se puede parecer no es exactamente lo mismo).
Aunque otra interpretación puede ser que esos tipos
dinámicos no son específicos, sino que un mismo tipo
(que en realidad ni es un tipo) soporta cualquier valor,
algo parecido al tipo Variant de COM (o de VB6). Y
por último, si ese tipo dinámico es producido por un
lenguaje orientado a objetos, posiblemente sea una
referencia a un objeto de un tipo que se ha inferido
según el valor asignado, algo parecido a lo que hacen
VB.NET y C# con la inferencia de tipos; la diferencia estará que los lenguajes estáticos habrán definido
esas variables con un tipo de datos, mientras que los
lenguajes dinámicos no suelen tener la necesidad (ni
la obligación) de definir las variables.
Cuando dinámico y estático se aplican a los lenguajes (para simplificar), estático significa que el lenguaje utiliza tipos estáticos, es decir especificaciones
concretas para cada tipo de datos, mientras que los lenguajes dinámicos no necesitan definir esos tipos de datos,
ya que suelen inferirse y el intérprete (los lenguajes dinámicos suelen tratarse como los lenguajes de script, y éstos
suelen ser interpretados en lugar de compilados) inferirá el tipo según el valor asignado.
En el resto del artículo nos centraremos en los
tipos de datos más que a los lenguajes.
Visual Basic y los tipos dinámicos
A los lectores que conozcan o hayan usado alguna versión de Visual Basic (da igual si es para .NET o no),
todo lo comentado seguramente les sonará de algo.
Simplificando, podríamos decir que el acceso dinámico a los miembros de un objeto es lo que llaman en
<< dnm.isla.vb
El DLR (principalmente la forma de gestionar los tipos de los lenguajes dinámicos y los de los
lenguajes estáticos) permitirá que los lenguajes “clásicos” (y estáticos) de .NET como VB.NET
y C# puedan interactuar con otros lenguajes (los llamados dinámicos) como Python, Ruby
(ambos nombrados con el prefijo Iron, al menos en las versiones implementadas por Microsoft) e incluso JavaScript (la versión dinámica), y precisamente la necesidad de permitir usar
los tipos dinámicos está justificada por la dificultad (o complicación) que supone el uso de objetos creados con los lenguajes dinámicos desde lenguajes estáticos.
inglés late binding (enlace tardío) y el acceso estático lo
que se conoce como early binding (enlace temprano),
algo que en Visual Basic siempre ha existido.
El enlace estático (o temprano) solo permite acceder a los miembros “conocidos” del tipo, es decir, los
miembros que esa clase (o tipo) defina; esto está bien y
es lo que siempre nos han recomendado (cuando los que
ahora lo recomendamos estábamos aprendiendo), entre
otras cosas porque la ejecución es más rápida y sobre
todo menos propensa a errores. Incluso hay lenguajes
como C# que solo permiten esta forma de enlace, al
menos hasta ahora, ya que su próxima versión (la 4.0) sí
que soportará el enlace dinámico además del estático.
Por otra parte, el enlace dinámico (o tardío) nos
permite hacer referencia a miembros que no existen en
el tipo de datos que estamos usando. Para que esto sea
posible, el tipo debe ser de uso general (en .NET de
tipo Object, ya que todos los tipos de .NET se derivan
de ese tipo básico). Es decir, el compilador aceptará el
acceso a ese miembro que no está definido en el tipo
de datos y será en tiempo de ejecución cuando se compruebe si ese miembro está realmente definido; por eso
lo de “enlace tardío”, ya que hasta que no se ejecute
ese código no se podrá comprobar el tipo de datos que
realmente tiene ese “objeto”. Aclarar que actualmente este tipo de enlace tardío en los lenguajes de .NET
solo se permite en Visual Basic, pero no en C#, aunque esto cambiará en la próxima versión.
En el listado 1 podemos ver cómo acceder a un método inexistente en la clase Object, pero que en realidad el
objeto referenciado por la variable obj1 sí que define, y
por tanto este código funcionará perfectamente. La salvedad es que si estamos usando Visual Basic 2008, además
de usar Option Strict Off, también deberíamos desactivar la inferencia automática de tipos, con idea de que
por defecto las cosas se hagan como se deben hacer (definiendo expresamente la variable del tipo de datos que
va a contener); por tanto, lo mejor es definir expresamente la variable obj1 como de tipo Object. El método
Mostrar usado desde la variable obj1 está definido en la
clase MiClase, por tanto la llamada a ese método funcionará cuando se ejecute la aplicación.
]
Dim obj1 A s Object
‘ A signamos a la variable un nuevo objeto
‘ del tipo MiClase
obj1 = New MiClase With {.Nombre = “Mi clase 1”}
‘ El tipo MiClase define el método Mostrar
‘ por tanto es correcto hacer esta llamada
obj1.Mostrar(“Esta es”)
Listado 1. Debemos tener desactivado Option Strict para
que este código funcione
Si el lector piensa que lo correcto hubiera sido declarar la variable obj1 del tipo MiClase, decirle que estaría
en lo cierto, pero aquí he usado esa clase para que la
variable tuviera algo, ya que lo habitual es que ese valor
se obtuviera de alguna forma en la que no tengamos forma de comprobar que en realidad tiene ese valor, como
podría ser si esa variable se asignara mediante una llamada a CreateObject, tal como vemos en el listado 2.
La desventaja de usar el enlace tardío radica en el
hecho de que el compilador no hace ninguna comprobación de que ese miembro realmente esté definido en
el tipo de datos, y por tanto es posible que el código falle
en tiempo de ejecución, y ya sabemos que no hay nada
peor que nuestra aplicación falle cuando esté ejecutándose en el equipo de nuestros clientes.
Dim obj2 A s Object
‘ Creamos un objeto del tipo Word.A pplication
obj2 = CreateObject(“Word.A pplication”)
‘ A ntes de acceder al objeto,
‘ debemos asegurarnos de que Word está disponible
If obj2 IsNot Nothing Then
Console.WriteLine(obj2.A ctivePrinter)
‘ Si llamamos a un método inexistente,
‘ dará error obj2.Mostrar(“Hola”)
End If
Listado 2. Ejemplo de enlace tardío usando CreateObject
<<dotNetManía
[
NOTA
51
<< dnm.isla.vb
Por otro lado, hay situaciones en las que puede
ser útil usar ese enlace dinámico, normalmente cuando usamos otros objetos que no proceden del propio
.NET Framework, por ejemplo si usamos objetos
COM procedentes de aplicaciones como Office, tal
como acabamos de ver en el listado 2.
Visual Basic puede ser no estricto, pero
no es dinámico
Tal como están las cosas actualmente, y de forma predeterminada (algunos seguimos lamentando que esto
sea así), Visual Basic no es estricto a la hora de hacer
conversiones o de acceder a los miembros de un objeto; es decir, se puede utilizar el enlace tardío a la hora
de acceder a los miembros que no estén definidos
expresamente (estáticamente) en un tipo en particular. Pero esto no significa que Visual Basic sea dinámico en el aspecto de permitir acceder dinámicamente
a los miembros de un objeto, sino que lo simula y a
la larga se obtienen los mismos resultados.
La única forma de permitir que Visual Basic simule ser un lenguaje dinámico (en lo referente a acceder dinámicamente a los miembros de un objeto) es
desactivando Option Strict. El problema es que esto
es algo que muchos no recomendamos que se haga,
y esperemos que no se justifique el hacerlo por la
necesidad de acceder dinámicamente a los miembros
de un tipo del que no tenemos la información de los
miembros que expone públicamente.
Ámbitos de Option Strict
Afortunadamente, Visual Basic nos permite usar
<<dotNetManía
Option Strict (ya sea activado o desactivado) a dos
52
niveles, y el nivel más bajo (o reducido) en el que se
puede utilizar es a nivel de fichero de código; es decir,
podemos restringir la comprobación no estricta solo
en el código que esté definido dentro de un fichero
de código. Esto, unido a que podemos definir clases
parciales, nos permite definir en esos ficheros de código solo aquellas partes de nuestros tipos que necesiten que la comprobación estricta del código no esté
activada, ya que es esa comprobación estricta que se
hace al tener activado Option Strict la que no nos permite acceder a miembros de un objeto que no estén
definidos en el tipo de ese objeto, o sea cuando usamos lo que ahora se llama acceso dinámico.
El otro ámbito de Option Strict es a nivel de proyecto, ya que podemos indicar que, por ejemplo, cierto estado esté activado en todo el proyecto. De esta
forma, si no indicamos expresamente el estado de esta
opción de comprobación estricta, siempre estará activado o desactivado, dependiendo del valor que haya-
El enlace dinámico puede ser útil
cuando usamos objetos que no
proceden del propio .NET
Framework, como los objetos
COM de Office
mos dado en las opciones del proyecto. Tal y como
hemos visto en el párrafo anterior, cuando necesitemos desactivar esa comprobación estricta lo podremos hacer a nivel de fichero de código; de esa forma,
solamente en ese fichero se dejará de hacer las comprobaciones que el compilador hace cuando asignamos el valor On a Option Strict.
Recapitulando sobre Option Strict
A título de recordatorio (así valdrá para aquellos
lectores que no suelen utilizar Visual Basic y por tanto puede que no sepan para qué sirve esta instrucción)
activando Option Strict el compilador nos obligará a
definir todas las variables con un tipo de datos adecuado; además, a la hora de asignar un valor a esas
variables se comprobará que el tipo de datos asignado es el mismo que el de la variable que recibe el valor
o se puede convertir de forma implícita (automáticamente). Y cuando estamos asignando valores entre
variables de distintos tipos de datos, también se comprobará si se puede hacer de forma implícita o se necesita hacer una conversión explícita (cast); en este último caso, la presencia en el código de esa conversión
explícita nos pondrá en alerta de que es posible que
dicha conversión falle y por tanto tengamos cuidado
con ese código, ya que según la Ley de Murphy, si
algo puede fallar, seguro que fallará.
Cuando instalamos Visual Studio (o Visual Basic
Express) el valor predeterminado de Option Strict es
Off, es decir, desactivado; por tanto, todas estas comprobaciones que he comentado antes no se hacen. De
esa forma, podemos declarar variables sin necesidad de
indicar de qué tipo son y asignarles valores de cualquier
tipo. Esto es posible ya que esas variables en realidad
son de tipo Object y este tipo de datos acepta cualquier
valor; por tanto, podremos asignar cualquier valor a una
variable que sea de tipo Object.
<< dnm.isla.vb
Problema, lo que se dice problema,
no hay ninguno. De hecho, mucha gente piensa que incluso es mejor tener desconectada esa opción, ya que así no tenemos que preocuparnos en hacer conversiones entre tipos ni tener que declarar las variables con un tipo de datos
determinado. Pero no nos engañemos:
está demostrado que una programación
con tipos de datos concretos es más eficiente que una que utilice tipos de datos
más generalizados (por no decir “genéricos”, que se podría confundir con los
tipos generic), y todo el trabajo que nos
dará tener que hacer las conversiones
de forma explícita nos ayudará a saber
qué es lo que estamos haciendo y (como
dije antes) alertarnos de que algo puede ir mal al hacer la conversión. Y es que
el compilador de Visual Basic a la hora
de hacer las conversiones entre tipos
diferentes de datos lo hará casi de la misma forma que lo haremos nosotros, pero
será más difícil de saber que se puede
producir un fallo al convertir entre esos
dos valores si no vemos que ahí se está
haciendo una conversión.
Los tipos dinámicos en .NET
Framework 4.0
Aunque aún está en una fase muy temprana de desarrollo (a la hora de escribir este artículo solo está disponible la
primera CTP), .NET Framework 4.0
incluirá soporte para los tipos dinámicos, ya que también permite mediante
el DLR la integración con lenguajes
dinámicos y por tanto, se podrá intercambiar información entre esos lenguajes y los denominados estáticos.
Para permitir la utilización de los
tipos dinámicos en lenguajes como C#
(que son muy estrictos), se ha tenido
que hacer uso de una nueva forma de
definir esos tipos dinámicos, ya que el
compilador no debe comprobar si los
miembros que se aplican a ese objeto
están definidos o no; al menos, esa comprobación no se hará en tiempo de compilación, si no que será en tiempo de
ejecución cuando se compruebe si realmente el objeto asignado a esa variable
dinámica soporta ese método o propiedad que se está usando. En C# 4.0
se definirá un tipo dinámico con la palabra clave dynamic; en cuanto el compilador se encuentre con esa declaración,
sabrá que debe aplicar late binding a esa
variable, y por tanto no hacer ningún
tipo de comprobación hasta que se esté
ejecutando el código.
En el listado 3 vemos un ejemplo
parecido al del listado 1, solo que en
esta ocasión estamos usando código de
C# 4.0 y particularmente de la instrucción dynamic y lo que el uso de esa instrucción supone: enlace tardío.
¿Será Visual Basic un lenguaje
dinámico?
Tal como están las cosas, la respuesta
es no. Al menos en lo que se refiere a
los tipos dinámicos, ya que la intención
es que llegue a serlo, es decir, que vuelva a ser un lenguaje de script o casi, ya
que ahora a ese tipo de lenguajes se les
llama dinámicos. Pero todo esto lo comprobaremos más adelante, cuando la
próxima versión de Visual Basic (y de
.NET Framework) esté más madura.
Mientras tanto, contentémonos con lo
que tenemos y aprovechémoslo; en esta
isla seguiré explicando cosas para aprovechar mejor este lenguaje.
dynamic obj1;
// A signamos a la variable un nuevo objeto del tipo MiClase
obj1 = new MiClase { Nombre = “Mi clase 1” };
// El tipo MiClase define el método Mostrar
// por tanto es seguro hacer esta llamada
obj1.Mostrar(“Esta es”);
Listado 3. Código equivalente del listado 1 para usar con C# 4.0
En Visual Basic no se ha añadido
ninguna nueva instrucción para definir
este tipo de variables dinámicas, ya que
Visual Basic permite usar ese modo
“retardado” de comprobación si se utiliza Option Strict Off.
Pero no nos confundamos: eso no es
un tratamiento dinámico de los tipos de
datos, ya que en realidad, para permitir
que todo esto sea posible, se ha agregado
una nueva interfaz para definir estos tipos
dinámicos; esa interfaz es IDynamicObject,
que está definida en el espacio de nombres System.Scripting.Actions, y Visual
Basic no utiliza esta interfaz, sino que simplemente hace lo que ha estado haciendo durante muchos años: esperar a que
llegue el momento de la ejecución del
código, y en ese preciso momento es
cuando comprueba si el objeto define o
no ese método (o cualquier otro miembro al que queramos acceder). Si lo define, bien; si no lo define, mal y de regalo
una excepción.
Conclusiones
En este artículo hemos hablado sobre
algo que en los próximos meses (o
años) seguramente será algo más habitual: los tipos y lenguajes dinámicos.
Pero como hay que estar en la realidad, también hemos visto (aprovechando la coyuntura del tema) cómo
Visual Basic puede ser dinámico o lo
que es lo mismo, menos estricto con
los tipos de datos que utilizamos en
nuestras aplicaciones. Confío en que
el lector sepa con más certeza que esa
forma de dinamismo no es la más
recomendable, salvo que realmente
sepamos qué es lo que estamos
haciendo, y en que después de esta
lectura el lector sabrá qué es lo que
hace en cada momento, o al menos
sabrá cómo ser estricto a la hora de
escribir el código o no serlo, si así lo
considera oportuno.
<<dotNetManía
¿Qué problema hay al usar Option
Strict Off?
53
todonet@qa
[email protected]
Dino Esposito
Arquitecto en IDesign,
Dino Esposito es una de
las autoridades mundiales reconocidas en tecnologías Web y arquitectura de software. Sus
libros más recientes son
"Programming ASP.NET
3.5-Core Reference" e
"Introducing Microsoft
ASP.NET AJAX" (Microsoft Press). Es ponente
regular en eventos de la
industria de ámbito
mundial, como Tech-Ed
o DevConnections, y
europeos, como DevWeek y Basta.
Un vistazo a Entity Framework
Este mes exploramos algunas características relacionadas con Entity Framework y el desarrollo
con la primera versión de una herramienta que tiene todavía mucho que decir y hacer en el futuro. Entity Framework se ha lanzado en su versión 1.0 este pasado verano, junto al SP1 de .NET
Framework 3.5. Como muchos otros productos de Microsoft en versión 1.0, no es perfecto, y, tal
como se ha visto en el pasado PDC, mejorará de forma muy significativa en su próxima versión.
En este artículo responderé a algunas preguntas que surgen frecuentemente tras un primer acercamiento a Entity Framework.
He comenzado con Entity Framework, con la idea de que tenía que ser muy superior a
LINQ to SQL y centrado en el modelado de domain spaces a través de entidades y
relaciones. Sin embargo, me parece muy similar a LINQ to SQL, y muy centrado en
datos. ¿En qué es diferente de LINQ to SQL?
Personalmente, he estado un tanto remiso a empezar con Entity Framework, y he comenzado a
estudiarlo sólo un poco antes de la salida de su
versión 1.0. Por el contrario, he estado haciendo
un montón de cosas con LINQ to SQL, a plena
satisfacción, desde el comienzo. Hay que decir
que cambié de opinión repetidamente respecto a
LINQ to SQL. Al principio, me parecía como un
ADO.NET, pero muy mejorado. Concretamente, me parecía una especie de ADO.NET capaz
de trabajar con objetos fuertemente tipados en
lugar de las clásicas colecciones de filas y columnas (débilmente tipadas).
Según esto, comencé por abordar el trabajo con
LINQ to SQL en la parte donde normalmente tratamos con los datos físicos. Simplemente, sustituí
la persistencia de ADO.NET por la de LINQ to
SQL. Inmediatamente, me di cuenta de que ambos
no eran intercambiables sin más. Una capa de
LINQ to SQL dialoga con su contrapartida utilizando su propio modelo de objetos. Para desconectar uno e insertar el otro necesitas un trabajo
de adaptación entre los tipos de datos que se inter-
cambian. Si la capa intermedia está basada en DataSets, hay que convertir los objetos LINQ to SQL
a éstos últimos, lo que puede resultar sorprendente, ya que la maquinaria de LINQ to SQL carga a
bajo nivel streams de ADO.NET directamente en
el modelo de objetos.
Por otra parte, no parece una buena idea cambiar toda la capa de datos de un sistema existente solo por que exista una nueva tecnología disponible. Si, en lugar de eso, evalúas LINQ to SQL
para un nuevo proyecto, verás que -más bien- se
parece mucho a una herramienta ORM
(Object/Relational Mapper). LINQ to SQL suministra un modelo de objetos e implementa un
número de patrones comunes en su contexto de
datos, tales como la carga diferida, unidades de
trabajo, mapas de identidades, bloqueo optimista, etc. y suministra una correspondencia de objetos para la persistencia de la información. Realmente, te da objetos de negocio con datos y comportamiento. Así pues, puede considerársele una
herramienta ORM con todos los derechos. Así de
simple.
columna en la base de datos como discriminador para distinguirlos. El valor del
discriminador se usa para especificar de
qué tipo de registro se trata. En otras palabras, esto quiere decir que se necesita
tener una columna ad-hoc si se quiere
crear y mantener una jerarquía en el
modelo de objetos.
Entity Framework soporta otros tipos
de correspondencias. En particular, el tipo
Tabla por tipo concreto, que utiliza una
tabla separada por cada tipo en la jerarquía, y el tipo Tabla por subclase, un
tipo híbrido que usa una tabla compartida para la información común acerca del
tipo base y tablas separadas para los tipos
derivados.
Entity Framework también soporta
los tipos complejos, tipos que se anidan
dentro de otros más grandes y que no han
sido pensados para constituir una entidad. El ejemplo canónico es el tipo Direc-
ción, que recoge las propiedades Calle,
Ciudad, Provincia y País. LINQ to SQL
no soporta los tipos complejos, pero he
diseñado un sistema alternativo que funciona sin romper el diseñador. Puedes leer
el artículo completo en: http://dotnetslackers.com/articles/csharp/ComplexTypes-in-LINQ-to-SQL-Reloaded.aspx.
Curiosamente, aunque Entity Framework
soporta totalmente los tipos complejos,
el diseñador de Visual Studio 2008 no lo
hace (ver figura 1). Esto significa que es
necesario editar manualmente el código
fuente del modelo de entidades para
introducir tipos complejos. Sin embargo,
si esto se hace, el modelo de datos no
podrá ser vuelto a cargar en el diseñador.
Esto se resolverá en la versión 2.0 de
Entity Framework. Por último, podemos
encontrar otras diferencias en la forma
en que ambos soportan la carga diferida
y los planes de consulta.
Figura 1: El diseñador de Visual Studio 2008 no soporta tipos complejos en Entity Framework
¿Cómo puedo especificar un query fetch plan con Entity Framework? ¿Está habilitada por defecto la carga
diferida como en LINQ to SQL?
Respecto a la carga de datos, existen algunas diferencias entre LINQ to SQL y
Entity Framework. Veamos los detalles.
Lo primero, la carga perezosa (lazy loa-
ding) y la carga diferida (deferred loading)
son equivalentes y se refieren a la misma
funcionalidad básica: la capacidad de cargar automáticamente objetos bajo
demanda. La carga perezosa es el nombre asignado en los libros de patrones de
diseño para denominar una forma de
codificar: el código es perezoso en el sen-
<<dotNetManía
Entity Framework no parece realmente un producto muy distinto desde el
punto de vista de su arquitectura. La similitud no es una leyenda urbana, pues hubo
que escalar bastante alto en las estructuras del software de Microsoft para decidirla. Podría decirse que ambos son el
mismo tipo de producto, aunque con
implementaciones distintas de algunas
características. Cada producto fue desarrollado por equipos independientes, que
vivían desconectados del resto del universo. Hoy, el mismo equipo está a cargo de ambos productos, y no les va a resultar fácil averiguar cómo diferenciarlos.
La solución más probable parece dejar
LINQ to SQL tal como está y mejorar
solamente Entity Framework. Sin embargo, no va a salir nada antes de la próxima
actualización significativa de .NET Framework a finales de 2009, si no en 2010.
Después de todo, creo que la diferencia más grande entre ambos es el
conjunto de bases de datos soportadas.
LINQ to SQL se limita a SQL Server,
mientras que Entity Framework es independiente de la base de datos y soporta
un modelo abierto y extensible para proveedores de bases de datos de terceros
(aunque la mayor parte de ellos está
todavía en desarrollo, lo que vincula
Entity Framework casi de forma exclusiva a la plataforma SQL Server).
La capacidad de relaciones entre entidades de LINQ to SQL está limitada
esencialmente a las del tipo 1:1 entre clases y tablas de la base de datos. Además,
LINQ to SQL solo soporta una manera
de implementar la herencia, conocida
como Tabla por jerarquía. Este modelo usa una única tabla para mantener
todos los tipos de una jerarquía de herencia (por ej. ClienteBase, ClienteRegistrado y ClienteDesconocido), y utiliza una
[email protected] [email protected]
<< dnm.todonet@qa
55
<<dotNetManía T o d o t N e t . q a @ d o t n e t m a n i a . c o m T o d o t N e t . q a @ d o t n e t m a n i a . c o m
<< dnm.todonet@qa
56
tido de que los objetos solo se cargan en memoria en el
momento en que son requeridos explícitamente. Carga
diferida es el término que utiliza Microsoft en LINQ to
SQL para hacer mención a un comportamiento observable: la carga se difiere hasta que los datos resultan absolutamente imprescindibles.
En LINQ to SQL, la carga diferida está soportada y
habilitada por defecto, lo que significa que si se hace una
consulta de un pedido y más tarde se trata de leer la información del cliente relacionado, se lanza una nueva consulta. En las aplicaciones modernas basadas en dominios,
la carga perezosa es una característica imperativa. Preserva el modelo de objetos de procedimientos prescriptivos de carga de datos que de otra forma tendrían que
ser insertados en cada lugar donde se requiriera el acceso a datos. Consecuentemente, la lógica de negocio de
una aplicación basada en dominios se "contaminaría" con
código propio del acceso a datos.
La carga perezosa puede tener ciertos efectos indeseables en el código (por ejemplo, demasiadas peticiones a la
base de datos) si no se comprende y gestiona adecuadamente por los desarrolladores. Probablemente por esta
razón, Entity Framework no soporta la carga perezosa en
absoluto. Por diseño. La política es que ninguna llamada a
la base de datos suceda sin el consentimiento explícito del
desarrollador. Eche un vistazo al siguiente código:
var orders = from o in context.Orders
where o.Status == “Completed”
select o;
foreach (Order o in orders)
{
// A cceso al cliente relacionado
if (!o.Customer.IsLoaded)
{
o.Customer.Load();
}
// Trabajo con datos del cliente
}
En Entity Framework, para forzar a una entidad relacionada a que se cargue en memoria se precisa una llamada explícita. En LINQ to SQL también se puede deshabilitar la carga diferida, pero si se hace esto, solo se
podrán recuperar los datos que falten mediante otra llamada. No se suministra ninguna otra contrapartida al
método Load.
El query fetch plan es el mecanismo que se usa para
decidir qué relaciones deben resolverse automáticamente.
Aquí tiene un ejemplo del funcionamiento en Entity Framework:
Order order =
context.Orders.Include(“OrderDetails”).
Include(“Product”).First();
El método Include indica a la entidad que se rellene
con datos provenientes de una relación existente entre
entidades. Por otra parte, en LINQ to SQL se utiliza el
método LoadWith para especificar qué relaciones deben
resolverse. Aquí va un ejemplo:
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Customer>(c => c.Order);
options.LoadWith<Order>(o => o.OrderDetails);
context.LoadOptions = options;
Como puede verse, aquí se hace evidente otra diferencia entre ambos sistemas: en Entity Framework, el
fetch plan se especifica a nivel de consulta; en LINQ to
SQL, se define a nivel de contexto.
Tengo que crear una relación entre una entidad Cliente y una entidad País. Quiero que la relación sea unidireccional. En otras palabras, quiero una relación 1:1 del tipo Cliente->País. Parece que no se puede conseguir esto sin tener igualmente una relación 1:n inversa entre País y Cliente.
Esto es correcto y, nuevamente, es así por diseño. Las
relaciones son bidireccionales. Lo sorprendente es
que se acabe obteniendo una relación bidireccional,
dado que las relaciones se crean a partir de restric-
ciones (constraints) de las bases de datos, basándose en
las claves ajenas.
No hay un camino alternativo en esta versión; es
algo que se arreglará en la versión 2.0.
Traducido al castellano por Marino Posadas
biblioteca.net
ADO.NET Entity Framework
Aplicaciones y servicios centrados en datos
Unai Zorrilla, Octavio Hernández y Eduardo Quintás
Editorial: Krasis Press
Páginas: 414
Publicado: octubre de 2008
ISBN: 978-8493548995
Idioma: castellano
Es un placer comentar la última obra de tres colaboradores de dotNetManía sobradamente conocidos por los lectores. Entity Framework es el nuevo marco para acceso a
datos propuesto por Microsoft, disponible desde la aparición del SP1 de Visual Studio
2008, y propone un modelo de acceso y manipulación de datos muy novedoso. Por eso,
un libro de este tipo era fundamental plantearlo –como así se ha hecho- desde el punto
de vista de un desarrollador que conoce los fundamentos de ADO.NET pero no ha manejado aún los recursos de LINQ con todas sus variantes.
El libro avanza desde la introducción y los conceptos de modelado que propone el
marco EF hasta la puesta en práctica de soluciones reales mediante esta tecnología, y con
esto queremos decir soluciones que están funcionando en empresas españolas en este
momento. Ese es otro de sus valores, aparte del indudable tono didáctico que los tres han
sabido imprimir a esta obra. Si la pregunta es ¿pero esto funciona en aplicaciones del día
a día?, la respuesta es que sí, y la forma de aprenderlo…ya saben.
Application Architecture Guide 2.0: Designing Applications on the
.NET Platform
J.D. Meier, Alex Homer, David Hill, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob
Boucher Jr. y Akshay Bogawat
Editorial: Microsoft
Páginas: 381
Publicado: diciembre de 2008
Idioma: inglés
Con prólogos de Soma Somasegar y Scott Guthrie comienza esta obra digital (probablemente se imprimirá en papel igualmente), gratuita y totalmente recomendable para cualquier
desarrollador o jefe de proyecto que quiera estar al día en la arquitectura de aplicaciones .NET
siguiendo las buenas prácticas aplicadas a todas las fases del ciclo de vida de las aplicaciones.
El libro está disponible para descarga en formato PDF desde la dirección de CodePlex
http://www.codeplex.com/AppArchGuide (y ha tenido 20.000 descargas en una semana).
novedades
Además, es una revisión de todos los conceptos nuevos que incorporan las nuevas tecnologías, como Entity Framework, aplicaciones R.I.A (Silverlight), aplicaciones móviles,
OBA, SharePoint LOB, etc. Y no se queda en el mero diseño arquitectónico, sino que
recorre casi todo lo que hay que tener en cuenta al planear y construir una aplicación con
cualquier tecnología .NET hoy en día, con especial énfasis en la construcción de las capas
o las recomendaciones de implantación y mantenimiento. Imprescindible.
Professional ADO.NET 3.5 with LINQ and the Entity Framework
Robert Jennings. Editorial: Wrox. Páginas: 672. ISBN: 978-0470182611. Fecha de publicación: febrero de 2009. Idioma: inglés.
Pro SQL Server 2008 Entity Framework
Jim Wightman. Editorial: APress. Páginas: 550. ISBN: 978-1590599907. Fecha de publicación: octubre de 2009. Idioma: inglés.
TEXTO: MARINO POSADAS
desván
Marino Posadas
Web 2.0,Web semántica y Web implícita
El notable avance de la participación social en
Internet ha desembocado en cotas de comunicación y creación de recursos compartidos que
exceden las previsiones de los más optimistas.
En 2004 nacía un nuevo concepto: la Web 2.0,
definida como la tendencia que propicia el uso
de la red como herramienta de colaboración,
creatividad e información compartidas y nueva
funcionalidad remota. No conlleva –en su inicio– ninguna nueva especificación técnica, sólo
un nuevo uso de la web como herramienta social.
Tim Berners-Lee, de hecho, la definía como
“una revolución empresarial, basada en el uso
de Internet como plataforma, que requiere –eso
sí– comprender las reglas del éxito que esa plataforma implica”. En realidad, se trata de nuevas
formas de usar la Web, en parte propiciadas por
las –para la mayoría, más supuestas que reales–
mejoras en las prestaciones de los servicios de
conexión de banda ancha.
¿Y dónde quedan las promesas? ¿Para cuándo un sistema inteligente de búsquedas en la red?
Casi nadie va más allá de las 3 primeras páginas
de enlaces devueltas por los buscadores, y todavía
son muchas las ocasiones en que nos quedamos
con la duda de si lo que estamos buscando existe o no. No se trata de estar en la Web, se trata
de que te puedan encontrar. Muchos protestaban por el “monopolio” de Microsoft, y han
abrazado amorosamente el de Google como un
mal necesario. Si no estás en Google, no estás.
Ya, ya sé que podemos usar otros: Live Search,
Yahoo, etc., y que algunos comenzamos a explorar otras posibilidades, pero los usuarios del pri-
mero son legión. Y los motores de búsqueda se
basan en algoritmos que pueden fallar o que no
son perfectos.
La solución prometida era es la de la Web
semántica. Se basa (disculpe el lector que ya lo
conozca) en la idea de añadir metadatos semánticos a las páginas, de forma que –al igual que
hacen las etiquetas XML con sus datos contenidos– describan lo que hay allí, su significado
y sus relaciones, y lo hagan de una manera formal, de tal suerte que sea posible más tarde procesar esos datos mediante un software y conseguir que los resultados de una búsqueda tengan
ese “factor de inteligencia” del que ahora carecen. El propio Berners-Lee lo intentó desde el
principio, pero no fue posible, según reconocía
en una charla ante el MIT Technology Review
Emerging Technologies (ver http://www.digitaldivide.net/articles/view.php?ArticleID=20). Pero
se necesitaría que las nuevas páginas creadas
(parece muy difícil revisar las existentes) utilizaran las tecnologías de descripción de los contenidos, como RDF y OWL.
No obstante, se están haciendo esfuerzos en
ese sentido, pero son más académicos que corporativos, y mucho menos, particulares. El equi-
<<dotNetManía
utilidades del mes
58
Microsoft Web Platform Installer. Más que interesante
paquete que permite
montar en un equipo
mediante un proceso
único todas las herramientas gratuitas
necesarias para el
desarrollo Web con
tecnologías de la
compañía: IIS, Visual
Web Developer 2008
Express Edition, SQL Server 2008 Express Edition
y .NET Framework 3.5, pudiendo seleccionar las
que se desea si no se necesitan todas. Para información y descargas: http://www.microsoft.com/web/channel/products/WebPlatformInstaller.aspx.
po de Carmen Costilla en la Universidad
Politécnica de Madrid, o Pablo Castells en la
Autónoma, son ejemplos de ello, junto a otras
iniciativas similares en centros de Calaluña, Baleares, Andalucía, etc. Y también existen propuestas interesantes a nivel gubernamental, como la
Red Temática de la Web Semántica, promocionada por el Ministerio de Educación y Ciencia (http://www.redwebsemantica.es/SemWeb/sewView/frames.jsp), pero no es menos cierto que la
inmensa mayoría de los desarrolladores no incorporan estas características en sus trabajos.
Y además, en 2007, apareció un nuevo término: la Web implícita, vocablo acuñado para designar las Web especializadas en la síntesis de información personal recopilada de Internet aportando una imagen coherente y lo más completa posible del individuo (o grupos de individuos). Hay
empresas que ya han hecho de esto su objetivo primario (ver http://www.orch8.net), y pueden encontrarse explicaciones más detalladas de esta idea en
http://blog.eturner.net/?p=14, http://blogs.zdnet.com/
web2explorer/?p=413 y http://www.avc.com/a_vc/
2006/12/2007_the_implic.html. Esta información
puede incluir vínculos visitados con más frecuencia, hábitos de navegación, prácticas de búsqueda
de información o cualquier otro dato generado sin
la intervención explícita del usuario, y la información así obtenida podría utilizarse en muchos contextos diversos. Sería un complemento a las visiones y usos prometidos por las dos anteriores como
–quizá– un anticipo de la próxima versión (sí, ya se
habla de la siguiente, la Web 3.0), que tendría como
objetivo la descentralización del yo. Pero tiempo
habrá de volver a este tema…
documentos en la red
ASP.NET Patterns every developer
should know. Artículo publicado en
Developer Fusion por el conocido
divulgador de tecnologías de Microsoft, Alex Homer. El artículo va acompañado de un ejemplo descargable muy descriptivo. Accesible en la página: http://www.developerfusion.com/article/8307/aspnet-patterns-every-developer-should-know.
YouTube API: Try before you buy
es un artículo de John Musser publicado en ProgrammableWeb sobre
una página expuesta por YouTube con
el fin de que los desarrolladores puedan probar la API de desarrollo de
YouTube sin necesidad de descargarse el SDK correspondiente. Puede verse la explicación y el enlace en: http://blog.programmableweb.com/
2008/12/09/youtube-api-try-before-you-buy.
Descargar