Visual Basic • C# • ASP.NET • ADO.NET • .NET Framework

Comentarios

Transcripción

Visual Basic • C# • ASP.NET • ADO.NET • .NET Framework
nº28 julio-agosto 2006 • 6,50 € (España)
Visual Basic • C# • ASP.NET • ADO.NET • .NET Framework • Windows Server System
dotNetManía
www.dotnetmania.com
Dedicada a los profesionales de la plataforma .NET
WebParts en ASP.NET 2.0 (y III) •
Servicios Web nativos con SQL
Server 2005 • Detección de
problemas de rendimiento en SQL
Server 2000 y SQL Server 2005
(IV) • Acceso a datos con
ADO.NET 2.0 (sin asistentes)
dnm.editorial
dotNetManía
Dedicada a los profesionales de la plataforma .NET
Vol. III •Número 28 • Julio-Agosto 2006
Precio: 6,50€
.NET Framework 3.0
Editor
Paco Marín
([email protected])
Atención al suscriptor
Pilar Pérez
([email protected])
Consejo de Redacción
Dino Esposito, Guillermo 'guille' Som, José
Manuel Alarcón, Lorenzo Ponte, Luis
Miguel Blanco, Miguel Katrib (Grupo
Weboo) y Octavio Hernández
Colaboradores habituales
Antonio Quirós, Braulio Díez, Carlos
Quintero, Eladio Rincón, Javier Aragonés,
Jorge Serrano, José Miguel Torres, Iván
González, Pepe Hevia, Salvador Ramos y
Sergio Vázquez
Además colaboran en este número
David Perona, Francisco A. González, José
Luis Balsera
Ilustraciones
Yamil Hernández
Edición, suscripciones y publicidad
.netalia
c/ Robledal, 135
28529 Rivas-Vaciamadrid (Madrid)
www.dotnetmania.com
Tf. (34) 91 666 74 77
Fax (34) 91 499 13 64
Imprime
Color Digital
ISSN
1698-5451
Depósito Legal
M-3.075-2004
>>
<<
Bienvenido al número 28, de julio y
agosto de 2006, de dotNetManía.
Entre los eventos Tech-Ed 2006 de
Boston y MEDC Europe 2006 de Niza,
este mes se han generado muchas e importantes noticias, pero ninguna tan polémica como la asignación del nombre comercial a la “suma” de .NET Framework 2.0
y WinFX. Y todo porque le han puesto
“.NET Framework 3.0”. A todas las personas que yo he consultado les parece raro
y confuso; y si leemos los comentarios que
ha generado la noticia (unos 400 solo en en
el blog de S. “Soma” Somasegar) vemos
que hay bastante consenso sobre el tema.
Podrían haberle puesto un número inferior
o podrían haber esperado a que apareciese
Orcas y así, tanto .NET Framework como
las librerías y el CLR tendrían la versión
3.0, pero al parecer a alguien de marketing
se le ocurrió que WinFX estaba añadiendo mucha confusión... Deberán darle un
premio, porque precisamente “confusión”
es la palabra que más se está usando ahora. Aunque la verdad es que tampoco tiene mayor importancia, o eso es lo que a
mí me parece.
Este mes nos hemos cogido la maleta y nos hemos ido a Boston con
Francisco González de Solid Quality
Learning y a Niza con José Luis
Balsera de Raona. Ambos se han estre-
nado este mes cubriendo el Tech-Ed y
el MEDC, respectivamente; por tal
motivo aprovecho para darles la bienvenida. Igualmente, le doy la bienvenida a
otro colaborador invitado, David
Perona, que se estrena con su “Servicios
Web nativos con SQL Server 2005”.
Este mes vuelve Marino Posadas
con otra de sus excelentes entrevistas,
esta vez a Arvindra Sehmi, la cabeza
visible del Enterprise Team en Microsoft
Corp's Developer and Platform Evangelism
Group en EMEA.
José Manuel Alarcón termina con
su estupenda serie de artículos sobre
WepParts en ASP.NET 2.0 y Eladio
Rincón nos envía el penúltimo de su
interesante serie sobre la detección de
problemas de rendimiento en SQL
Server.
El artículo de portada este mes es
nuevamente para la sección dnm.futuro, donde Octavio Hernández presenta
las novedades de VB 9.0 para implementar LINQ. Este tipo de contenidos
quizá no se puedan aplicar a día de hoy,
pero pienso que son necesarios para ir
preparándonos para el nuevo .NET
Framework ¿3.5? con el CLR ¿3.0? y
C# ¿3.0? o VB ¿9.0?. Mejor de versiones no hablamos :-).
Y dentro hay más. Espero que le guste.
Paco Marín
<<dotNetManía
Redactor Jefe
Marino Posadas
([email protected])
3
28
dnm.sumario
MEDC Europe 2006
08-09
Tech-Ed Boston 2006
10-11
Entrevista a Arvindra Sehmi
12-14
Nuestro entrevistado de hoy es la cabeza visible del Enterprise Team en Microsoft
Corp's Developer and Platform Evangelism Group en Europa, Oriente Medio y
África (EMEA) y su trabajo se focaliza hacia la adopción de las mejores prácticas
dentro de la comunidad de arquitectos de EMEA.
WebParts en ASP.NET 2.0 (III)
16-20
Con este artículo finalizamos la serie sobre WebParts comenzada hace dos números en
dotNetManía. En él trataremos algunos conceptos avanzados sobre bloques personalizables
que nos permitirán llegar a un buen nivel en el desarrollo de este tipo de aplicaciones. En
concreto, veremos cómo intercambiar información entre ellos y cómo exportarlos para su
reutilización.
Lo que nos traerá Orcas:VB 9.0 y LINQ
22-29
dnm.sumario
Este artículo presenta las novedades que incluirá (probablemente con algunas variaciones)
Visual Basic 9.0, incluyendo la sintaxis de las expresiones de consulta, que constituyen el
principal reflejo en el lenguaje de la tecnología LINQ, y las extensiones para el soporte
directo de XML.
Servicios Web nativos con SQL Server 2005
30-35
Con el uso de HTTP EndPoints podemos exponer a la Web tanto los procedimientos
almacenados como las UDF de nuestra base de datos sin tener que usar ninguna otra
herramienta ni abrir puertos TCP para SQL Server 2005.
Detección de problemas de rendimiento en SQL Server 2000 y
SQL Server 2005 (IV)
36-39
En esta cuarta entrega nos vamos a centrar en analizar qué tipo de información hay
almacenada en la memoria de SQL Server, división del uso de la memoria y cómo
detectar bloqueos con las nuevas DMV de SQL Server 2005.
Acceso a datos con ADO.NET 2.0 (sin asistentes)
41-46
Tal como comentamos en el número anterior, en esta ocasión vamos a ver cómo podemos
acceder a una base de datos usando única y exclusivamente código, es decir, sin usar los
asistentes que Visual Studio 2005 pone a nuestra disposición y que, en honor a la verdad, a
muchos les facilitará la tarea de crear aplicaciones ADO.NET de una forma bastante sencilla.
dnm.todotnet.qa
Informes, autenticación y actualización por lotes
47-49
Esta semana, la primera de las 3 preguntas de rigor resuelve problemas relacionados
con Reporting en ASP.NET. Otras preguntas se centran en la autenticación por
Internet y las actualizaciones por lotes en ADO.NET.
dnm.laboratorio
FileHelpers
50-51
Es relativamente frecuente que el trasvase de información desde/hacia una aplicación se
realice mediante archivos planos generados periódicamente. En tales ficheros, los registros
se almacenan en líneas de texto que deben ser interpretadas para su posterior explotación.
En el laboratorio de esta semana analizamos una librería que permite importar, exportar y explotar con gran comodidad archivos de este tipo en aplicaciones .NET.
dnm.comunidad.net
52-54
Eventos locales
Emprendia. La iniciativa para los e-mprendedores
dnm.biblioteca.net
55
Programming Microsoft ASP.NET 2.0 Core Reference
Visual C# 2005: A Developer's Notebook
dnm.desvan
58
6
noticias.noticias.noticias.noticias.noticias.noticias
<< dotNetManía
<< dnm.noticias
.NET Framework 3.0
A principios del pasado mes de Junio,S.“Soma” Somasegar,corporate vice president de la Developer Division
de Microsoft, anunció la decisión de Microsoft de ponerle nombre comercial a WinFX: .NET Framework 3.0.
Además de esto, Infocard también
ha sido bautizado y a partir de ahora se llamará Windows CardSpace y
también le conoceremos por sus
siglas WCS.
Así, las tecnologías que incluían
WinFX hasta el momento: Windows
Presentation Foundation (WPF),
Windows Communication Foundation
(WCF), Windows Workflow Foundation
(WF) y Windows CardSpace (WCS)
se suman a .NET Framework 2.0
para convertirse finalmente en
.NET Framework 3.0.
Sin embargo, las tecnologías anteriores como ADO.NET, ASP.NET,
WinForms y el propio CLR o las
BCL, no cambian y seguirán en su versión 2.0 como actualmente. Esto significa que, aunque pudiera parecerlo
por el cambio de versión principal del
.NET Framework, no hay cambios
sobre lo antiguo y podemos seguir trabajando con los compiladores y las técnicas actuales como hasta ahora.
.NET Framework 3.0 verá la
luz con la salida de Windows Vista
y estará disponible también para
Windows XP y Windows Server
2003, tal y como estaba pensado.
Ahora .NET Framework 3.0 versión CTP de junio ya está dispo-
S. “Soma” Somasegar es corporate vice president of the Developer
Division at Microsoft Corporation. Esta división es responsable de
todos los lenguajes de programación, herramientas y plataformas
en Microsoft, incluyendo Visual Studio, Web Platform and Tools,
.NET Framework, CLR y otras tecnologías de la plataforma de
desarrollo .NET. Además supervisa el India Develpment Center
(IDC) en Hyderabad, India.
Somasegar comparte frecuentemente sus pensamientos con los desarrolladores a
través de su blog en: http://blogs.msdn.com/somasegar.
nible para su descarga pública en:
http://www.microsoft.com/downloads/de
tails.aspx?FamilyId=8D09697E-48684D8D-A4CF-9B82A2AE542D.
Esto ha creado cierta confusión en
la comunidad de desarrolladores, ya
que la versión 3.0 está construida sobre
la versión 2.0 de .NET Framework.
Parecía obvio que WinFX tendría que
sumarse a .NET Framework, pero la
mayoría pensábamos –equivocadamente, por lo que se ve– que WinFX
se integraría en el .NET Framework
con la aparición de lo que a día de hoy
llamamos Orcas y que además añadiría LINQ, pasando a llamarse, entonces sí, .NET Framework 3.0. Sin
embargo, ahora lo que sabemos es que
cuando aparezca Orcas, el número de
.NET Framework será el 3.5, mientras que la versión del CLR será para
entonces la 3.0.
Asimismo, Somasegar anunció que
DLinq pasará a llamarse LINQ to SQL
mientras que XLinq se llamará LINQ
to XML. El esquema general de nombres para LINQ es el siguiente:
LINQ para ADO.NET, el cual
incluye:
LINQ to DataSet
LINQ to Entities
LINQ to SQL
El soporte de LINQ para otros
tipos de datos incluye:
LINQ to XML
LINQ to Objects
Más información en el blog de S.
“Soma” Somasegar en http://blogs.
msdn.com/somasegar, en el sitio de
MSDN en http://msdn.microsoft.com/
winfx, o en los nuevos sitios de
http://www.netfx3.com.
Microsoft libera públicamente la beta 2 de Windows Vista
Microsoft ha anunciado la disponibilidad del Programa de Evaluación
de Windows Vista Beta 2 para clientes,
pensado especialmente para aquellos
desarrolladores y profesionales de TI
que no disponen de suscripción a
MSDN y TechNet, pero que desean
recibir la beta 2 del próximo sistema
operativo de la compañía y disfrutar
de sus múltiples escenarios.
Los profesionales inscritos en este
programa podrán acceder a la beta 2
de Windows Vista a través de la des-
carga gratuita de la Web de la compañía o recibir el producto en DVD,
mediante el pago de los costes de producción y distribución.
Todos los detalles sobre la descarga de la beta 2 de Windows Vista se
encuentran en http://www.microsoft.
com/spain/windowsvista donde los usuarios también disponen de la versión
beta del asesor de actualizaciones
Windows Vista Upgrade Advisor, la
herramienta de software de diagnóstico que les ayudará a elegir la edición
de Windows Vista más adecuada a sus
necesidades, así como a conocer si sus
equipos son capaces de soportar las
características del nuevo SO.
Una vez instalada la beta 2 de
Windows Vista, los usuarios disponen de una guía de producto detallada para profesionales de TI y desarrolladores, programa antivirus para
proteger sus equipos, así como información acerca de todas las versiones
del nuevo sistema operativo, blogs,
artículos técnicos, etc.
dnm.noticias
Primera CTP de Microsoft
Robotics Studio
Más de 250 participantes se dan citan en
la 3ª edición del Borland Day
Microsoft ha presentado en la
RoboBusiness Conference and Exposition
2006, la primera CTP de Microsoft
Robotics Studio, la plataforma de desarrollo de robótica integrada y destinada a las academias, aficionados y desarrolladores comerciales, que servirá para
crear aplicaciones robóticas.
Microsoft Robotics Studio incluye
una herramienta de programación visual
que facilita la creación y utilización de
aplicaciones para robots. Permite a los
desarrolladores generar servicios modulares para hardware y software, permitiendo a los usuarios interactuar con los
robots a través de interfaces basadas en la
Web o en Windows. Por supuesto, pueden extenderse funcionalidades desarrollando con cualquiera de los lenguajes de
la plataforma .NET.
Más información y descargas en:
http://msdn.microsoft.com/robotics.
Bill Curtis,director de procesos de Borland,exhorta a los asistentes a centrarse
en la gestión del ciclo de vida de las aplicaciones como la mejor manera de
conseguir el éxito en el desarrollo de las aplicaciones.
Los robots de MSN invaden el mundo
Microsoft ha iniciado un concurso
internacional para incorporar a su servicio de mensajería instantánea MSN
Messenger (próximamente Windows
Live Messenger) nuevas funciones que
ofrezcan prestaciones complementarias a sus más de 205 millones de usuarios en todo el mundo. Esta iniciativa
está dirigida a desarrolladores de software y tiene como objetivo crear robots
inteligentes que integrados dentro del
programa de mensajería instantánea
proporcionen de forma automática e
interactiva respuestas e información a
los usuarios, como si de una persona
real se tratara.
Los creadores de los robots más útiles e imaginativos obtendrán hasta 40.000
dólares en premios, mientras que todas
las propuestas aceptadas estarán disponibles en http://www.robotinvaders.com.
Los desarrolladores tienen a su disposición en el centro de recursos de
Windows Live (http://www.msdn.com/live)
todas las herramientas , tecnologías y guía
necesarias para poder participar.
Concurso para desarrolladores sin fronteras
Programa ninemillion.org
En el Tech-Ed 2006 se anunció un
concurso que pretende animar a los desarrolladores y arquitectos de software a
presentar un diseño para una aplicación
empresarial de Office que favorezca a una
organización benéfica de su elección. Los
ganadores pueden recibir una financiación de 150.000$ en efectivo, además de
otros premios para hacer realidad sus ideas. Más en: www.developwithoutborders.com.
Coincidiendo con el Día Mundial del
Refugiado, ACNUR y Microsoft pretenden atraer la atención sobre la situación
actual de los niños refugiados en todo el
mundo. A través de su red de servicios
online MSN, Microsoft proporcionará
soporte a la campaña a través de visibilidad publicitaria y contenido editorial en
sus portales y servicios, y con alojamiento y traducción a 9 idiomas de la Web
www.ninemillion.org.
taciones y formación en esta
metodología de
procesos, están
mejorando el
desarrollo de
aplicaciones.
Además,
han participado
como ponentes, dando un
Bill Curtis, director de
valor mayor al
procesos de Borland
evento y complementando las soluciones de
Borland, las siguientes compañías:
Aventia, Coritel, EDS, Microsoft,
Oracle, Sogeti, Sun y MTP. También
han sido patrocinadores el Club-BPM,
HP, Intel y TAISA.
Además...
Windows Communication Foundation
RSS Toolkit
Este toolkit, que viene con todo el código fuente, ilustra como exponer feeds ATOM
y RSS a través de WCF endpoints. Descargar
desde http://wcf.netfx3.com/files/folders/encoders/entry3262.aspx.
Creative Commons Add-in para
Microsoft Office
Microsoft y CC se han asociado con la
finalidad de realizar una herramienta de licencia de copyright que permita una fácil adición
de la información de licencia de CC para que
se pueda trabajar con ella a través de MS
Office. Disponible gratis en http://office.microsoft.com y de http://www.creativecommons.org.
Nuevos planes para WinFS
No habrá beta 2 de WinFS y no aparecerá en solitario. Se rumorea que quizá lo haga
en 2007-2008 con Katmai, la nueva versión de
SQL Server. Ver en: http://blogs.msdn.com/winfs.
Liberada la edición CTP de SQL Server
2005 Everywhere Edition
Es la próxima versión de SQL Server
2005 Mobile Edition. Más información en:
http://www.microsoft.com/sql/ctp_sqleverywhere.mspx.
dnm.noticias
<< dotNetManía
El tema central del Borland Day
2006 ha sido la “Optimización del
Desarrollo de Software” (Software
Development Optimization – SDO) y
los diferentes ponentes han demostrado diversas maneras de alcanzar este
objetivo mediante casos reales y ejemplos de las mejores prácticas del desarrollo de software. Asimismo, y con el
mismo objetivo, se han presentado
nuevas soluciones específicas para el
gobierno y la gestión de las TI, la gestión con calidad del ciclo de vida, la
definición y gestión de requisitos y la
gestión del cambio.
Una de las temáticas más seguidas
este año, ha sido CMMI (Capability
Maturity Models Integration), donde Borland ha mostrado como sus implemen-
7
dnm.directo.eventos
José Luis Balsera
MEDC Europe 2006
Del 6 al 8 de junio se celebró en la ciudad francesa de Niza la Microsoft Mobile and
Embedded DevCon 2006 Europe, la conferencia para desarrolladores de sistemas y
aplicaciones para dispositivos móviles e incrustados que Microsoft organiza, en diversos lugares del mundo,para dar a conocer las novedades que se producen en este campo de la mano de los propios responsables de su diseño e implementación. El lema de
este año fue “Avivar el conocimiento.Acelerar el desarrollo”
<< Las sesiones se agruparon en torno a 3 ejes: el desarrollo para
José Luis Balsera es
Ingeniero Senior de
Software en Raona
(www.raona.com), donde
trabaja como
desarrollador, arquitecto
y formador en
tecnologías .NET. José
Luis está especializado
en el desarrollo de
aplicaciones móviles
usando .NET Compact
Framework y
smart clients
la plataforma Windows Embedded, el desarrollo de
aplicaciones para Windows Mobile y la movilización
de negocios usando tecnologías Microsoft. También se
ofreció la posibilidad de “tocar” código mediante prácticas en laboratorio, bien siguiendo unos guiones, bien
siguiendo las instrucciones de algún experto, sobre varios
de los temas que se trataron durante las conferencias.
Durante la sesión de presentación, Todd Warren, vicepresidente corporativo de la división de dispositivos móviles e incrustados, hizo un balance positivo de la evolución
de la tecnología y del mercado anunciando que su grupo
fue el de mayor crecimiento para la compañía de Redmond,
con un incremento del 40% anual durante ocho trimestres
consecutivos. Entre los casos de éxito comentados, todos
pertenecientes a empresas europeas, apareció el despliegue
de dispositivos basados en Windows Mobile que hizo
Correos recientemente. Lo más destacable, aparte de las
novedades que comentaremos a continuación, fue la hoja
de ruta para el lanzamiento de las nuevas versiones de los
sistemas: tanto los sistemas incrustados (CE y XP
Embedded) como Windows Mobile tendrán ciclos de 18
a 24 meses, con entregas de Feature Packs intermedias que
ofrecerán mejoras e incorporarán nuevas funcionalidades.
Por ejemplo, este año aparecerá Windows CE 6.0 y el
próximo año se lanzará un feature pack con las actualizaciones que se desarrollen en ese intervalo. Lo mismo sucederá con Windows Mobile, pero cabe destacar que las
actualizaciones de este sistema coincidirán, además, con las
de las herramientas para Visual Studio 2005.
En sintonía con la planificación expuesta este año tocaba explicar, principalmente, novedades para sistemas
incrustados. Como decíamos, se presentó la versión beta
de Windows CE 6.0, que tiene previsto su lanzamiento
definitivo durante el último trimestre de este año. En esta
ocasión el sistema ha visto totalmente remodelado su
núcleo para dar respuesta a las necesidades que ya se están
planteando y, sobre todo, a las necesidades futuras. Por
fin se ha podido superar el límite de los 32 procesos
simultáneos y la restricción a 32 MB del espacio de memoria virtual de cada uno de ellos. Los nuevos límites se
sitúan en 32.768 procesos y 2 GB de memoria sin un
aumento notable de los requisitos del sistema (300 KB es
ahora el tamaño mínimo, frente a los 200 KB en Windows
CE 5.0), lo que no se debe a que se prevea que aparezcan
dispositivos con tales requerimientos sino, como humorísticamente comentó Mike Hall, senior technical product
manager de Windows Embedded, para poder soportar el
proceso número 33 que insistentemente los desarrolladores les pedían. También ha habido cambios en la modularización del sistema. Ahora podrán ejecutarse controladores en el espacio del núcleo con la finalidad de disminuir el coste de los cambios de contexto, e incluso
podrán tener acceso a la interfaz de usuario. Obviamente,
también existirá la posibilidad de restringir controladores a un espacio de ejecución aislado, en contexto de usuario, para no perjudicar al resto del sistema. Otro cambio
importante es el de la separación física entre el kernel y la
capa que expone el hardware del dispositivo (OEM
Adaptation Layer), lo que permitirá cambiar el hardware
sin tener que modificar el diseño del sistema. Otras novedades destacables serán la mejora de los mecanismos de
seguridad y el soporte para archivos y volúmenes grandes mediante el sistema exFAT. Por último, aunque no
menos importante, la herramienta principal para el diseño
de sistemas, el Platform Builder, se ha incorporado a
Visual Studio 2005. Esto, además de permitir un trabajo
más productivo con el catálogo de componentes, ha permitido incorporar herramientas gráficas para las tareas
más comunes, introducir Intellisense en otras y aprovechar
todas las características del entorno de Visual Studio, como
puede ser el control de código fuente.
<< dnm.directo.eventos
Todd Warren, Corporate Vice President Mobile and Embedded Devices Product Group
sino que es interpretado. Microsoft orienta
el sistema a situaciones que no requieren
mucha capacidad de cálculo, aunque sí robustez y fiabilidad, sincronización de datos e
interfaz gráfica de usuario rica pero con interacción limitada. Las primeras aplicaciones
reales las veremos en los portátiles que soporten el SideShow de Windows Vista y en controles remotos para Windows Media Center.
Las sesiones dedicadas al desarrollo de
aplicaciones, tanto nativas como para .NET
Framework, estuvieron claramente enfocadas a profundizar en las técnicas para la adaptación al dispositivo, mejorar el rendimiento y aprovechar mejor las Managed API
introducidas con la versión 2 del Compact
Se presentó el .NET Micro Framework
como un CLR “bootable”
Framework. Como novedad más destacable en este ámbito, el equipo de Patterns &
Practices presentó la Software Factory for
Mobile Clients, que consiste en un conjunto de aplicaciones de referencia, patrones, application blocks, how to’s, documentación, etc., que tienen por objetivo proporcionar un entorno de desarrollo y un conocimiento de buenas prácticas para el desarrollo de aplicaciones móviles. Entre los bloques reutilizables incluidos merece la pena
mencionar el Mobile Composite UI (para construir interfaces de usuario modulares), el
Data Subscription Block (para la sincronización de datos con SQL Server), el
esto, una buena colaboración del equipo del
.NET Micro Framework y toda la estrategia de la que supieron dotar a sus algoritmos, los participantes proporcionaron una
buena diversión al público con sus “combates”. Al final, de entre los 14 equipos, los
representantes de una empresa austriaca se
alzaron con la victoria.
El concurso puso prácticamente el broche final a 3 días de sesiones, charlas informales, ejercicios prácticos y demostraciones que los más de 450 asistentes y 27 expositores pudieron compartir en una conferencia bien organizada y que esperemos
vuelva a Europa en próximas ocasiones.
<<dotNetManía
La otra estrella en el apartado de sistemas operativos fue el .NET Micro
Framework. Lo que empezó siendo el mecanismo que controlaba los relojes tipo SPOT
(MSN Direct) está evolucionando en un sistema operativo dirigido a pequeños dispositivos como sensores, actuadores, monitores
corporales para la atención médica, automatización del hogar, controles remotos, etc.
Durante la conferencia, se presentó como
novedad que aún no ha alcanzado ni el estadio de beta, por lo cual no hay ninguna certeza sobre las características de la versión final,
ni sobre cuándo estará disponible.
Simplificando los términos, se habló del
.NET Micro Framework como un CLR
“bootable”, es decir, el CLR inicia el sistema, gestiona los procesos, las interrupciones,
la memoria, etc.; incluso los controladores
de dispositivos se pueden escribir en C#.
Actualmente funciona sobre procesadores
ARM7 y ARM9, con requerimientos tan
bajos como 27MHz, 384KB de RAM y 1
MB de ROM. En realidad, el tamaño útil
mínimo del sistema es de 250 KB de ROM
y 70 KB de memoria RAM, sin necesidad de
MMU. En cuanto a su funcionalidad, cabe
destacar que, aparte de las características básicas de .NET (excepciones, delegates, garbage
collection, etc.), cuenta con los espacios de
nombres fundamentales de la biblioteca de
clases, como pueden ser System.Collec
tions, System.Threading o System.Reflec
tion. En algunos casos se han hecho modificaciones en la implementación (p. ej., datos
más compactados en System.Runtime.Se
rialization) o se ha tenido que modificar ligeramente las interfaces de las clases.
La principal diferencia con el resto de implementaciones del CLR es que, por razones de
espacio, el código no se compila just-in-time
Disconnected Service Agent (para la invocación de Web Services en escenarios de conexión intermitente) y el Orientation Aware
Control (para la adaptación de la interfaz de
usuario a los diversos formatos de pantalla
existentes). La versión presentada, que ya
está disponible en GotDotNet solo para
Pocket PC, aún no es la definitiva aunque
se espera que aparezca en unos dos meses.
En el ámbito de acceso a datos, se presentó SQL Server Everywhere, la nueva
edición de SQL Server para dispositivos
móviles, que en esta ocasión vendrá acompañada por versiones compatibles para el
entorno PC.
Las sesiones contaron con una buena
asistencia en general y bastante participación en los turnos de preguntas. Cabe destacar también la total colaboración de la
mayoría de los conferenciantes en este aspecto. Las respuestas se pudieron buscar también en las charlas con los expertos que se
organizaron en el pabellón de Microsoft.
Por último, destacaremos la sesión más
celebrada y divertida de las tres jornadas: la
competición de los Sumo Robots. Los
pequeños robots gobernados por el .NET
Micro Framework se entregaron a los grupos de asistentes que los solicitaron el primer día. Éstos pudieron asistir a una sesión
práctica que les proporcionó los conocimientos básicos para programarlos. Con
9
dnm.directo.eventos
Francisco A. González
Tech-Ed Boston 2006
Entre el 11 y el 16 de junio se celebró la decimocuarta edición de Microsoft Tech-Ed,
esta vez, en Boston, en el estado de Massachussets, sede de las prestigiosas universidades Harvard y el MIT (Massachussets Institute of Technology). El Tech-Ed es el mayor
evento a nivel mundial para desarrolladores de software de tecnologías Microsoft.
<< Con una asistencia excelente, más de 12.000 personas,
pales empresas de
la industria como
HP, ORACLE,
IBM, EMC2... La
estrella de todo el
evento ha sido el TLC (Technical Learning Centre).
Estos miniespacios estaban formados por una serie de
mesas de trabajo y stands con máquinas y software
preinstalado para que cualquiera pudiera dirigirse a
los líderes de desarrollo y managers de los distintos
productos de Microsoft así como a MVP, autores de
libros, y expertos reconocidos por Microsoft en la
industria.
Las sesiones estuvieron agrupadas en distintas tecnologías donde podemos destacar:
• Inteligencia de Negocio: donde se trataron temas
relacionados con SQL Server 2005 (Integration
Services, Analysis Services y Reporting Services),
Bussiness Scorecard Manager 2005, Office 2007,
Excel y SharePoint Portal Server.
• Sistemas Conectados: Las aplicaciones actualmente
no pueden estar en el contexto de una sola máquina
o proceso y deben comunicarse con ambientes heterogéneos, exponiendo la problemática que esto conlleva. Se vieron aplicaciones como Windows
Communications Foundation, Windows Workflow
Foundation, Windows CardSpace (WCS) (antes
InfoCard), WSE, .NET Enterprise
Services, MSMQ, .NET Remoting, System
Microsoft SQL Server 2005.
Transactions, ASP.NET Web Services,
Implementation and Maintenance, de Solid
BizTalk Server, Commerce Server, Host
Quality Learning, uno de los MCTS Training Kit
Integration Server.
(en inglés) para preparar el examen 70-431, se
• Desarrollo y Administración de
presentó en el Tech-Ed de Boston de este año,
Bases de Datos: Mostrando las nuecomo uno de los libros más vendidos.
vas características de SQL Server 2005:
rendimiento, seguridad, diseño, escalabilidad y productividad. SQL Server
Microsoft y sus “diamantes” (MVP, partners, MCT,
regional directors, etc…) mostraron la utilización de los
productos al más alto nivel así como sus experiencias
en la vida real.
El show comenzó el domingo por la noche con la
keynote, donde se lamentó la ausencia de Bill Gates
o Steve Ballmer. Bob Muglia (Senior Vice President),
Ray Ozzie (Chief Technical Officer) y Chris
Capossella (Corporate Vice President) enfocaron principalmente en la necesidad de capacitar y reconocer
a los profesionales de la informática. Con eslóganes
como “Power to the pros” (poder para los profesionales), “Do more with more” (Haz más con más) y
“People Ready” (personal preparado) se mostró el
compromiso de Microsoft de capacitar a los profesionales con las herramientas necesarias para afrontar los problemas de ahora y del futuro. El glamour
de la keynote lo ofreció la actriz de la serie norteamericana 24 Horas, Mary Lynn Rajskub que, con
humor, continuó enfatizando la importancia del personal IT en las organizaciones.
En total hubo más de 1.000 sesiones en sus distintas modalidades. Sesiones formales, grupos de discusión, desayunos y cenas de trabajo, laboratorios
tutorizados y un sinfín de actividades. Alrededor de
todas estas actividades estaba la feria con las princiFrancisco A.
González Díaz trabaja
como Ingeniero de
Integración de Solid
Quality Learning. Es
Ingeniero Superior en
Informática por la
Universidad de Murcia.
MCP en BizTalk Server.
<< dnm.directo.eventos
2005, ADO.NET, SQL Server
2005 Express y SQLCLR fueron
de gran interés en esta edición del
Tech-Ed.
• Herramientas para desarrolladores: donde se abarcó el ciclo de
desarrollo utilizando Visual Studio
Team System. Las herramientas
destacadas en este grupo fueron:
Visual C#, Visual Basic, Visual
Studio, Debugging, .NET
Framework, 64-bit, CLR, Visual
Studio Team System, Windows
Form, Smart Clients y Windows
Mobile 5.0.
Novedades
Durante el Tech-Ed fuimos testigos
de bastantes novedades, no solo del
anuncio de abandono del día a día, en
el equipo de Microsoft, por parte de Bill
Gates a mediados de 2008 dejando al
mando a Steve Ballmer, sino también
supimos que en los próximos 16 meses
tendremos nuevas versiones del top 3
de los productos de Microsoft en rentabilidad y uso. Tendremos Office 2007,
Windows Vista a principios de 2007 y
en otoño de 2007 llegará Longhorn
Server, el nuevo sistema operativo de
servidor que reemplazará a Windows
Server 2003.
Otra de las novedades más reseñables es que Microsoft ha renombrado
su software en el apartado de seguridad
con un nuevo producto llamado
Microsoft Forefront, que contiene
Microsoft Forefront Client Security
(actualmente Microsoft Antigen for
Exchange), Microsoft Forefront
Security for SharePoint (actualmente
Microsoft Antigen for SharePoint),
Microsoft Antigen for Instant
Messenger y Microsoft Internet
Security & Acceleration Server 2006
(servidor para la protección de amenazas por Internet en las organizaciones)
Chris Capossela anunció la disponibilidad Exchange Server 2007 Beta
2 para finales de 2007. Alex Cobb anunció BizTalk Server 2006 R2 y un nuevo paquete de adaptadores que se presentarán próximamente.
En cuanto a High Performance
Computing (HPC), Microsoft presentó
Computer Cluster Server 2003, que
responde a la demanda para la ejecución
de aplicaciones en paralelo o de gran consumo de recursos. Entre sus objetivos
están las aplicaciones científicas que
requieran grandes cálculos o el procesamiento de tareas de business intelligence.
En los próximos 16 meses tendremos nuevas versiones
del top 3 de los productos de Microsoft en rentabilidad
y uso.Tendremos Office 2007,Windows Vista a principios
de 2007 y en otoño de 2007 llegará Longhorn Server
Además, los asistentes pudimos
obtener la primera edición CTP del
Visual Studio Team Edition for
Database Professionals, un nuevo
producto de la línea Team System
(http://msdn.microsoft.com/vstudio/te
amsystem/products/dbpro).
Durante esta semana, Tech-Ed ha
creado un lugar para el intercambio
de conocimiento, anuncios y debates
sobre tecnología, con una gran cantidad de personal de Microsoft y profesionales de todo el mundo en un
ambiente internacional. Próxima cita:
Tech-Ed Europe en Barcelona a principios de noviembre. Les mantendremos informados.
Solid Quality Learning en
el Tech-Ed de Boston
En el TLC de SQL Server, con el
eslogan “Always on Technologies”,
Solid Quality Learning tuvo un papel
destacado. Un gran conjunto de sus
mentores impartió sesiones,
demostraciones y presentó libros y
proyectos junto con Microsoft.
Además, tuvimos dos buenas
noticias: la primera es que supimos
que el Training Kit sobre SQL Server
2005 desarrollado por Solid Quality
Learning y recién publicado está en
la lista de más vendidos de Amazon;
y la segunda es el reconocimiento a
Mauro Sant’Anna, uno de los
mentores de Solid Quality Learning,
como regional director del año.
<<dotNetManía
Estas no fueron las únicas líneas, pues
se trataron todos los productos de
Microsoft relacionados con arquitectura,
aplicaciones para negocios, Management
and Operations, mensajería y movilidad,
Microsoft Application Platform,
Microsoft IT, Office System, seguridad,
soluciones verticales para la industria,
desarrollo Web, Windows Client,
Windows Server Infrastructure, etc.
Alejandro Leguizamo, mentor de Solid Quality Learning en uno de los ChalkTalk
sobre minería de datos con SQL Server 2005 Analysis Services
11
dnm.directo.entrevistas
Marino Posadas
Entrevista a Arvindra Sehmi
Nuestro entrevistado de hoy es la cabeza visible del Enterprise Team en Microsoft
Corp’s Developer and Platform Evangelism Group en Europa, Oriente Medio y
África (EMEA) y su trabajo se focaliza hacia la adopción de las mejores prácticas dentro de la comunidad de arquitectos de EMEA.
<< Antes de nada, a modo de presentación, ¿cuál es tu
Marino Posadas es
asesor técnico y
redactor de
dotNetManía, MVP de
C# y formador de
Alhambra-Eidos
labor actual en Microsoft?
Pertenezco al grupo de Desarrollo y Plataforma
de Microsoft para Europa, Oriente Medio y África, y
tengo a mi cargo el Enterprise Team de Arquitectura.
Soy responsable de dos tipos principales de arquitectos: los de soluciones y los de infraestructura. También
realizamos labores de marketing y soy además el encargado de suministrar asistencia a nuestros “partners”
y asociados de desarrollo respecto a cuestiones de
arquitectura. Aparte de eventos de gran calado, como
puedan ser los IT Forums o el Tech-Ed, promovemos acciones del tipo workshop, o Deep-Dives (cursos
de inmersión profunda), sobre
tecnologías fundamentales,
generalmente en la línea del
producto que aparece a corto/medio plazo. De igual forma,
en ocasiones asesoramos a clientes en formato “uno a uno”, esto
es con asesorías personalizadas
sobre desarrollos puntuales, para
ofrecerles diseño de soluciones
y revisión de estructuras arquitectónicas.
Paulatinamente, las tecnologías vinculadas con los servicios Web han ido siendo
aceptadas e implantadas en
soluciones actuales, pero la
impresión es que –todavíaSOA como arquitectura no es
lo suficientemente compren-
dida y adoptada. ¿Cuál sería tu consejo a este respecto?
La primera cuestión sería separar los dos conceptos, al menos inicialmente, aunque pertenezcan
al mismo grupo conceptual. Respecto a los servicios
Web, tenemos claro que son la tecnología que va a
servir de base a todo lo que signifique interoperabilidad. Y, además, incluyen todo lo que suministran los Web Services Enhancements, ahora en su versión 3.0. En Vista y Longhorn, esta tecnología está
presente dentro de WCF (antes Indigo), que incluye estos estándares vinculados a los servicios Web.
Tenemos un modelo de programación bastante sofis-
Marino Posadas y Arvindra Sehmi
<< dnm.directo.entrevistas
¿Puede Microsoft ofrecerte una guía de
construcción, una asesoría puntual, para
ayudarte a la resolución de esos problemas
arquitectónicos? Totalmente. Esa es una de
las cosas que hace mi equipo
<<dotNetManía
ticado, que es la base de Indigo, pero no nos olvidamos de los niveles más inferiores y sus posibilidades.
Ahora bien, todo esto no significa sino que la
orientación a servicios es una de las posibilidades
arquitectónicas que las nuevas plataformas van a
ofrecer, pero ni mucho menos la única. Si hablamos genéricamente de una orientación a servicios
(una arquitectura SOA), existen varios principios
que deben de cumplirse, uno de los cuales consiste
en identificar exactamente los límites de la arquitectura de negocio, los contratos de negocio necesarios para su funcionamiento, etc. Y nunca hablando de productos, sino simplemente de estructuras
arquitectónicas del software. El paso siguiente es
hacer corresponder esa arquitectura con una implementación concreta, donde sí intervendrán productos concretos.
Si eso se hace utilizando herramientas vinculadas
con .NET, puedes usar tecnologías punteras, como
BizTalk o SharePoint, por ejemplo, y tienes muchas
otras posibilidades…
Como la de construirlo tú mismo si conoces suficientemente bien los principios en que se basa…
Exactamente. Ahora bien, ¿puede Microsoft ofrecerte una guía de
construcción, una asesoría puntual,
para ayudarte a la resolución de esos
problemas arquitectónicos? Totalmente. Esa es una de las cosas que
hace mi equipo.
Así pues, Indigo dará toda la infraestructura para diversas soluciones de
comunicación. Pero eso nos lleva a
una pregunta sobre remoting. ¿Se le
supone obsoleto, a la vista de las novedades venideras?
No realmente. Todavía va a
estar ahí, y nos ha
ayudado a comprender mucho
mejor los problemas vinculados a
las arquitecturas
distribuidas. Lo
que sucede es que
las restricciones
de remoting (su
propia naturaleza) no lo capacitan para ciertas
soluciones distribuidas de naturaleza heterogénea,
y además no
Arvindra Sehmi
cumple con ciertos principios de la orientación a servicios, especialmente en lo referente a los contratos y el formato de
intercambio basado en mensajes.
¿Sería adecuado decir que si tienes totalmente
el control del dominio de instalación, la opción de
remoting es perfectamente válida y de buen rendimiento, pero si no es así la opción mejor serían los
servicios Web?
Te diré que –de hecho- esa es exactamente la forma en que lo estamos recomendando. Y además, remoting va a formar parte integrante del modelo de programación de Indigo. Todavía es muy consistente, si
te encuentras dentro de estos términos.
Otra cuestión que surge vinculada con la adopción de estas arquitecturas es el rendimiento (o la
posible penalización asociada a su implantación).
¿Qué puedes decirnos al respecto?
El rendimiento está asociado muchas veces con
el mensaje intercambiado; con su formato después
de la seriación. De ahí que –tanto en Indigo como
en .NET 2.0- hayamos optimizado notablemente
la forma en que se serian los mensajes XML para
favorecer este aspecto. De hecho, ya hay comparativas de rendimiento muy favorables respecto a la
13
<< dnm.directo.entrevistas
<<dotNetManía
Respecto a los servicios
Web, tenemos claro que
son la tecnología que
va a servir de base a
todo lo que signifique
interoperabilidad.Y,
además, incluyen todo
lo que suministran los
Web Services Enhancements,
ahora en su versión 3.0.
En Vista y Longhorn, esta
tecnología está presente
dentro de WCF (antes
Indigo), que incluye estos
estándares vinculados
a los servicios Web
14
utilización de servicios Web. Respecto
al protocolo HTTP, resulta muy apropiado para una semántica preguntarespuesta. Se pueden utilizar otros
transportes, como TCP/IP, MSMQ,
SMTP o incluso algún otro tipo. Pero
la importancia de disponer de distintos transportes es que podemos seleccionar distintos modelos como el
asincrónico unidireccional (garantizado y fiable), o puedes seleccionar un
mecanismo bidireccional y utilizarlo
junto a un estándar de servicios extendidos como WS-Reliable Messaging o
WS-Security.
Además, la gente está empezando
a construir aplicaciones cada vez más
y más complejas y el ajuste de rendimiento para estas aplicaciones se vuelve un asunto crucial en la implantación. Y a veces el problema está en que
no acaban de comprender las implicaciones que la elección de una determinada arquitectura tiene en ese rendimiento. Y por otro lado, suministramos mecanismos para realizar las
cosas de forma muy sencilla, de manera que también se corre el riesgo de
que el desarrollador adopte el principio del mínimo esfuerzo sin analizar
suficientemente las consecuencias de
la adopción de una determinada técnica. Por eso suministramos guías y
documentación (un montón de documentación, de hecho…).
Otra cuestión que vincula al desarrollo con la arquitectura y la facilidad
de uso de un programa tiene que ver
con el modelo de propone Vista para la
construcción de aplicaciones. O sea,
¿Cómo es posible unificar los modelos
de aplicación Windows y Web, tan distantes en un principio?
Básicamente porque vamos a contar con los medios para describir cómo
va a ser la interfaz de usuario mediante XAML. Tú suministras esa descripción de la IU a un motor de interpretación. Si éste es de tipo Web,
obtienes páginas Web, si se trata de
un intérprete de Windows, obtienes
aplicaciones Windows Forms. XAML
es –realmente– una forma en la que
puedes seriar objetos. Puedes entenderlo como una generalización de la
seriación de objetos para la interfaz
de usuario.
¿Crees que, quizá, la falta de conocimiento profundo de cuál es la forma
correcta de implantar arquitecturas en
capas constituye la principal barrera para
su adopción masiva?
Sin duda. Especialmente, de la forma de organizar la comunicación entre
capas y la forma es que esta comunicación tiene diferentes impactos tanto en
el desarrollo como en el rendimiento
final de la aplicación. Se necesita comprender bien la arquitectura completa
end-to-end, incluyendo las restricciones
de implantación.
En otro orden de cosas, hemos visto que Microsoft ha anunciado una nueva titulación relacionada con la arquitectura de aplicaciones. ¿En qué va a
consistir?
Hemos estado recogiendo la opinión de nuestros partners a ese respecto para acotar exactamente el alcance
que debería de tener. E incluso hemos
hablado con grandes partners de cara
una unificación de criterios (Intel,
Lotus, IBM, HP, etc.). De hecho,
hemos establecido un sistema de mentoring, de forma que cualquiera que
desee certificarse pueda contar con ese
sistema en un período de 12 a 18 meses
que consideramos el mínimo imprescindible antes de abordar las pruebas
finales. Será un requisito enviar una
serie de documentación para la certificación, ya que es difícil evaluar este tipo
de conocimiento simplemente con sistemas on line. Es algo que recuerda a la
defensa de una tesis que tú realizarás
ante un grupo de expertos en arquitectura, para evaluar tus conocimientos.
Y finalmente, tus recomendaciones
para los que quieran abordar estas tecnologías…
Pasar por una fase previa de estudio y pruebas similar a la que recomendamos para los exámenes que describía anteriormente. Libros y artículos sobre buenas prácticas, disponibles
en MSDN, asistencia a foros, simposios y eventos sobre arquitectura, asimilación de patrones de diseño y su
implantación en .NET Framework, y
analizar aplicaciones ya resueltas y disponibles, tales como Global Bank
Infrastructure, donde se explican todos
estos términos en fases y desde diferentes perspectivas.
dnm.asp.net
José M.Alarcón
WebParts en ASP.NET 2.0 (y III)
Con este artículo finalizamos la serie sobre WebParts comenzada hace dos números
en dotNetManía. En él trataremos algunos conceptos avanzados sobre bloques personalizables que nos permitirán llegar a un buen nivel en el desarrollo de este tipo de
aplicaciones.En concreto,veremos cómo intercambiar información entre ellos y cómo
exportarlos para su reutilización.
<< Con lo visto hasta ahora ya estamos en condiciones de
construir complejas aplicaciones Web personalizables
que eran impensables hasta la aparición de la versión
2.0 de ASP.NET. Sin embargo, hay ciertas funcionalidades que nos resultarían muy convenientes y que
todavía no sabemos hacer: por ejemplo, establecer una
comunicación entre los bloques.
El hecho de poder separar nuestra aplicación en bloques de funcionalidad que luego se pueden distribuir a
voluntad dentro de una o varias páginas es algo muy interesante. Sin embargo, en cuanto empecemos a usarlos
en aplicaciones reales nos daremos cuenta de que no basta con tener esto. En la mayor parte de los casos no triviales veremos que es necesario que los bloques existentes, independientemente de su ubicación, se comuniquen entre sí. Por ejemplo, podemos disponer de un bloque que muestre una lista de productos y otro que sirva
para ver un informe de ventas de esos productos. Si no
podemos hacer que lo escogido en el primero influya en
los resultados que muestra el otro, los bloques no nos
valdrán de mucho.
Comunicación entre bloques
José Manuel Alarcón
es redactor de dotNetManía.
Es ingeniero industrial y
especialista en consultoría de
empresa. Ha escrito varios libros,
y ha publicado más de
doscientos artículos sobre
informática e ingeniería en
revistas especializadas.Visita su
blog en www.jasoft.org.
El ejemplo anterior es solo uno más de los muchos
que se nos pueden ocurrir, pero evidencia la necesidad
de varias funcionalidades para conseguir nuestro objetivo. En primer lugar, necesitamos alguna forma de que
la información fluya entre los bloques. Pero no llega solo
con eso, ya que tenemos que asegurarnos de que solo los
bloques compatibles sean capaces de comunicarse (la
información del producto seleccionado puede que no
signifique nada para otros bloques que haya en la misma página). Finalmente, debemos encontrar un método estándar que permita relacionar desde la interfaz de
usuario a los bloques compatibles entre sí, independientemente del tipo de datos que intercambien.
Para construir la comunicación entre dos bloques
debemos hacer lo siguiente:
1. Decidir qué datos vamos a intercambiar, cuál es
su tipo, su formato y su cantidad. Definir una interfaz que permita intercambiar dicha información.
2. Definir uno de los controles como proveedor.
3. Definir otro (u otros) como consumidor(es).
4. En caso de querer una conexión estática, hay que
definir ésta.
5. En caso de necesitar conexiones dinámicas (decididas por el usuario en tiempo de ejecución), es
necesario usar un control especial para definirlas.
Vamos a crear un ejemplo simple que ilustre todo el
proceso. Crearemos dos WebParts mediante controles
de usuario. En uno de ellos habrá un campo de texto
cuyo contenido será transmitido al otro bloque, de modo
que siempre que haya alguna variación en el primero se
vea reflejada en el segundo.
Dado que los principios básicos de comunicación
entre WebParts son los mismos, le resultará fácil reconstruir el ejemplo para comunicar cualquier otro tipo de
información, incluso más compleja formada por diversos miembros.
Primer paso: la interfaz de comunicación
En este caso lo que se transmitirá desde un bloque al otro es simplemente texto (el contenido del
cuadro de texto del control origen de datos). Podría
ser el identificador de un producto, o una estructura
compleja que represente varios atributos de un cliente, por ejemplo. En cualquiera de los casos, lo que
<< dnm.asp.net
debemos tener muy claro antes de hacer nada es qué
se va a transmitir, para luego ser consecuentes en la
definición de toda la arquitectura.
En el caso que nos ocupa, dado que sólo es texto,
podemos definir en la carpeta App_Code (para que esté al
alcance de toda la aplicación) una interfaz como ésta llamada ITextTransfer:
Partial Class Proveedor
Inherits System.Web.UI.UserControl
Implements ITextTransfer
Public Function Texto() As String
Implements ITextTransfer.Texto
Return TextBox1.Text
End Function
End Class
Fuente 2
Más sencilla – imposible. Su único miembro es un
método que devuelve una cadena. En lugar de una función, podríamos haber definido también una propiedad
de solo lectura. Si lo que intercambiamos es algo más
complejo que una cadena, bastará con definir una clase
o estructura en alguna parte y devolverla a través de la
interfaz.
Esta interfaz es la que se pasará entre ambos extremos de la conexión.
Segundo paso: definición de la fuente o
proveedor
Ahora vamos a crear un control que se encargará
de enviar datos a los posibles consumidores que definamos. Agregue al proyecto un nuevo control de usuario llamado Proveedor.ascx y agregue sobre su superficie un control TextBox y un botón. No es necesario
introducir código alguno para responder a los eventos de estos dos elementos. El cuadro de texto será un
mero contenedor de información y el botón lo usaremos únicamente para forzar el envío de datos al servidor (es decir, para forzar un postback):
<asp:TextBox ID=”TextBox1” MaxLength=”16” Runat=”server” />
<asp:Button ID=”Button1” Text=”Enviar datos” Runat=”server” />
Fuente 1
Como proveedor de la información textual que
nos interesa, este control deberá implementar un
método que proporcione acceso a un objeto que implemente la interfaz que hemos acordado en el paso anterior, el cual será “enviado” a los consumidores con los
que se comunique.
El objeto que implementa esta interfaz puede ser
una clase definida para la ocasión o, más comúnmente, puede ser el propio WebPart, que en ese caso deberá
implementar la interfaz. Es decir, en nuestro ejemplo,
deberá definir un método Texto tal y como indica ésta
en el fuente 2.
Lo único que hace la función es devolver la información que nos interesa, o sea, el contenido del cuadro de
texto. Además, como ya he dicho, es necesario indicar a
la infraestructura de WebParts cómo se realizará la comunicación y que éste es un bloque que proveerá de datos a
otros. Esto se consigue definiendo un método cualquiera que devuelva la interfaz de comunicación y marcándolo como proveedor de origen de conexiones, así:
<ConnectionProvider(“Proveedor”, “ProveedorID”)> _
Public Function GetTextTransferInterface() As ITextTransfer
Return Me
End Function
Fuente 3
En este código vemos la definición de un método
que lo único que hace es devolver una referencia al propio control, que será el origen de la conexión. El método se puede llamar como queramos. Finalmente, y lo
más importante, el atributo ConnectionProvider sirve
para indicar a la infraestructura de WebParts que este
método actúa como origen de una conexión entre bloques, e indicamos como atributos la descripción y el identificador único que le otorgamos a dicho origen.
Esto es tal vez lo más complicado de entender de
todo el proceso, así que medítelo un rato antes de continuar leyendo. En cualquier caso, como se ve en el fragmento anterior, si bien es algo complejo conceptualmente
es muy fácil de implementar en la práctica.
Tercer paso: definir un consumidor de
datos
La construcción del consumidor de datos sí que es
realmente sencilla. Lo único que debemos hacer es definir un método que reciba como parámetro la interfaz de
intercambio de datos que hemos decidido antes y decorarlo con un atributo.
Añada un control de usuario al proyecto y llámelo Consumidor.aspx. Arrastre sobre su superficie una
etiqueta de texto. En ella
NOTA
mostraremos el texto que
emite el proveedor del paso
En el anterior artículo de esta serie se afiranterior.
maba que sólo se pueden crear verbos perEn la vista de código
sonalizados al definir WebParts puros, pero
fuente del control defino en controles de usuario. En realidad sí
na un método para asiges posible implementando la interfaz
nar el contenido de la
IWebActionable. Muchas gracias a Juan Luis
Ceada por apuntar esta posibilidad.
etiqueta como en el
fuente 4.
<<dotNetManía
Public Interface ITextTransfer
Function Texto() As String
End Interface
17
<< dnm.asp.net
<ConnectionConsumer(“Consumidor”, “ConsumidorID”)> _
Public Sub GetTextTransferInterface(_
ByVal proveedor As ITextTransfer)
Label1.Text = proveedor.Texto()
End Sub
Fuente 4
El control no necesita implementar la interfaz, ya
que sólo la consume. Basta con definir un método similar a éste en el que el único parámetro es un objeto que
implementa la interfaz de intercambio de datos y que
está decorado con un atributo ConnectionConsumer que
indica a la infraestructura de WebParts que se trata de un
punto final en una conexión, especificando su descripción y un identificador único.
Dentro del método el código es muy sencillo ya que
tenemos una referencia al control origen de datos de la
conexión, y sólo tenemos que llamar al método Texto de
la interfaz para obtener la cadena que está contenida dentro de su cuadro de texto.
Este método será llamado de forma automática
por parte de la infraestructura de WebParts siempre
que sea necesario refrescar los contenidos de la conexión, por lo que nuestro bloque no tiene que preocuparse de nada más.
Si en lugar de usar controles de usuario hubiésemos
implementado un control WebPart real, la forma de proceder sería exactamente la misma.
Cuarto paso: conexiones estáticas
<<dotNetManía
Una vez que hemos definido correctamente el conducto de paso y los dos extremos de la conexión, sólo
resta conectarlos entre sí. La forma más sencilla de
hacerlo es definir una conexión en tiempo de diseño
entre un control fuente y un control consumidor. Es
el control WebPartManager, encargado de controlar toda
la lógica de la página, el que nos facilita los medios
necesarios.
18
Figura 1
Arrastre un ejemplar de cada control que acabamos de crear a sendas WebPartZone de la página de
ejemplo. Ahora seleccione el control WebPartManager1
y en sus propiedades pulse el botón de la propiedad
StaticConnections, como se ilustra en la figura 1. En
el diálogo que aparece solo tendremos que agregar un
nuevo elemento y establecer el nombre de los controles que queremos conectar usando las propiedades
ProviderID y ConsumerID para la fuente y el sumidero
de información respectivamente.
Como es obvio, estos controles deben haber sido
definidos con la función correspondiente y deben usar
la misma interfaz de comunicación. Si no fuese así, se
produciría un error nada más ejecutar la página.
Como resultado de haber usado este diálogo se incluye un elemento WebPartConnection en las etiquetas de la
página (figura 2).
Figura 2
Quinto paso: conexiones dinámicas
Es probable que el establecimiento de conexiones
estáticas sea el más interesante en la mayor parte de las
situaciones, ya que no podemos esperar que un usuario
medio tenga la capacidad (o más bien el interés) de definir sus propias conexiones entre bloques. Aún así, para
cierto tipo de aplicaciones con usuarios más avanzados
sí puede resultar de útil permitir que sea el propio usuario el que defina de qué forma quiere conectar unos elementos con otros. Esto es especialmente cierto cuando
un mismo control de origen puede actuar como fuente
para varios controles sumidero, cada uno especializado
en ofrecer determinada información a partir de los datos
facilitados por el primero. Por ejemplo, imaginemos una
típica página de cuadro de mandos para ejecutivos en la
que nuestros usuarios escogen lo que necesitan ver.
Podemos definir ciertos controles proveedores que listen los productos y regiones en las que actúa nuestra
empresa, así como otro para ofrecer los años de actividad para los que existen datos. Si construimos diversos
controles sumidero que pueden enlazarse a todas estas
fuentes (incluso a varias a la vez) para mostrar informes,
gráficas de ventas, etc., ofreceremos una potente herramienta para consulta de información en la que cada uno
de nuestros usuarios será capaz de ver exactamente lo
que necesita. Sólo tendrán que arrastrar los controles
“filtro” (orígenes) y los visualizadores en los que tengan
interés y, en cuanto los enlacen, podrán navegar por la
información de la manera que deseen y con la distribución en pantalla que les resulte más cómoda.
<< dnm.asp.net
Figura 3
Figura 5
Figura 4
En situaciones como ésta es cuando
necesitamos las conexiones dinámicas.
En realidad, es también muy sencillo
obtener esta funcionalidad. Basta con
hacer uso del control ConnectionsZone disponible en la barra de herramientas de
“Elementos Web en Visual Web Developer” (figura 3). Arrastre uno de estos a
la columna derecha de la tabla que hemos
estado usando en nuestros ejemplos. En
la figura 4 podemos ver el aspecto que tiene sobre la superficie de diseño. En el control de catálogo añada los dos controles
(la fuente y el sumidero) que acabamos de
crear para que estén disponibles en la página. Por fin, añada un último control
LinkButton para pasar al modo de conexión del WebPartManager. En su propiedad
Text escriba “Conectar bloques”, y como
resultado de su pulsación use el código del
fuente 5.
Al pasar a modo de conexión veremos
que aquellos bloques que son fuente o
sumidero de datos disponen de una opción
Figura 6
Fuente 5
al paso final en el que se muestra el resultado de la operación.
Una vez establecida la conexión,
vamos a probarla. En el control origen
introduzca una frase cualquiera en el
campo de texto y pulse el botón para
provocar un postback al servidor. A partir de ese momento, la frase aparecerá
reflejada en el control sumidero en todo
momento, manteniéndose sincronizado el contenido de ambos entre los postbacks (figura 6).
Exportación de WebParts
Si disponemos de un WebPart complejo, que ofrece muchas propiedades
para configurar o las que tiene son complicadas, será interesante brindar la posibilidad de guardar sus ajustes para reutilizarlos. Así podremos hacer un uso posterior en el mismo portal o incluso llevárnoslo a otro portal que disponga del mismo control. De hecho, éste no tiene ni
por qué ser el mismo, ya que mientras se
llame igual y posea propiedades con el
mismo nombre y tipo será compatible la
<<dotNetManía
nueva en su menú desplegable de acciones: “Conectar”. Al elegirla, aparece el
diálogo de creación de conexiones en la
página. Éste va mostrando diversos aspectos a medida que se establece la conexión.
La figura 5 ilustra los tres pasos necesarios para crear una conexión dinámica
y el aspecto del control en cada uno de
ellos. El paso 1 aparece tras elegir el método “Conectar” en el menú desplegable del
control origen de datos. Simplemente insta al usuario a crear una nueva conexión
para éste pulsando sobre el enlace de la
parte superior. También informa de las
conexiones existentes con origen en éste,
de haber alguna anterior. A continuación,
se permite seleccionar el control sumidero o destino de la conexión, para lo cual
debemos elegirlo de una lista desplegable.
En ésta sólo se muestran los controles que
estén presentes en la página
y que implementen la interProtected Sub LinkButton5_Click(ByVal sender As Object,
faz común de comunicaByVal e As System.EventArgs) Handles LinkButton5.Click
ción que tiene el control
WebPartManager1.DisplayMode =
WebPartManager.ConnectDisplayMode
origen. Una vez elegido el
End Sub
control se pulsa sobre el
botón “Conectar” y se llega
19
<< dnm.asp.net
Figura 7
información transferida, puesto que los
ajustes se hacen mediante reflexión y no
con tipos estrictos.
Para que un bloque pueda exportar
sus propiedades hay que indicar esta
necesidad en el constructor de la clase,
usando su propiedad ExportMode. En la
figura 7 se observan los tres posibles valores que tiene esta propiedad: exportarlo
todo, no exportar nada (valor por defecto) o exportar sólo aquello que no sea
confidencial.
Normalmente no tendremos propiedades confidenciales, pero es posible que
en ocasiones pudieran hacernos falta. Si,
por ejemplo, una de las propiedades del
WebPart es la clave que éste necesita para
conectarse a un origen de datos y obtener
sus contenidos, no deberíamos permitir
que se exporte y esté al alcance de cualquiera. Para marcar una propiedad como
confidencial debemos usar una de las
sobrecargas del atributo Personalizable
ya visto, cuyo segundo argumento es precisamente un booleano para indicarlo:
<<dotNetManía
Personalizable(
PersonalizationScope.Shared, False)
20
No basta con marcar un bloque como
exportable. Se debe habilitar explícitamente la capacidad de exportación de la
infraestructura desde el archivo de configuración web.config usando el atributo
enableExport del nodo <webParts> y estableciéndolo como verdadero.
Al hacer todo esto, el control ofrecerá
una opción de exportación en su menú
desplegable. Al elegirla, se creará un archivo con el mismo nombre que el título del
control y extensión .WebPart que podremos almacenar en disco. Se trata de un
archivo XML en el que aparece el nombre del tipo del control y una serie de
nodos con las propiedades del control y
sus valores en el momento de la exportación. Por ejemplo, vea el fuente 6.
Este es el XML resultante de exportar el control que creamos antes y que sirve para mostrar el nombre de usuario de
Windows actual. La mayor parte de las
para las propiedades, forzar la carga de ciertos controles potencialmente dañinos, o
saturar la memoria del servidor forzando
la carga de muchos controles. Por ello la
importación de WebParts debería estar per-
<?xml version=”1.0” encoding=”utf-8”?>
<webParts>
<webPart xmlns=”http://schemas.microsoft.com/WebPart/v3”>
<metaData>
<type name=”Jose.WebParts.UsuarioWebpart” />
<importErrorMessage>No se puede importar este elemento Web.</importErrorMessage>
</metaData>
<data>
<properties>
<property name=”AllowClose” type=”bool”>False</property>
<property name=”Width” type=”unit” />
<property name=”AllowMinimize” type=”bool”>True</property>
<property name=”ExportMode” type=”exportmode”>All</property>
<property name=”AllowConnect” type=”bool”>True</property>
<property name=”ChromeType” type=”chrometype”>Default</property>
<property name=”TitleIconImageUrl” type=”string” />
<property name=”Description” type=”string” />
<property name=”Hidden” type=”bool”>False</property>
<property name=”TitleUrl” type=”string” />
<property name=”AllowEdit” type=”bool”>True</property>
<property name=”Height” type=”unit” />
<property name=”HelpUrl” type=”string” />
<property name=”Title” type=”string”>Usuario Windows actual</property>
<property name=”CatalogIconImageUrl” type=”string” />
<property name=”Direction” type=”direction”>NotSet</property>
<property name=”ChromeState” type=”chromestate”>Normal</property>
<property name=”AllowZoneChange” type=”bool”>True</property>
<property name=”AllowHide” type=”bool”>False</property>
<property name=”HelpMode” type=”helpmode”>Navigate</property>
<property name=”Mayusculas” type=”bool”>False</property>
</properties>
</data>
</webPart>
</webParts>
Fuente 6
propiedades son las estándar para un
WebPart, y además serializa también nuestra propiedad Mayusculas (al final).
Todo esto está muy bien pero, ¿de qué
vale exportar estos valores si no podemos
importarlos? Vamos a ver cómo se hace,
ya que es también muy sencillo. Basta con
añadir un control ImportCatalogPart a la
zona de catálogos de nuestra página. Al
hacerlo, cuando pasemos a modo catálogo se nos ofrece la posibilidad de buscar
un archivo con extensión .WebPart en el
disco duro y subirlo a la Web. Al recibirlo, se trata de instanciar un objeto del tipo
indicado en el archivo que herede de
WebPart, y se ajustan sus propiedades. Así
de sencillo.
Obviamente, esta característica tiene
implicaciones de seguridad importantes,
puesto que un usuario malicioso puede crear archivos XML con valores inadecuados
mitida únicamente a usuarios de alto rango, y aún así las propiedades de los controles deberían hacer una buena validación
de los datos que les lleguen.
En resumen
A lo largo de estas tres entregas hemos
estudiado toda la infraestructura de
WebParts que ofrece ASP.NET 2.0. Se
trata de una característica muy espectacular en esta versión y que abre todo un
mundo de posibilidades para el programador que sepa sacarle partido. Hemos
aprendido prácticamente todo lo que
necesita saber para hacer aplicaciones
complejas con la infraestructura de bloques, desde los fundamentos hasta las
características más avanzadas. Espero que
estos contenidos le hayan resultado útiles
y provechosos.
dnm.futuro
Octavio Hernández
Lo que nos traerá Orcas:
VB 9.0 y LINQ
Este artículo presenta las novedades que incluirá (probablemente con algunas
variaciones) Visual Basic 9.0, incluyendo la sintaxis de las expresiones de consulta, que constituyen el principal reflejo en el lenguaje de la tecnología LINQ,
y las extensiones para el soporte directo de XML.
<< Ya en una entrega anterior hemos presentado los fundamentos de LINQ (Language INtegrated Query),
una combinación de extensiones al lenguaje y
librerías de código manejado que permite expresar
de una manera uniforme consultas sobre colecciones de datos provenientes de las más diversas fuentes: objetos en memoria, bases de datos relacionales o documentos XML, entre otros. Si bien los
ejemplos que acompañaban a ese artículo estaban
codificados en C#, entonces mencionamos que la
tecnología LINQ estaría disponible no solo para
los programadores de este lenguaje, sino
que Visual Basic 9.0 (la versión del lenguaje que implementará “Orcas”)
también ofrecería las mismas facilidades (e incluso algunas más, podríamos añadir ahora) para expresar
directamente con los recursos del
lenguaje colecciones de datos de
diferente naturaleza y consultas sobre
ellas.
Requisitos preliminares
Octavio Hernández
es colaborador habitual
de dotNetManía,
Ingeniero en
Informática de Sistemas
y MVP de C#.
Para probar los ejemplos de código que acompañan al artículo, el lector deberá instalar la presentación preliminar de LINQ, disponible en la URL
que se indica en la bibliografía [1]. El software de
mayo de 2006 incluye versiones previas de los compiladores de C# 3.0 y VB 9.0, varios ensamblados en
los que se implementan las novedades y la tecnología LINQ, y un conjunto de plantillas de proyectos que se muestra en la figura 1.
Adicionalmente, se ofrece un directorio de ejemplos
de código y otro de documentación. Recomendamos
especialmente la lectura de los documentos incluidos
en el directorio Docs, así como el análisis y ejecución
de los ejemplos.
Los ejemplos que se presentan en este artículo se
apoyan en la clase Persona de entregas anteriores.
Aunque está claro que en principio no habría sido
necesario (uno de los objetivos centrales de .NET es
precisamente facilitar la interacción de módulos desarrollados en diferentes lenguajes), el fuente 1 presen-
Figura 1. Plantillas de proyectos LINQ
en Visual Basic
ta una versión de la clase implementada en Visual Basic 9.0.
Nuevas características “básicas” de VB 9.0
En este punto introduciremos las
novedades de más bajo nivel que incluye Visual Basic 9.0 y que en mayor o
menor medida sirven como fundamento o pueden ser utilizadas en combinación con aquellas que directamente
están relacionadas con LINQ y sus tecnologías “derivadas”. Estas novedades
“básicas” son las siguientes:
• Determinación implícita del tipo de
variables locales.
• Inicializadores de objetos y colecciones.
• Tipos anónimos.
• Tipos anulables*.
• Métodos extensores.
• Interfaces dinámicas.
• Identificadores dinámicos*.
• Relajación de delegados.
Las características marcadas con *
no están aún implementadas o lo están
solo parcialmente en la versión actual
de la presentación preliminar de LINQ
para VB.
Determinación implícita del tipo de
las variables locales
En Visual Basic 9.0 será posible
obviar la especificación del tipo de una
variable local que se vaya a inicializar
explícitamente. El compilador determinará de forma implícita el tipo de
la variable en base al tipo de la expresión de inicialización. Por ejemplo, en
el fragmento de código que se muestra en el fuente 2 el compilador infie-
Public Enum SexoPersona
Mujer = 0
Varón = 1
End Enum
Public Class Persona
‘ campos
Private _nombre As String = Nothing
‘ en VB 9.0 se podrá utilizar:
‘ Private _sexo As SexoPersona? = Nothing
Private _sexo As Nullable(Of SexoPersona) = Nothing
Private _fechaNac As Nullable(Of DateTime) = Nothing
‘ constructores
Public Sub New()
‘ nada
End Sub
Public Sub New(ByVal nombre As String, ByVal sexo As SexoPersona)
MyClass.New()
_nombre = nombre
_sexo = sexo
End Sub
Public Sub New(ByVal nombre As String, ByVal sexo As SexoPersona, _
ByVal fechaNac As DateTime)
MyClass.New(nombre, sexo)
_fechaNac = fechaNac
End Sub
‘ propiedades
Public Property Nombre() As String
Get
Return _nombre
End Get
Set(ByVal value As String)
_nombre = value.ToUpper()
End Set
End Property
Public Property Sexo() As Nullable(Of SexoPersona)
Get
Return _sexo
End Get
Set(ByVal value As Nullable(Of SexoPersona))
_sexo = value
End Set
End Property
Public Property FechaNac() As Nullable(Of DateTime)
Get
Return _fechaNac
End Get
Set(ByVal value As Nullable(Of DateTime))
_fechaNac = value
End Set
End Property
Public ReadOnly Property Edad() As Nullable(Of Integer)
Get
If _fechaNac.HasValue Then
Return Convert.ToInt32(DateTime.Today. _
Subtract(FechaNac.Value).TotalDays / 365.25)
Else
Return Nothing
End If
End Get
End Property
‘ métodos
Public Overrides Function ToString() As String
Dim s As String = “”
If _nombre Is Nothing Then s &= “ANONIMO” Else s &= _nombre
If _sexo.HasValue Then
If _sexo.Value = SexoPersona.Mujer Then
s &= “ (M)”
Else
s &= “ (V)”
End If
End If
If _fechaNac.HasValue Then s &= “ (“ & Edad.ToString() & “)”
Return s
End Function
End Class
Fuente 1. Clase Persona utilizada en los ejemplos
<<dotNetManía
<< dnm.futuro
23
<< dnm.futuro
re que la variable N es de tipo Integer por el tipo de
la constante que se le intenta asignar. Este mecanismo puede utilizarse también en otras construcciones del lenguaje, como los bucles For..Next y
For Each..Next.
Sub Ejemplo1()
‘ Declaración implícita del tipo de la variable
Dim N = 2 ‘ equivale a Dim N As Integer = 2
piedades o campos del objeto se especifican mediante un inicializador de objeto.
Para que este mecanismo funcione es requisito
indispensable que la clase ofrezca un constructor sin
argumentos, como ocurre en el caso de las clases que
no tienen un constructor definido explícitamente y
de aquellas que son sintetizadas artificialmente por el
compilador (“tipos anónimos”, que presentaremos a
continuación).
b) Inicializadores de colecciones
‘ Declaración implícita del tipo de la variable
‘ y los elementos del array
Dim Arr = {1, 2, 3, 4, 5, 6, 7, 8, 9}
‘ También en bucles for y foreach
For Dim k = 1 To 10
Console.WriteLine(k)
Next
For Each Dim i In Arr
Console.WriteLine(i)
Next
‘ Enlace tardío con Strict On
Dim M As Object
M = 27
M = “abc”
End Sub
Fuente 2. Determinación implícita del tipo de las variables
Independientemente del estado de la opción
Option Strict, el acceso a las variables cuyo tipo es
inferido por el compilador siempre se realiza
mediante enlace temprano. De hecho, cuando esta
opción esté en On (lo que vienen recomendando desde hace mucho nuestros columnistas - vea por ejemplo [3]), para utilizar el enlace tardío sobre una
variable en VB 9.0 se deberá declararla explícitamente como As Object . Este cambio hacia una
mayor utilización en situaciones “normales” del
fuerte control de tipos hace posibles nuevas aplicaciones del enlace tardío que presentaremos más
adelante en este artículo.
Inicializadores de objetos y colecciones
VB 9.0 añadirá nuevas construcciones sintácticas
para permitir la especificación directa de constantes
de clases y colecciones, que aportarán una mayor
comodidad y economía de expresión al lenguaje.
<<dotNetManía
a) Inicializadores de objetos
24
En el fuente 3 se muestra cómo se podrá asignar
una “constante” construida ad hoc a una variable de
una clase cualquiera. En lugar de la llamada al constructor con argumentos, o de la llamada al constructor básico seguida de un bloque With..End With, en
esta variante más “declarativa” los valores de las pro-
La extensión de la sintaxis para la inicialización de
objetos se ampliará también a las colecciones genéricas. El tipo al que se aplica el inicializador de colección debe implementar la interfaz genérica
System.Collections.Generic.ICollection(Of T), y la
inicialización se traduce en la construcción de la colección, seguida de una secuencia de llamadas al método ICollection(Of T).Add(T) para añadir cada elemento de la lista. El propio fuente 3 muestra más adelante cómo puede hacerse la inicialización de una variable Hijos de tipo List(Of Persona).
‘ a nivel de módulo para utilizarla en varios métodos
Dim Hijos As List(Of Persona) = Nothing
Sub Ejemplo2()
‘ Inicializador de objeto
Dim ag = New Persona { _
Nombre := “Amanda”, _
Sexo := SexoPersona.Mujer, _
FechaNac := New DateTime(1998, 10, 23) _
}
‘ ** Equivale a:
‘ Dim ag = New Persona()
‘ With ag
‘
.Nombre = “Amanda”
‘
.Sexo = SexoPersona.Mujer
‘
.FechaNac = New DateTime(1998, 10, 23)
‘ End With
‘ Inicializador de colección
Hijos = New List(Of Persona) { _
{ _
Nombre := “Diana”, _
Sexo := SexoPersona.Mujer, _
FechaNac := New DateTime(1996, 2, 4) _
}, _
{ _
Nombre := “Dennis”, _
Sexo := SexoPersona.Varón, _
FechaNac := New DateTime(1983, 12, 27) _
} _
}
‘ ** Equivale a:
‘ Dim hijos = New List(Of Persona)
‘ hijos.Add(New Persona(“Diana”, SexoPersona.Mujer,_
New DateTime(1996, 2, 4)))
‘ hijos.Add(New Persona(“Dennis”, SexoPersona.Varón,_
New DateTime(1983, 12, 27)))
End Sub
Fuente 3. Inicializadores de objetos y colecciones
<< dnm.futuro
La expresión “tipos anónimos” se refiere a la posibilidad de que el compilador de VB 9.0 sintetice de
forma automática nuevos tipos de datos a partir de las
propiedades que se le indiquen en expresiones de inicialización. Por ejemplo, a partir del fragmento de
código que se muestra en el fuente 4, el compilador
generará un tipo dotado de las propiedades que se indican en su expresión de inicialización, Nombre y
Ejemplares. El nombre que asigne internamente el
compilador al tipo es irrelevante; lo realmente importante del ejemplo es que las variables rev1 y rev2 serán
de un mismo tipo anónimo y no de dos tipos diferentes. El compilador “combina” las definiciones de tipos
anónimos siempre que en las expresiones de inicialización se incluyan las mismas propiedades, los tipos
de éstas coincidan y estén declaradas en el mismo
orden.
Sub Ejemplo3()
‘ Tipos anónimos
Dim rev1=New {Nombre:=“DotNetManía”, Ejemplares:=12}
Dim rev2=New {Nombre:=“MSDN Magazine”, Ejemplares:=12}
‘ ** Equivale a:
‘ Dim rev1 As _Anonimo1_ = New _Anonimo1_()
‘ ‘_Anonimo1_ es una clase que implementa propiedades
‘ ‘Nombre y Ejemplares (ver código fuente)
‘ With rev1
‘ .Nombre = “DotNetManía”
‘ .Ejemplares = 12
‘ End With
‘ Dim rev2 As _Anonimo1_ = New _Anonimo1_()
‘ With rev2
‘ .Nombre = “MSDN Magazine”
‘ .Ejemplares = 12
‘ End With
End Sub
Fuente 4. Generación de tipos anónimos
Tipos anulables
.NET Framework 2.0 implementó el tratamiento de los tipos genéricos a nivel de motor de ejecución, y a partir de esa posibilidad C# 2.0 y Visual Basic
2005 incorporaron al lenguaje la capacidad para definir y manipular tipos genéricos. Adicionalmente, entre
las clases base de .NET 2.0 se incluye el tipo genérico Nullable(Of T), que nos permite dotar a los tipos
valor de la semántica de valor nulo que caracteriza a
los tipos referencia. Por ejemplo, declarando el campo privado _sexo de la clase Persona del fuente 1 de
tipo Nullable(Of SexoPersona) podremos inicializarlo con el valor Nothing. Tal asignación se traduce en
la asignación del valor False a la propiedad HasValue
del tipo.
Aparte de permitir aprovechar las características
intrínsecas del tipo, la versión actual de Visual Basic
no ofrece ninguna facilidad lingüística directa para
trabajar con los tipos anulables. Corrigiendo esa limitación, y equiparándose en este sentido a C#, VB 9.0
integrará en el lenguaje el tratamiento de los tipos
anulables. En primer lugar, ofreciendo una sintaxis
más cómoda para la definición de estos tipos: en lugar
de Nullable(Of Integer) ahora podremos usar la notación Integer?, mucho más concisa. Pero lo más importante es que se integrará en el lenguaje la operación
sobre estos tipos en función de sus tipos subyacentes,
utilizando una semántica de valor nulo similar a la de
SQL. Por ejemplo, la primera suma que se muestra
en el fuente 5 producirá Nothing, dado que uno de sus
operandos tiene ese valor. Por el contrario, la segunda suma producirá 7, dado que ambos operandos tienen asignado un valor.
Para lograr un efecto similar a éste en VB 2005
sería necesario encapsular el tipo Nullable(Of Integer)
dentro de una estructura y definir para ésta los operadores correspondientes, como se ha hecho en [4].
Sub Ejemplo4()
Dim m As Integer? = Nothing
Dim n As Integer? = 4
Dim p As Integer? = 3
Dim x As Integer? = m + n ‘ x = Nothing
Dim y As Integer? = n + p ‘ y = 7
End Sub
Fuente 5. Declaración y uso de tipos anulables
Métodos extensores
Los métodos extensores (extension methods) son un
recurso de conveniencia que permite extender o
ampliar la funcionalidad de una clase sin necesidad de
modificar su código fuente ni recurrir a la herencia.
Los operadores de consulta de LINQ que veremos
más adelante se implementan utilizando métodos
extensores.
Suponga que tenemos a nuestra disposición la
clase Persona del fuente 1, pero únicamente en su
forma compilada, como parte de una librería de clases. Suponga además que quisiéramos extender artificialmente la clase con métodos adicionales – por
ejemplo, añadirle métodos lógicos que nos permitan conocer si la persona cumple años durante el
mes actual o es mayor de edad. Usando los nuevos
recursos que brindará VB 9.0, la solución consistiría en crear un módulo (que se muestra en el fuente 6), dotándolo de los métodos extensores correspondientes.
Para poder utilizar los métodos de este tipo
como métodos extensores, tanto el módulo como
los propios métodos deberán marcarse con el atributo System.Runtime.CompilerServices.Extension.
<<dotNetManía
Tipos anónimos
25
<< dnm.futuro
<System.Runtime.CompilerServices.Extension()> _
Module Persona_Extension
‘ métodos extensores
<System.Runtime.CompilerServices.Extension()> _
Public Function CumpleAñosEsteMes(ByVal [Me] As Persona) As Boolean
Return [Me].FechaNac.HasValue AndAlso _
[Me].FechaNac.Value.Month = DateTime.Today.Month AndAlso _
[Me].FechaNac.Value.Day >= DateTime.Today.Day
End Function
<System.Runtime.CompilerServices.Extension()> _
Public Function MayorDeEdad(ByVal [Me] As Persona) As Boolean
Return [Me].Edad.HasValue AndAlso [Me].Edad.Value >= 18
End Function
‘ método extensor con parámetro-función
<System.Runtime.CompilerServices.Extension()> _
Public Function CumpleCondicion(ByVal [Me] As Persona,
ByVal F As Func(Of Persona, Boolean)) As Boolean
Return F([Me])
End Function
End Module
Fuente 6. Módulo que implementa los métodos de extensión
Los métodos extensores deben tener un primer
parámetro del tipo que se pretende extender, y dado
que estos métodos se van a utilizar como métodos
de instancia, surge naturalmente la idea de llamar
al parámetro [Me] (los corchetes son necesarios,
dado que Me es palabra reservada), como muestra el
ejemplo.
Una vez que tenemos nuestros métodos programados, solo tenemos que “ponerlos en ámbito” en el
código donde queremos utilizarlos, mediante la directiva Imports. A partir de ese momento, podremos aplicar los métodos extensores a objetos de la clase “extendida” como si de un método de instancia corriente de
ésta se tratase. En el fuente 7 se muestra un fragmento
de código en el que se aplican los métodos extensores definidos anteriormente a un objeto de la clase
Persona.
Tenga en cuenta que muchos de los métodos extensores que se utilizan en LINQ requieren en calidad
<<dotNetManía
Sub Ejemplo5()
Dim ag = New Persona { _
Nombre := “Amanda”, _
Sexo := SexoPersona.Mujer, _
FechaNac := New DateTime(1998, 10, 23) _
}
26
If ag.MayorDeEdad() Then
Console.WriteLine(“Amanda es mayor de edad!”)
Else
Console.WriteLine(“Amanda es menor de edad.”)
End If
‘ llamada a través de delegado
If ag.CumpleCondicion(AddressOf MayorDeEdad) Then
Console.WriteLine(“Amanda es mayor de edad!”)
Else
Console.WriteLine(“Amanda es menor de edad.”)
End If
End Sub
Fuente 7. Utilización de métodos extensores
de parámetros a delegados que “apunten” a la funcionalidad a ejecutar cuando llegue el momento adecuado. Por ejemplo, el fuente 6 ofrece un método
extensor CumpleCondicion que recibe como parámetros la referencia a un objeto de la clase Persona para
el que se desea comprobar si cumple una condición
lógica determinada, y la condición en sí, expresada en
forma de delegado genérico del tipo Func(Of Persona,
Boolean). El fuente 7, por otra parte, muestra un ejemplo de su utilización.
Interfaces dinámicas
En aras de la completitud, mencionaremos brevemente tres nuevas características propuestas para
VB 9.0 que no tienen relación directa con LINQ y
que están orientadas a hacer el lenguaje más dinámico, en línea con las posibilidades que ofrecen otros
lenguajes modernos como Python o Ruby.
En primer lugar están las interfaces dinámicas,
que permiten cobijar temporalmente bajo un mismo “paraguas” a objetos no relacionados entre sí
pero que comparten (por azar o diseño consciente)
una serie de características. Por ejemplo, el código
que se presenta en el fuente 8 define la interfaz dinámica ITieneNombre, en la que tiene cabida cualquier
objeto que disponga de una propiedad alfanumérica
llamada Nombre. A continuación, se define una función
que devuelve una persona o una revista (en este último caso utilizando un tipo anónimo).
Un objeto declarado como de tipo correspondiente
a una interfaz dinámica es accedido siempre mediante enlace tardío (dinámico), pero la suscripción a la
interfaz dinámica nos permite disponer de las ventajas del tipado estático al acceder a los miembros, y en
particular disponer de la ayuda Intellisense.
Dynamic Interface ITieneNombre
Property Nombre() As String
End Interface
Public Function ObtenerObjetoConNombre(_
ByVal N As Integer) As ITieneNombre
Select Case N
Case 1
Return New Persona(“Paco Marin”,
SexoPersona.Varón)
Case 2
Return New {Nombre:=“DotNetManía”, Ejemplares:=12}
Case Else
Return Nothing
End Select
End Function
Public Sub Ejemplo6()
‘ ** interfaces dinámicas
Dim objetoConNombre As ITieneNombre
objetoConNombre = ObtenerObjetoConNombre(_
New Random().Next(3))
ObjectDumper.Write(objetoConNombre)
End Sub
Fuente 8. Utilización de interfaces dinámicas
<< dnm.futuro
Un caso extremo de dinamismo es aquel en el
que en tiempo de compilación no conocemos el
nombre del método al que debemos llamar, los
argumentos de la llamada o incluso la clase a la que
el método pertenece. Los identificadores dinámicos permiten cubrir tales situaciones, y lograr una
economía de expresión muy alta con respecto a si
fuera necesario hacer las mismas tareas utilizando
reflexión.
El fuente 9 presenta ejemplos de llamadas dinámicas a los métodos de una clase Prueba. Como puede verse, en el código se llama a funciones cuyos nombres se almacenan en variables o expresiones de tipo
String.
Public Class Prueba
Public Sub Saludo()
Console.WriteLine(“Hola!”)
End Sub
Public Function Sumar(_
ByVal ParamArray nums As Integer()) As Integer
Dim suma = 0
For Each i As Integer In nums
suma += i
Next
Return suma
End Function
End Class
Public Sub Ejemplo7()
‘ ** identificadores dinámicos
Dim p As Object = New Prueba()
‘ As Object es imprescindible!
Dim método As String = “Saludo”
‘ el nombre del método a llamar
p.(método)() ‘ equivale a p.Saludo()
Dim args = {1, 2, 4, 8}
Console.WriteLine(“La suma es: “ & p.(“Sumar”)(args))
End Sub
Fuente 9. Utilización de interfaces dinámicas
Relajación de delegados
Por último, otro cambio que se incorporará al lenguaje en la próxima versión hará consistentes las reglas
de asociación de delegados a las reglas de llamadas a
métodos, basadas en la contravarianza de los argumentos. Por ejemplo, en la aplicación Windows
Forms cuyo código se muestra en el fuente 10 (proyecto LINQ_VB2), la firma del gestor asociado al evento Click ha sido modificada de forma tal que el segundo argumento es de un tipo (Object) más general que
el que originalmente requiere ese evento (EventArgs).
Esta novedad permitirá crear métodos delegados más
generales y por lo tanto aplicables a un mayor número de situaciones.
Public Class Form1
‘ firma del gestor de eventos modificada!
Private Sub Mensaje(ByVal sender As System.Object,
ByVal e As Object) Handles Button1.Click
MessageBox.Show(“Hola desde VB 9.0”, “Saludo”)
End Sub
End Class
Fuente 10. Ejemplo de relajación de delegados
LINQ en VB 9.0
Como hemos dicho al principio de este artículo en
nuestra definición de LINQ, la clave de esta tecnología
reside en que abre al programador la posibilidad de expresar las consultas sobre datos provenientes de las más disímiles fuentes (colecciones en memoria, bases de datos
relacionales, documentos XML) utilizando recursos de
su propio lenguaje de programación.
No repetiremos aquí todo lo relacionado con los
fundamentos, la arquitectura y el funcionamiento de
LINQ, sino que referiremos al lector a [2]. El programador de VB que haya seguido este artículo hasta
aquí ya dispondrá del bagaje conceptual necesario
(tipos anónimos, métodos extensores) para comprender todo lo que en aquella referencia se trata. LINQ
es una tecnología 100% multi-lenguaje, diferencias
sintácticas aparte. Basaremos nuestra exposición en
ejemplos que ayuden a comprender la sintaxis de las
expresiones de consulta en VB 9.0.
Expresiones de consulta
Las expresiones de consulta (la documentación
de VB se refiere a ellas como query comprehensions,
mientras que la de C# las denomina query expressions) son el principal mecanismo mediante el que
cobra vida la tecnología LINQ. No son otra cosa
que expresiones responden a una nueva sintaxis añadida al lenguaje y que pueden actuar sobre cualquier objeto que satisfaga la interfaz genérica
System.Collections.Generic.IEnumerable<T>, transformándolo mediante un conjunto de operadores en otra
colección que implementa la misma interfaz.
En el fuente 11 se muestran algunos ejemplos
de expresiones de consulta basadas en la colección
de objetos Hijos que hemos creado e inicializado
en el fuente 3. Cualquiera que esté familiarizado
con SQL reconocerá en las expresiones de consulta las operaciones del álgebra relacional como selección, proyección, ordenación o agrupación. Algunas
operaciones, como los agregados (Count, Sum, etc.),
aún no están presentes en la sintaxis VB implementada en la versión actual de la presentación preliminar, pero en cualquier caso, como muestra el
segundo ejemplo, están disponibles si se utiliza la
sintaxis explícita de llamadas que hemos descrito
detalladamente en [2].
<<dotNetManía
Identificadores dinámicos
27
<< dnm.futuro
Public Sub Linq1()
‘ lista de chicas, ordenada alfabéticamente
Dim chicas = From h In Hijos _
Where h.Sexo.HasValue AndAlso _
h.Sexo.Value = SexoPersona.Mujer _
Select New {Nombre := h.Nombre, Edad := h.Edad}
Order By Nombre
ObjectDumper.Write(chicas)
End Sub
Public Sub Linq2()
‘ cantidad de hijos mayores de edad
Dim promedio = (From h In Hijos _
Where h.MayorDeEdad() _
Select h).Count()
‘ ** en un futuro próximo:
‘ Select Count() From h In Hijos ...
ObjectDumper.Write(promedio)
End Sub
Public Sub Linq3()
‘ agrupación por sexos
Dim grupos = From h In Hijos _
Group By h.Sexo.Value _
Select It
‘ It - significa aquí “el grupo”
‘ cuántos de cada sexo
For Each Dim g In grupos
Console.WriteLine(g.Key & “ - “ & g.Count)
Next
End Sub
Fuente 11. Ejemplos de expresiones de consulta
Resultados de consultas como conjuntos de datos
<<dotNetManía
Otra de las novedades importantes relacionadas
con LINQ e incorporadas en esta presentación preliminar es la posibilidad de tratar los resultados de
consultas como conjuntos de datos. Específicamente, esta versión incorpora un nuevo operador, ToDataTable, que permite convertir el resultado de una consulta en un objeto DataTable para, por
ejemplo, pasarlo a otra capa de la aplicación o
conectar a él controles visuales. La figura 2 muestra una rejilla en la que se visualiza el resultado de
una consulta sobre una colección de libros famosos. El código que produce la imagen se muestra
en el fuente 12.
28
Figura 2. Enlace a datos de resultado de consulta
Private Sub Button2_Click(ByVal sender As
System.Object,
ByVal e As System.EventArgs) Handles Button2.Click
Dim consulta = From l In libros _
Select l _
Order By Año
Dim tabla As DataTable = consulta.ToDataTable()
DataGridView1.DataSource = tabla
End Sub
Fuente 12. Enlace a datos sobre el resultado de una consulta
Soporte directo para XLinq en el
lenguaje
VB 9.0 ofrece varias nuevas características destinadas específicamente a dar soporte intrínseco a XML y
XLinq, la tecnología derivada de LINQ para la ejecución de consultas integradas sobre documentos XML.
El tema merece un artículo independiente, y aquí solo
presentaremos las principales novedades, que son:
• Literales XML.
• Importación y uso de espacios de nombres XML.
• Enlace tardío sobre XML.
‘ ** importación de espacio de nombres XML
Imports ns = “http://www.w3.org/1999”
Public Sub Xml1()
‘ ** literales XML
Dim ag =
<Persona
Nombre=”Amanda”
<%= SexoPersona.Mujer %>
Sexo=<%=
<%= #10/23/1998# %>>
%>
FechaNac=<%=
</Persona>
Console.WriteLine(ag.GetType().ToString())
ObjectDumper.Write(ag)
‘ ** ahora con elementos y espacio de nombres
Dim ag2 =
<Persona xmlns=”http://www.w3.org/1999”>
<Nombre>Amanda</Nombre>
<%= SexoPersona.Mujer %></Sexo>
<Sexo><%=
%>
<%= #10/23/1998# %>
<FechaNac><%=
%></FechaNac>
</Persona>
‘ ** uso de espacio de nombres XML
Console.WriteLine(
“Amanda nació el “ + ag2. <ns:FechaNac>.Value)
Dim sobrinos =
<Sobrinos>
<Persona
Nombre=”Adrián”
<%= SexoPersona.Varón %>
Sexo=<%=
<%= New DateTime(2005, 8, 2) %>
FechaNac=<%=
%>>
</Persona>
<%= ag %>
</Sobrinos>
Console.WriteLine(sobrinos.GetType().ToString())
ObjectDumper.Write(sobrinos)
Fuente 13. Ejemplos de literales XML
<< dnm.futuro
Literales XML
Public Sub Xml2()
‘ ** literal XML a partir de consulta LINQ
Dim hijosXML =
<Hijos>
<%= Select <Persona Nombre=<%= h.Nombre %>
%>
<%= h.Sexo.Value %>
Sexo=<%=
<%= h.FechaNac.Value %>
FechaNac=<%=
%>>
</Persona> _
From h In Hijos %>
</Hijos>
Console.WriteLine(hijosXML.GetType().ToString())
ObjectDumper.Write(hijosXML)
‘ ** enlace tardío sobre XML
For Each Dim x In hijosXML...Persona
Console.WriteLine([email protected])
Next
End Sub
Fuente 14. Literal XML obtenido de una consulta LINQ
Los objetos resultantes de la compilación de los
fragmentos XML son de tipo XmlElement, definido en
el ensamblado System.Xml.XLinq, lo que garantiza la
total interoperabilidad con otros lenguajes que utilicen XLinq.
Importación y uso de espacios de nombres XML
Para dar consistencia a la inserción de XML en
nuestro código fuente, VB 9.0 permitirá importar al
mismo espacios de nombres XML usando la sentencia Imports, como se muestra en el fuente 13. A todo
espacio de nombres XML importado siempre deberá
asignársele un alias. Más adelante en el ejemplo se
muestra la sintaxis que permite hacer uso de estos alias
para cualificar elementos o atributos.
Visual Basic 9.0 permite insertar
directamente en el código fuente
fragmentos de documentos XML
nica, las variables de nuestro código se pueden enlazar
en tiempo de ejecución a atributos y elementos XML a
través de construcciones sintácticas especiales. El fuente 14 muestra un bucle en el que se utilizan dos de estas
construcciones: la notación hijosXML...Persona representa al “eje descendiente”: la colección de todos los
nodos Persona que descienden de hijosXML, no importa
a qué nivel de profundidad; por otra parte, la notación
[email protected] tiene que ver con el “eje de atributos” y produce una referencia al objeto XAttribute asociado al atributo Nombre del elemento x.
Conclusión
En este artículo hemos presentado las nuevas características que incluirá la versión 9.0 de Visual Basic,
que estará disponible oficialmente junto con Orcas,
la próxima versión de Visual Studio. En particular,
hemos hecho mayor énfasis en las nuevas características de VB 9.0 que sirven de soporte para LINQ y
XLinq. A esta última tecnología dedicaremos íntegramente una de nuestras próximas entregas.
Agradecimientos
El autor quiere agradecer la ayuda de Guillermo
“Guille” Som, que ha contribuido a mejorar este artículo con múltiples sugerencias y puntualizaciones de
gran utilidad.
Bibliografía
[1]
Recursos relacionados con VB 9.0 y LINQ:
http://msdn.microsoft.com/vbasic/future/default.aspx.
[2]
Hernández, Octavio “Lo que nos traerá Orcas: la tecnología LINQ”, publicado en dotNetManía Nº 25,
abril de 2006.
Enlace tardío sobre XML
[3]
Som, Guillermo “Generics y Visual Basic .NET”,
publicado en dotNetManía nº 8, octubre de 2004.
Además de permitir la codificación directa de XML,
VB 9.0 también simplifica el acceso a las estructuras XML
mediante el enlace tardío sobre XML. Mediante esta téc-
[4]
Som, Guillermo “Definición de estructura para
operar sobre tipos anulables”, publicado en
http://www.elguille.info.
<<dotNetManía
VB 9.0 permite insertar directamente en el código fuente fragmentos de documentos XML. Los valores que se asocian a los atributos y elementos no tienen que ser especificados necesariamente mediante
constantes, porque el lenguaje incorpora una sintaxis
que recuerda a la de ASP para “rellenar” las estructuras XML con el resultado de expresiones del lenguaje de programación. El fuente 13 muestra algunos
ejemplos claros.
Una aplicación muy potente de esta nueva característica de VB 9.0 es la que permitirá obtener un literal XML a partir del resultado de una consulta LINQ,
como se muestra en el fuente 14.
29
dnm.servidores.sql
David Perona
Servicios Web nativos con
SQL Server 2005
Con el uso de HTTP EndPoints podemos exponer a la Web tanto los procedimientos almacenados como las UDF de nuestra base de datos sin tener que usar ninguna otra herramienta ni abrir puertos TCP para SQL Server 2005.
<< En este artículo veremos cómo mediante el uso de los HTTP
David Perona Martínez
trabaja como desarrollador para
Clave Informática, S.L. Es Técnico
Superior en Administración de
Sistemas Informáticos y
MCAD.NET.
EndPoints podemos exponer a la Web tanto los procedimientos almacenados como las UDF de nuestra base de
datos prácticamente sin esfuerzo. Estos objetos nos permitirán crear interfaces de acceso vía HTTP o TCP para
SOAP, T-SQL, Service Broker e incluso para DBMirroring. Nos centraremos en el objetivo de este artículo y hablaremos exclusivamente de la creación de
HTTP/SOAP EndPoints en SQL Server.
En cierta forma, esta habilidad ya estaba disponible
con SQL Server 2000. SQLXML 3.0 nos proveía de un
conjunto de herramientas que nos permitían enviar y
recibir datos en formato XML y además permitía crear
servicios Web con posibilidad de ejecución de procedimientos y UDF, al igual que los EndPoints.
Una de las mejoras más notables que se han añadido con la aparición de los EndPoints es la supresión
de IIS para gestionar las peticiones HTTP de los servicios Web. Pero alguien debe hacerse cargo de estas
redirecciones, por lo que para poder crear estos servicios necesitaremos que la máquina en la que va a
residir SQL Server funcione bajo Windows 2003 o
Windows XP con SP2. Ya que será http.sys el encargado de realizar todo este trabajo.
El funcionamiento de http.sys (HTTP Listener
Process) es el siguiente. Imaginemos que hemos creado un EndPoint en la dirección http://miServer/dotnetmania. Al crearlo, queda automáticamente registrado en http.sys. Cuando llega una petición SOAP,
la recoge en primera instancia el servidor especificado en la llamada, en nuestro caso miServer. El siguiente paso es comparar el resto de la cadena con la lista
de EndPoints que el servidor tiene registrados y, en
caso de coincidencia, éste envía la petición directamente al EndPoint correspondiente, omitiendo así el
paso por IIS. En la figura 1 vemos claramente diferenciadas las distintas metodologías.
Figura 1
Veamos un ejemplo
Ahora que ya hemos visto quiénes somos y hacia
dónde vamos, es el momento de entrar en materia.
Para crear un servicio Web en SQL Server 2005
son necesarios tres pasos:
1. Crear el origen de datos. Un procedimiento almacenado, una UDF o incluso, como veremos más
adelante, un proceso batch.
2. Crear un EndPoint especificando algún WebMethod
que nos proporcione el acceso a esos datos.
3. Crear una aplicación cliente que solicite esos datos.
En este ejemplo crearemos un servicio Web que
nos ofrecerá una lista de todos los artículos de los
<< dnm.servidores.sql
que disponemos y que al seleccionarlo, cualquiera
de ellos nos enseñará su foto. Para ello, usaremos
la base de datos AdventureWorks que adjunta SQL
Server 2005.
El primer paso será crear los objetos que nos ofrecerán los datos. En nuestro caso crearemos un procedimiento almacenado, que podemos ver en el fuente
1, y que nos devolverá un listado básico (código y nombre) de la tabla de Productos.
CREATE PROCEDURE dbo.GetArticulos
AS
SELECT P.ProductID, P.Name
FROM Production.Product P
ORDER BY P.ProductID
Fuente 1
En el fuente 2 tenemos el segundo procedimiento almacenado que nos hará falta. Este nos devuelve
la imagen y el nombre del artículo que le pasemos
como parámetro, de la tabla ProductPhoto.
Sencillo, ¿verdad? Ya tenemos nuestro EndPoint
creado y listo para su uso. Podremos comprobar su
correcto funcionamiento si por ejemplo desde cualquier navegador le pedimos que nos devuelva el documento WSDL (Web Service Description Language)
correspondiente al servicio. Con http://miServer/dotnetmania?WSDL nos mostrará una página con toda la
información del EndPoint.
Ahora que tenemos todos los requisitos a punto,
crearemos una aplicación muy simple que nos mostrará el listado de artículos y que, al movernos por
ellos, nos mostrará las fotos de cada uno. Para ello,
abrimos Visual Studio y creamos un nuevo proyecto
Windows, al que llamaremos EndPoints. Al formulario lo llamaremos frmEndPoint, y añadiremos los
siguientes controles:
• Un DataGridView, que llamaremos oGrid.
• Un PictureBox, que llamaremos PicImagen.
• Un Label, que llamaremos LblImagen.
• Un Button, que llamaremos Button1.
Con lo que conseguiremos que tenga una apariencia parecida la que vemos en la figura 2.
CREATE PROCEDURE dbo.GetImagenArt
@ProductID int
AS
SELECT PF.LargePhoto, PF.LargePhotoFileName
FROM Production.Product P
LEFT JOIN Production.ProductProductPhoto PPF
ON P.ProductID = PPF.ProductID
LEFT JOIN Production.ProductPhoto PF
ON PPF.ProductPhotoID = PF.ProductPhotoID
WHERE P.ProductID = @ProductID
Fuente 2
CREATE ENDPOINT sql_DotNetMania
STATE = STARTED
AS HTTP (
PATH = ‘/DotNetMania’,
AUTHENTICATION = (INTEGRATED),
PORTS = (CLEAR),
SITE = ‘miServer’)
FOR SOAP (
WEBMETHOD ‘GetProducts’
(Name=’AdventureWorks.dbo.GetArticulos’),
WEBMETHOD ‘GetImageProd’
(Name=’AdventureWorks.dbo.GetImagenArt’),
BATCHES = DISABLED,
WSDL = DEFAULT,
DATABASE = ‘AdventureWorks’,
NAMESPACE = ‘http://Adventure-Works/’)
Fuente 3
Figura 2
Lo primero que debemos hacer es añadir una referencia Web a nuestro proyecto. Cuando se nos pregunte dónde se encuentra nuestro servicio, simplemente escribiremos la dirección del WSDL (que en
nuestro caso será http://miserver/dotnetmania?WSDL).
Una vez que lo tengamos localizado, le daremos el
nombre Local_EndPoint.
En el fuente 4 podemos ver el código del ejemplo.
Como con cualquier servicio Web, tendremos que
importar el espacio de nombres de la clase de este servicio en el encabezado del módulo en el que lo vayamos a usar. Importaremos también los espacios
System.Data y System.Data.SqlClient, que nos harán
falta para el desarrollo del ejemplo.
En la cabecera de la clase inicializamos el objeto
que contendrá el servicio y un array de objetos, pues-
<<dotNetManía
Con los procedimientos almacenados ya creados,
el único paso que nos queda es crear nuestro EndPoint.
Para ello, usaremos el código del fuente 3.
31
<< dnm.servidores.sql
Imports System.Data
Imports System.Data.SqlClient
Imports EndPoints.local_EndPoint
Public Class frmEndPoint
Dim myEndPoint As New EndPoints.local_EndPoint.sql_DotNetMania
Dim oReturned() As Object
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim oSet As New DataSet
oGrid.AllowUserToAddRows = False
oGrid.AllowUserToDeleteRows = False
oGrid.EditMode = DataGridViewEditMode.EditProgrammatically
myEndPoint.Credentials = System.Net.CredentialCache.DefaultCredentials
oReturned = myEndPoint.GetProducts
If oReturned(0).ToString = “System.Data.DataSet” Then
oSet = CType(oReturned(0), DataSet)
oGrid.DataSource = oSet
oGrid.DataMember = oSet.Tables(0).ToString
oGrid.Refresh()
End If
End Sub
Private Sub oGrid_RowEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs)
Handles oGrid.RowEnter
Dim oSet As New DataSet
Dim oByte() As Byte
Dim oRow As DataRow
If Not oGrid.Item(e.ColumnIndex, e.RowIndex).Value.ToString.Trim = “” Then
myEndPoint.Credentials = System.Net.CredentialCache.DefaultCredentials
oReturned = myEndPoint.GetImageProd(oGrid.Item(0, e.RowIndex).Value.ToString.Trim)
If oReturned(0).ToString = “System.Data.DataSet” Then
oSet = CType(oReturned(0), DataSet)
oRow = oSet.Tables(0).Rows(0)
‘
oByte = oRow(0)
PicImagen.Image = New Bitmap(New System.IO.MemoryStream(oByte))
lblImagen.Text = oRow(1)
End If
End If
End Sub
End Class
Fuente 4
to que el EndPoint no siempre nos va a devolver objetos de tipo DataSet. Dependiendo del tipo de consulta, podemos obtener distintos elementos, como podemos ver en la tabla 1.
A continuación, pasaremos nuestras credenciales al
servicio Web. Y si son aceptadas, ya podemos acceder
Elemento en SQL Server
Resultado de SELECT
Resultado de SELECT especificando FOR XML
Raise error
<<dotNetManía
Parámetro de salida
32
Filas Afectadas
Valor devuelto por una consulta
a todas los WebMethods que hayamos definido en nuestro EndPoint. Si nos fijamos en el código de Button1,
está comprobando el tipo que ha devuelto la función
GetProducts; en caso de ser un DataSet, lo asigna a un
objeto DataSet local a la función y lo establece como
DataSource del DataGridView. Con esto ya tendremos
cargada toda la información de los artículos en la rejilla.
Objeto .NET
El último paso es comprobar el
System.Data.DataSet
movimiento por las filas de la rejilla para ir cargando las imágenes.
System.Xml.XmlElement
Como puede comprobarse, el códiSqlMessage (del WSDL)
go es muy parecido al de la carga de
SqlParameter (del WSDL)
los artículos.
SqlRowCount (del WSDL)
Todo el código de este ejemplo
puede descargarse de www.dotnetmaSystem.Int32
Tabla 1 nia.com.
<< dnm.servidores.sql
Entrando en detalle
En la propia instrucción de creación del EndPoint
podemos especificar el nombre que le queremos dar,
un login válido para SQL Server o Windows, que será
el propietario de dicho servicio y el estado del servicio una vez que se haya creado.
CREATE ENDPOINT AUTHORIZATION =
usrDavid STATE = STARTED
Los posibles valores para el parámetro STATE, son
Started, Stopped (valor por defecto) y Disabled. Cuando
el servicio está en el estado Stopped, sigue escuchando
y recibiendo peticiones, aunque devuelve un mensaje de error al cliente. Por el contrario, cuando está en
el estado Disabled, está “físicamente” desconectado,
no recibe las peticiones.
Obviando la propia definición del EndPoint, el resto de la sintaxis consta de dos partes claramente diferenciadas:
En la primera parte, especificamos el protocolo de trasporte (TPC o HTTP), el servidor en el
que residirá nuestro servicio, el puerto de escucha,
el método de autentificación del EndPoint y una lista de direcciones IP a la que queramos restringir el
acceso.
• PATH – Especifica la URL de nuestro EndPoint, En
nuestro caso, “/dotnetmania”. Esta es la dirección
que tendremos que escribir para acceder al servicio. Con lo que la sintaxis queda de la siguiente
forma: http://miServer/dotnetmania.
• AUTHENTICATION – Especifica el tipo de autentificación que usaremos para nuestro servicio. Los
posibles valores son: Basic, Digest, Integrated
(usará la configuración de Windows), NTLM o
Kerberos.
• PORTS – Indica el tipo de puerto a usar. Los posibles valores son CLEAR (HTTP) o SSL (que aceptará HTTPS).
• Clear_Port y SSL_Port – Permiten especificar
puertos distintos a los que se asumen por defecto al indicar el parámetro PORTS. Por defecto, la
opción CLEAR usará el puerto 80 y la opción
SSL el 443.
HTTP (
PATH = ‘/DotNetMania’,
AUTHENTICATION = (INTEGRATED),
PORTS = (CLEAR),
SITE = ‘miServer’)
FOR SOAP ( ...
Fuente 5
80/DotNetMania'. De esta forma, la URL estará per-
manentemente ocupada y evitaremos conflictos de
dirección. De la misma forma, para cancelar la
reserva de esta dirección, ejecutaremos lo siguiente: sp_delete_http_namespace_reservation N'
N'http://miServer:80/DotNetMania'. Si, por el
contrario, estuviésemos omitiendo el parámetro SITE, o le estuviésemos pasando como valor
un “*”, la reserva que se crearía sería la siguiente: http://*:80/dotnetmania.
En la segunda parte de la sintaxis de un
EndPoint, informamos sobre el tipo de EndPoint
que estamos creando y a qué peticiones va a estar
escuchando. Podremos especificar tanto SOAP,
como T-SQL, Service Broker o incluso Database
Mirroring. Para cada uno de ellos, tendremos la
posibilidad de especificar un subconjunto de parámetros para definir su configuración. Nos centraremos en SOAP, que es el objetivo de este artículo. Tendremos que definir como mínimo un
<<dotNetManía
Con este sistema, haremos accesible
información de nuestro sistema
vía servicios Web
• SITE – Mediante este parámetro especificamos el
nombre de la máquina en la que reside el servicio
Web. Si omitimos este parámetro, se asumirá el
valor “*”, que indica que la escucha se efectuará
sobre todos los posibles hosts de la máquina que no
estén explícitamente reservados. Otro posible valor
es “+”, que indicará que la operación de escucha
se efectuará sobre todos los posibles hosts de la
máquina, pero sin discriminar los que estén reservados. Otros valores aceptados por esta propiedad
pueden ser LocalHost, el nombre DNS o incluso la
dirección IP de la máquina.
Cuando creamos un EndPoint, implícitamente estamos reservando una URL para nuestro servicio. Por ejemplo, en el caso que nos ocupa, si
observamos el fuente 5, estamos implícitamente
reservando la dirección http://miServer:80/dotnetmania. Esto quiere decir que mientras nuestro
servidor esté en ejecución, http.sys redireccionará cualquier petición que se haga a esta dirección a SQL Server. Sin embargo, podrá ser usada por cualquier otro servicio cuando el servidor
esté detenido. Para evitar esta situación, una buena práctica es reservar la URL explícitamente,
con ayuda del procedimiento almacenado
sp_reserve_http_namespace. La sintaxis es la siguiente: sp_reserve_http_namespace N'http://miServer:
33
<< dnm.servidores.sql
Podremos especificar tanto SOAP,
como T-SQL, Service Broker o
incluso Database Mirroring
•
•
•
WebMethod, que enlazaremos a un procedimeinto
almacenado o una UDF. Indicaremos si dejamos
habilitada la posibilidad de ejecutar Batches sobre el
servidor. Es altamente recomendable dejar esta
opción deshabilitada (el estado por defecto), a menos
que sea de vital importancia tenerla habilitada, lo que
nos obligará a extremar al máximo las medidas de
seguridad de nuestro servicio. No hace falta que os
explique lo que podría pasar si no somos totalmente meticulosos en este aspecto.
Además, podremos definir otras propiedades
como quién será el encargado de generar la información WSDL que ofreceremos. Por defecto, es
el mismo servicio el encargado de generar este
fichero, aunque tenemos la opción de crear un
procedimiento almacenado y que sea éste el que,
a petición del cliente, ofrezca un XSD personalizado. Si usamos la opción Default, el EndPoint puede producir dos versiones distintas del mismo
XSD. Con http://miServer/dotnetmania?wsdl,
devolverá un XSD con tipos derivados, para un
correcto mapeo de los tipos de datos más complejos que se pueden almacenar en SQL Server.
Por otra parte, podremos usar http://miServer/
dotnetmania?wsdlsimple . Este es un formato
Tipo de
Autentificación
<<dotNetManía
•
•
•
Configurando aspectos de seguridad
Tipos de autentificación
Si os fijáis, en la opción AUTHENTICATION del servicio Web no hay posibilidad de especificar la autentificación anónima, detalle éste que nos puede evitar
más de un problema. Echemos un vistazo al resto de
posibles tipos.
Configurando permisos sobre EndPoints
La sintaxis para ofrecer permisos a un EndPoint es
muy parecida a la que se utiliza para el resto de objetos de SQL Server.
Descripción
BASIC
Este método se caracteriza por añadir a la cabecera HTTP, el usuario y la contraseña codificados en Base64.
Requiere la utilización de SSL en la definición del servicio, ya que estamos pasando la información de la conexión
en la misma petición y es relativamente fácil decodificar un código en Base64.
DIGEST
Al igual que el método BASIC, pasa tanto el usuario como la contraseña a través de la red, pero esta vez codificados mediante MD5 (algoritmo de codificación unidireccional). Con este tipo de autentificación sólo podremos
especificar usuarios de un dominio de Windows; no acepta usuarios locales de la máquina. Cuando el servidor
recibe esta información,compara el hash de la contraseña con el que quedó almacenado cuando se creó el usuario. Como nota, diremos que este tipo de autentificación sólo acepta encriptación MD5 bajo controladores de
dominio de Windows Server 2003.
NTLM
Es el mecanismo de autentificación de Windows 95, 98 y NT 4.0. Ofrece un sistema más completo que Basic y
Digest.A partir de Windows 2000, se implementó con SSPI.
Estándar en Internet. Soportado a partir de Windows 2000 por medio de SSPI. Cuando se usa este tipo, SQL
Server asocia su instancia principal con la cuenta que la está ejecutando.
KERBEROS
34
•
reducido del anterior y se diferencia en que esta
versión mapea todos los tipos de SQL Server en
tipos nativos XSD.
WEBMETHOD — Con este parámetro indicamos los
distintos métodos que estarán disponibles para el
servicio. A cada uno de ellos deberemos asociarles un procedimiento almacenado o una función
al que quedará enlazado. Podremos definir varios
WebMethods por EndPoint.
BATCHES — Indica si es posible la utilización de TSQL.
WSDL — Indica dónde está el XSD que será devuelto al cliente cuando nos lo solicite.
DATABASE — Especifica la base de datos en la que
reside nuestro servicio.
NAMESPACE — Especifica el espacio de nombres para
nuestro EndPoint.
FORMAT — Indica qué posibles tipos ofrecerá el servicio como respuesta. {ALL_RESULTS, ROWSETS_ONLY, NONE}.
LOGIN_TYPE — {MIXED, WINDOWS}.
INTEGRATED
Este tipo prepara a nuestro EndPoint para que responda a los tipos de autentificación NTLM y KERBEROS.
Tabla 2
<< dnm.servidores.sql
Tipo_de_acción puede tomar valores como Alter,
Connect, Control, Take Ownership y View Definition. Para
ejecutar este comando, es necesario que estemos en
la base de datos Master. Por ejemplo, el comando:
USE Master
Go
GRANT CONNECT ON ENDPOINT::sql_DotNetMania
TO usr_Clave
Otorga permisos para poder usar el EndPoint con
nombre sql_dotnetmania al usuario usr_Clave. El parámetro WITH GRANT OPTION indica que usr_Clave estará
capacitado para asignar este mismo permiso a otros
logins.
Para denegar cualquier tipo de acción sobre un
servicio:
USE Master
Go
DENY [Tipo_de_acción]
ON ENDPOINT::Nombre_EndPoint
TO SQL_Login CASCADE
El funcionamiento es el mismo. El parámetro CASCADE indica que se debe propagar la denegación del
permiso a todos los logins a los que el denegado se lo
haya garantizado previamente.
Y para eliminar cualquier permiso establecido o
denegado previamente, usaremos:
USE Master
Go
REVOKE [Tipo_de_accion]
ON ENDPOINT::Nombre_EndPoint
[FROM | TO] SQL_Login
Algunos consejos
Como contrapartida a la facilidad de creación de
HTTP EndPoints, tenemos que tener en cuenta que
estamos trabajando con un servicio Web como cualquier otro, pero que está directamente conectado a la
base de datos, por lo que el nivel de seguridad tiene
que ser extremo. Aquí se exponen las prácticas básicas para asegurar nuestros servicios Web.
• Usaremos autentificación Kerberos. En la propiedad AUTHENTICATION, especificaremos siempre
Kerberos, o bien Integrated, que permitirá a Windows
seleccionar la autentificación NTLM o Kerberos.
• Limitaremos tanto como podamos el alcance de
los permisos que otorguemos. Siempre intentaremos asignar permisos exclusivamente a personas
El apartado más importante es la
configuración de los aspectos
de seguridad de estos objetos
o grupos de personas que necesiten tener acceso
a estos servicios. Desde luego, nunca debemos asignar ningún permiso al rol público.
• Usar SSL para información confidencial. De este
modo permitiremos la encriptación de los contenidos confidenciales que circulen por la red. SQL Server
requiere la configuración de un certificado. En este
punto, tendremos especial cuidado, pues si configuramos un certificado para el puerto 443 (puerto por
defecto de SSL), estaremos aplicándolo a todo el tráfico que circule por ese puerto. Por ejemplo, IIS puede estar recibiendo información por el mismo puerto. En este caso, el certificado les afectaría a los dos.
• Configurar estos servicios en servidores que estén
tras un firewall.
• Asegurarse de que la cuenta Invitado está deshabilitada en el sistema operativo.
Otro aspecto importante a tener en cuenta es el rendimiento de estos servicios. Si la solución maneja mucho
código XML o si hace un uso intensivo de procedimientos
almacenados, el rendimiento que pueden ofrecer los
HTTP EndPoints es considerablemente bueno, puesto
que permiten compartir la lógica de negocio fácilmente
con otras aplicaciones. Por otro lado, si nuestra aplicación hace uso de procesos transaccionales críticos, o trabajamos con tipos muy grandes, como Binary Image o
Text, el rendimiento no será optimo. Tened en cuenta la
sobrecarga que se genera al tener que convertir estos
objetos en mensajes SOAP. Además, estamos hablando
de un formato basado en texto, diferente al formato binario nativo de SQL Server, Tabular Data Stream (TDS).
Esto significa que el tamaño de los datos a enviar aumentará entre un 20 y un 30%.
Conclusión
Con HTTP Endpoints, SQL Server 2005 nos ofrece una forma sencilla de crear interfaces para servicios Web, Service Broker e incluso para DB-Mirroring.
Ahora nos será mucho más fácil acceder a nuestro servidor SQL Server desde lugares desde los que antes
nos era muy trabajoso, como pudieran ser aplicaciones en sistemas no Windows, dispositivos móviles y
un largo etcétera.
<<dotNetManía
GRANT [Tipo_de_acción]
ON ENDPOINT::Nombre_EndPoint TO SQL_Login
WITH GRANT OPTION
35
dnm.servidores.sql
Eladio Rincón
Detección de problemas de rendimiento en
SQL Server 2000 y SQL Server 2005 (IV)
En esta cuarta entrega nos vamos a centrar en analizar qué tipo de información
hay almacenada en la memoria de SQL Server, división del uso de la memoria y
cómo detectar bloqueos con las nuevas DMV de SQL Server 2005.
<< ¿Cómo está desglosada la información almacenada en la memoria?
En el segundo artículo de la serie identificamos
la actividad que había en la memoria (contadores
como Memory:Pages/sec y Memory:Available Bytes,
KBytes y MBytes deberían resultar familiares al lector); ahora veremos cuáles son los límites de memoria a los que debe hacer frente SQL Server y además
cómo está repartida dicha memoria. Para ello utilizaremos dos herramientas: el monitor de rendimiento y, por otro lado, comandos DBCC y vistas de sistema de SQL Server.
Monitor de rendimiento
Eladio Rincón
Es Director de Tecnología de
Bases de Datos de Solid
Quality Learning y
colaborador habitual de
dotNetManía. Es MVP en SQL
Server y uno de los fundadores
del grupo de usuarios de SQL
Server en España GUSE.
SQL Server tiene dos contadores de rendimiento
que indican cuánta es la memoria del servidor que se está
utilizando y cuánta es la memoria máxima a la que puede aspirar SQL Server (memoria objetivo). Como norma general, en mediciones largas de tiempo, el valor de
la memoria reservada (SQL Server Memory:Memory
Manager:Total Server Memory), debería tener valores inferiores al 80 por ciento de la memoria objetivo (SQL Server
Memory:Memory Manager:Target Server Memory).
Cuando la memoria objetivo se encuentra por encima
de esos porcentajes, nos está indicando que SQL Server
necesita más memoria de la que puede disponer, que no
necesariamente indicará falta de memoria física. Por
ejemplo, el mes pasado vimos cómo encontrar patrones
de ejecución de consultas; ¿qué pasaría si encontráramos
un patrón de consultas que se resuelve de forma inefi-
SQL Server tiene dos contadores de
rendimiento que indican cuánta es la
memoria del servidor que se está utilizando
y cuánta es la memoria máxima a la que
puede aspirar SQL Server
ciente? Imagínese que analiza el plan de ejecución de la
consulta y se da cuenta que no existe un índice apropiado para la consulta. ¿Cómo resuelve SQL Server esa
consulta? Evidentemente, leyendo muchísima información –probablemente recorriéndose un índice completo, en lugar de realizar búsquedas de índice (por rango,
o búsqueda directa)– lo cual implicaría que SQL Server
tendría que acceder mucho a disco para recuperar la
información necesaria para procesar la consulta y, a su
vez, localizar espacio en memoria para alojar las lecturas realizadas.
Con contadores del monitor de rendimiento también podremos ver cuáles son los tipos de información que ocupan los buffers de memoria de SQL
Server; los contadores para la versión 2000 son los
que puede ver en la tabla 1.
Para SQL Server 2005, los contadores son casi
los mismos, excepto el último que en lugar de ser
<< dnm.servidores.sql
SQLServer:Buffer Manager Procedure cache pages Páginas en caché de procedimiento
Páginas totales reservadas
SQLServer:Memory Manager
Memoria para conexiones de usuario
Connection Memory
SQLServer:Memory Manager Lock Memory
Memoria para bloqueos
SQLServer:Memory Manager Optimizer Memory
Memoria reservada por el optimizador
SQLServer:Cache Manager
Páginas utilizadas totales por el caché
Cache Pages – _Total
que nos encontramos con más frecuencia de la deseada en el que gran parte
de la memoria disponible por SQL
Server es utilizada para guardar planes
de ejecución de las consultas que se procesan en el servidor.
Tabla 1
SQLServer:Cache Manager, se ha cambiado por SQLServer:Plan Cache. Para
calcular la memoria total usada por los
objetos que exponen cantidad de páginas, deberá multiplicar el valor por 8
(una página = 8Kb).
Con estos contadores obtenemos
cómo está desglosado el contenido de la
memoria; como la memoria es un recurso limitado, debemos hacer seguimiento
de cómo distribuye SQL Server la memoria entre cada uno de sus componentes.
Por ejemplo, si vemos que la memoria utilizada para caché de procedimiento es alta,
estaremos forzando a que otros componentes de SQL Server, como la memoria
para página de datos, vean reducida su área
de trabajo. Lo mismo sucede para otros
componentes como la memoria de bloqueos, como veremos más adelante. Sin
embargo, estos contadores de rendimiento no serán válidos si el servidor SQL
Server tiene habilitado el uso de memoria mediante AWE; para estos casos deberá analizarlo con comandos DBCC como
vemos a continuación.
Comandos DBCC
Para sistemas con AWE habilitado,
el comando DBCC MEMORYSTATUS devuelve información más precisa relativa a
la distribución de la memoria; aunque
la información presentada varía mucho
entre la versión 2000 y la versión 2005,
los valores que deseamos comprobar se
encuentran presenten en ambas versiones. El comando devuelve una instantánea del reparto de memoria de SQL
Server. Información sobre el comando
se puede encontrar en los documentos
de KB de Microsoft referenciados al
final del artículo ([1] y [2]). En nuestro caso utilizaremos la información
que muestra la versión 2000. El primer
conjunto de resultados puede aparecer
como se ve en la tabla 2.
Buffer Distribution
Stolen
Free
Procedures
Buffers
4290
388
13510
Inram
0
Dirty
4238
Kept
I/O
Latched
Other
0
0
168
19436
Tabla 2
La columna buffers está expresada
en páginas de 8Kb, y la columna buffer
distribution indica:
• Stolen, buffers reservados para ordenaciones, operaciones hash, bloqueos, transacciones, etc.
• Free, buffers disponibles para usar.
• Procedures, buffers usados para caché
de procedimiento: planes de ejecución, contextos de ejecución de procedimientos, etc.
• Inram, buffers “pinned”. En desuso,
se puede hacer que una tabla permanezca en memoria con el comando DBCC PINTABLE (en desuso).
• Dirty, buffers con datos modificados
que todavía no se han volcado a disco.
• Kept, sin uso en SQL Server 2000,
2005.
• I/O, buffers a la espera de completar
operación de I/O.
• Latches, buffers adquiridos para operaciones de latches (bloqueos para
garantizar la consistencia física del
medio).
• Other, el resto de los buffers; es decir
páginas de datos confirmados, y
páginas de índices principalmente.
En la tabla 2 podemos ver que casi
la mitad de los buffers se utilizan para
caché de procedimiento. Este es un caso
Cómo gestiona SQL Server el caché
de procedimiento
No voy a explicar el funcionamiento completo del caché de procedimiento porque me llevaría más de un artículo, pero pretendo que se quede con
la idea de qué hace SQL Server con el
caché de procedimiento cuando recibe
peticiones de consultas:
• Cuando llega una consulta a SQL
Server (consulta ad hoc, llamada a procedimiento almacenado, consulta
parametrizada, etc.), lo primero que
hace es validar si existe una coincidencia de la consulta en caché; en caso que
no exista, la consulta se compila, se
genera su plan de ejecución, se guarda el plan en caché, y a continuación
se procesa la consulta. En el momento en que el plan se guarda en caché,
queda disponible para que otras conexiones puedan utilizarlo.
• ¿Qué pasaría si llega el mismo
patrón de ejecución de nuevo? En
lugar de recompilarla, el servidor
reutilizará la que ya tiene en caché.
Veamos en qué consiste el patrón
de ejecución de las consultas con algunos ejemplos:
1. Select id, cantidad from
dbo.Orders where id = 1
2. Select id, cantidad from
dbo.Orders where id = 2
3. Select id, cantidad from
dbo.Orders where id = [par0]
4. Exec dbo.ObtenerPedidos @par0 = 1
5. Exec dbo.ObtenerPedidos @par0 = 2
Para SQL Server las consultas 1 y
2 suponen dos planes de ejecución
diferentes; sin embargo, si las consultas 1 y 2 hubieran sido parametrizadas, habrían utilizado el plan de ejecución “genérico” 3. Por otro lado, las
consultas 4 y 5 de igual manera comparten el mismo plan de ejecución
porque los argumentos son parametrizados. Alrededor de este proceso
<<dotNetManía
SQLServer:Buffer Manager Total pages
37
<< dnm.servidores.sql
hay políticas que sigue SQL Server
para invalidar planes de ejecución,
auto-parametrización de consultas,
recompilación, etc., que se pueden
consultar en los documentos de referencia [4]. Fíjese que esta estrategia
es parecida a la que seguimos en el
artículo anterior referente a la búsqueda de patrones de ejecución de
consultas :-).
Veamos ahora cuál es el contenido del
caché de procedimiento; para ello usaremos las vistas de sistema que tenemos en
SQL Server, tanto 2000, como 2005.
La misma consulta en SQL Server
2000, sería la siguiente:
select
c.usecounts, c.cacheobjtype,
c.objtype, c.sql
from master.dbo.syscacheobjects c
Analicemos las columnas que
devuelve la consulta:
• Usecounts: número de veces que se
ha usado el plan desde el momento
en que se insertó en caché.
• Cacheobjtype : tipo de objeto de
caché almacenado; puede ser plan
compilado, plan ejecutable, árbol
relacional, procedimiento almacenado extendido…
• Objtype : el tipo de objeto
referenciado; valores como
consulta ad-hoc, vista, procedimiento almacenado, trigger, sentencia preparada...,
son algunos de los valores que
puede tener.
• Text (“sql” en SQL Server
2000): los primeros 3.900
caracteres de la sentencia
interpretada que se ejecutó.
[ ]
NOTA
Desde la versión 7.0 de SQL Server,
Microsoft dejó de dar soporte al
comando DBCC MEMUSAGE;la idea
del comando era muy interesante
porque reportaba los 20 objetos que
más memoria usaban,sin embargo,si
hace uso del comando estará
corriendo un riesgo que debería analizar si está dispuesto a asumir; en la
lista de recursos puede ver el documento de KB relacionado [3]
Vistas de sistema de SQL Server
<<dotNetManía
Para ver el contenido de la caché de
procedimientos usaremos la vista de sistema syscacheobjects que se encuentra
en la base de datos master. En la versión
2005 también se puede consultar, pero se
recomienda hacerlo a través de las vistas
dinámicas de administración (DMV) sys.
dm_exec_cached_plans, y sys.dm_exec_sql_
text. Son vistas muy descriptivas sobre la
información que contienen; quizás la única novedad en SQL Server 2005 es que
para “cruzar” ambas vistas haremos uso
del nuevo operador CROSS APPLY de la
siguiente forma:
38
select
c.usecounts, c.cacheobjtype,
c.objtype, s.text
from sys.dm_exec_cached_plans c
cross apply sys.dm_exec_sql_text
(c.plan_handle) s
Generalmente buscamos la
frecuencia con que se reutilizan
los planes de ejecución y ése es
un valor que nos da la columna
usecount. Si el valor de usecount
es muy bajo indica que ese plan de ejecución es muy poco reutilizado. ¿Qué
quiere decir esto? Que SQL Server tuvo
que soportar el coste de compilar el plan
de ejecución de la consulta, ponerlo en
caché, y luego se reutilizó muy poco.
Este es un caso típico que se produce en
aplicaciones cliente que envían consultas ad hoc al servidor. La consulta ad
hoc, normalmente, tiene que pasar por
el proceso de compilación excepto en
los casos de autoparametrización. Sin
embargo, usando procedimientos almacenados, al tener su plan de ejecución
en caché, no es necesario recompilarlos
(la excepción es el uso de la opción WITH
RECOMPILE, o invalidación del plan por
estadísticas desactualizadas de los objetos asociados al procedimiento almacenado). En el siguiente artículo de esta
serie, analizaremos los casos en los que
pueda ser recomendable recompilar planes de ejecución y buscaremos solucio-
nes a potenciales problemas del uso de
planes de ejecución en caché no óptimos para todos los tipos de llamadas.
Bloqueos
Otro de los problemas frecuentes
que encontramos en nuestros clientes
son esperas causadas por bloqueos;
como deben recordar del primer artículo de la serie, si tuviera problemas de
bloqueos, habrían sido reportados con
los comandos DBCC y DMV relacionados
con waitstats. Sin embargo, estos problemas suelen ser solucionados con
estrategias adecuadas de indexación.
Hasta ahora hemos estado hablando de
minimizar el número de lecturas que
debe hacer el sistema de discos; normalmente se consiguen buenos resultados
optimizando las consultas más frecuentes; a su vez, esto supondría que el sistema procesaría las consultas en menos
tiempo y, por lo tanto, bloquearía menos
tiempo recursos de SQL Server como
tablas, índices, filas, etc.
Sin embargo, habrá ocasiones en que
existen pequeños bloqueos que necesita detectar y, al ser tan pequeños, no
estarían reportados en las consultas
patrones creadas en el artículo anterior.
Para ello utilizaremos la técnica que
vamos a explicar en la siguiente sección.
Cómo detectar bloqueos
La vista de sistema master.dbo.sysprocesses expone información sobre las
conexiones que están activas en el servidor; las conexiones de usuario comienzan
a partir de spid 51; los valores anteriores a
51 (no quiere decir que utilice todos), SQL
Server se los reserva para procesos dedicados a tareas específicas, por ejemplo proceso de checkpoint, proceso de truncado de
registro de transacciones, proceso de localización de abrazos mortales, etc. En SQL
Server 2005, la DMV que expone la información que necesitamos es sys.dm_exec_
requests.
Concretamente lo que estaremos
buscando será la columna blocked en la
versión 2000 y la columna blocking_
session_id en la versión 2005. Dichas
columnas indican cuál es el proceso que
está bloqueando al actual, por lo que
intentaremos buscar lo siguiente:
<< dnm.servidores.sql
Id_conexión
Id_bloqueador
sql_conexion
sql_bloqueador
53
55 select * from dbo.tabla
where condicion
delete from dbo.tabla
where condicion
54
55 update dbo.tabla
where condicion
delete from dbo.tabla
where condicion
56
55 select * from dbo.tabla
where condicion
delete from dbo.tabla
where condicion
52
55 select * from dbo.vista
where condicion
delete from dbo.tabla
where condicion
poder hacer una operación cross apply
con la DMV sys.dm_exec_sql_text de
la que obtenemos la sentencia SQL
que se está ejecutando en ese momento. El resto de la consulta realiza la
misma operación, pero en este caso
para obtener información sobre el
proceso bloqueador.
Conclusiones
Tabla 3
En este caso concreto, la conexión
55 está bloqueando a los procesos 52,
53, 54 y 56. Fíjese que la conexión 55
está bloqueando la tabla dbo.tabla y
no permite que pueda ser accedida
por el resto de peticiones (incluso una
vista).
Ahora que conocemos cuál es el
resultado que queremos obtener, debemos definir:
• La frecuencia con que se ejecuta el
análisis. El ejemplo será cada 2
minutos.
• El tiempo de duración de los bloqueos. En el ejemplo será 20 segundos.
• Dónde se reportan los bloqueos
localizados.
El proceso será encapsulado en un
procedimiento almacenado, que con
una frecuencia de 2 minutos “buscará” procesos bloqueados en el sistema; además tomará una muestra de los
procesos que se encuentran bloqueados (la columna blocked o blocking_
session_id) y, pasados 20 segundos, se
tomará otra muestra para ver si todavía siguen bloqueados, en cuyo caso
se tomarán las medidas correspondientes de auditoría.
En este artículo hemos visto cómo
analizar la distribución de la memoria
de SQL Server entre los componenEl pseudocódigo del proceso sería el
siguiente:
tes del motor. También hemos aprendido a ver el contenido del caché de
<cada 2 minutos>
procedimiento e identificar la frecuen<capturar_procesos_bloqueados en v1>
cia de uso de los planes de ejecución
<esperar 20 segundos>
localizados en memoria. Asimismo
<capturar_procesos_bloqueados en v2>
hemos aprendido a localizar procesos
<si procesos bloqueados en v1 y v2>
<auditar/reportar estado>
que intervienen en bloqueos, desglosando el bloqueo en
dos partes: el proceso
select cur1.session_id, cur1.blocking_session_id,
que bloquea y los prosql1.text sql_bloqued, sql2.text sql_bloquer
cesos que sufren el blofrom sys.dm_exec_requests cur1
queo; de esta forma se
join @t last
pueden desarrollar
on cur1.session_id = last.session_id
cross apply sys.dm_exec_sql_text(cur1.sql_handle) sql1
prácticas de auditoría
left join sys.dm_exec_requests cur2
en sus sistemas para
on cur2.session_id = last.blocking_session_id
detectar largos tiempos
outer apply sys.dm_exec_sql_text(cur2.sql_handle) sql2
de ejecución causados
por bloqueos.
Fuente 1
El código completo lo puedes
encontrar en [5], sin embargo vamos a
explicar su parte más importante (ver
fuente 1).
La variable de tabla @t representa
las conexiones bloqueadas y sus bloqueadores. Su resultado se cruza con
la DMV sys.dm_exec_requests para
obtener el handler (referencia a la consulta en ejecución) de la sesión, y así
Referencias
INF: Using DBCC MEMORYSTATUS to
[1] Monitor SQL Server Memory Usage
http://support.microsoft.com/kb/271624/en-us
How to use the DBCC MEMORYSTATUS
command to monitor memory usage on SQL
[2] Server 2005. http://support.microsoft.com/
kb/907877/en-us
BUG: DBCC MEMUSAGE Is Not Supported
in SQL Server 7.0. http://support.
[3] microsoft.com/default.aspx?scid=kb;
en-us;196629
]
Fíjese que se hace una operación left join con el proceso bloqueador porque es posible que el proceso que está bloqueando no se encuentre en
ejecución.
Para finalizar, el proceso puede rellenar los resultados en una tabla para
analizarlo posteriormente, puede enviar un correo electrónico a una lista
de destinatarios, o incluso se puede configurar para matar al proceso que
está causando los bloqueos con el comando KILL. Mi recomendación es
registrarlo en una tabla para posteriormente analizar (y tirar del hilo),para
encontrar el proceso de negocio asociado a los bloqueos.
Batch Compilation, Recompilation, and Plan
Caching Issues in SQL Server 2005.
[4] http://www.microsoft.com/technet/prodtechnol/
sql/2005/recomp.mspx
Cómo capturar procesos bloqueadores y procesos
bloqueados en SQL Server 2005. http://siquel[5] net.etraducciones.com/default.aspx?Tema=MSS
QL05&Seccion=ADM05&Articulo=003.xml
Hands-On SQL Server 2000 Troubleshooting:
Locking and blocking de NetImpress. eBook
escrito por Kalen Delaney en el que ana[6] liza todos los pormenores de los bloqueos,
tipos de bloqueos, captura de bloqueos y
abrazos mortales. Sólo se puede adquirir en
formato electrónico en librerías virtuales.
<<dotNetManía
[
NOTA
39
dnm.inicio.fundamentos
dnm.incio.taller
Guillermo “Guille” Som
Acceso a datos con ADO.NET 2.0
(sin asistentes)
Tal como comentamos en el número anterior, en esta ocasión vamos a ver cómo
podemos acceder a una base de datos usando única y exclusivamente código, es
decir, sin usar los asistentes que Visual Studio 2005 pone a nuestra disposición y
que, en honor a la verdad, a muchos les facilitará la tarea de crear aplicaciones
ADO.NET de una forma bastante sencilla.
Como pudimos comprobar en el número anterior,
crear un formulario para acceder a una tabla o a un procedimiento almacenado es muy fácil si nos apoyamos en
los asistentes de acceso a datos que Visual Studio 2005
(y con sus limitaciones, las versiones Express) pone a
nuestra disposición. Pero algunos programadores de la
“vieja escuela” preferimos o nos gusta más escribir código para obtener casi la misma funcionalidad. Por tanto,
en esta ocasión vamos a crear un proyecto en el que tendremos la misma funcionalidad que vimos en el número anterior, pero escribiendo todo el código de forma
manual. Hacerlo de esta forma no es solo por capricho
o masoquismo, sino porque así tendremos una perspectiva diferente que nos permitirá entender mejor cómo
realizar las tareas comunes de acceso a datos con
ADO.NET 2.0.
Detalles del proyecto que realizaremos
usando solo código
Guillermo “Guille” Som
es Microsoft MVP de Visual Basic
desde 1997. Es redactor de
dotNetManía, miembro de Ineta
Speakers Bureau Latin America,
mentor de Solid Quality Learning
Iberoamérica y autor del libro
Manual Imprescindible de Visual
Basic .NET.
http://www.elguille.info
Como hemos comentado anteriormente, crearemos un proyecto que nos permitirá hacer, de forma
manual, lo mismo que hicimos en el número anterior. Y para facilitar la tarea, vamos a relacionar los
pasos que seguiremos para conseguir nuestro propósito, aunque antes resumiremos brevemente qué funcionalidad tendremos en nuestro proyecto.
El proyecto nos permitirá acceder a una base de datos
creada con SQL Server 2005 que estará definida en la
instancia de SQLEXPRESS. Esa base de datos será la mis-
ma que usamos en el número anterior (pruebaGuille) y
que podremos crear usando una utilidad que incluimos
en el ZIP con el código de ejemplo. Crearemos dos formularios; uno de ellos nos permitirá mostrar, modificar
y añadir nuevos datos, y el formato que usaremos consistirá en mostrar cada campo de la tabla (Prueba) en una
caja de texto. Además tendremos un segundo formulario en el que mostraremos los datos en un control
DataGridView; esos datos los obtendremos por medio de
un procedimiento almacenado (StoredProcedure1) al que
le indicaremos la fecha a partir de la que queremos mostrar dichos datos.
Preparativos para realizar la conexión a
la base de datos
Para poder acceder a los datos, tendremos que
conectarnos a la base de datos que será del tipo SQL
Server 2005, creada en la instancia de SQL Express,
aunque no necesariamente tiene por qué ser así. Para
realizar dicha conexión, tendremos que establecer la
cadena de conexión que le indicará a ADO.NET las
características de la base de datos a acceder. Dicha
cadena será la siguiente:
Data Source=(local)\SQLEXPRESS;
Initial Catalog=pruebaGuille;
Integrated Security=True
Particularmente, tendremos que crear un objeto
de la clase SqlDataAdapter del espacio de nombres
<<dotNetManía
<< Acceso a datos sin asistentes
41
<< dnm.inicio.taller
SqlClient. Entre otras cosas, a ese objeto le podemos
pasar la mencionada cadena de conexión, además de
la selección de los datos que queremos manipular. La
selección de datos que haremos será la de todas las
columnas y todas las filas de la tabla Prueba, quedando dicha cadena de esta forma:
using sinAsistentesCS.Properties;
Esto nos permitirá acceder a ese valor de la siguiente forma:
string cadenaConexion =
Settings.Default.conexionGuille;
SELECT * FROM Prueba
Esta cadena la podemos adaptar a los datos que queramos manipular, y no solo podemos indicarla como una
sentencia “directa” sino que también podemos usar un
procedimiento almacenado que hayamos definido en
nuestra base de datos. En este primer ejemplo “manual”
o sin asistentes usaremos un procedimiento almacenado para seleccionar los datos que se hayan modificado a
partir de una fecha. En una próxima ocasión veremos
más ejemplos en los que usaremos procedimientos almacenados no solo para mostrar o recuperar los datos, sino
también para realizar operaciones de actualización, etc.
Incluso crearemos esos procedimientos almacenados
usando código de C# (y de VB), pero por ahora es preferible dejar las cosas simples.
La cadena de conexión la vamos a guardar en los
datos de configuración de la aplicación. Para ello usaremos la ficha “Configuración” de las propiedades de la
aplicación. Tal como podemos ver en la figura 1, en el
nombre asignaremos conexionGuille y en el ámbito seleccionaremos “Aplicación”; esto hará que se añada a nuestro proyecto un fichero llamado app.config que será el
que contenga todos los valores añadidos con el ámbito
de aplicación; esos valores serán de solo lectura.
<<dotNetManía
Figura 1.Asignar la cadena de conexión a las
propiedades de configuración.
42
Para acceder a los valores de configuración podemos agregar una importación del espacio de nombres
Properties que estará incluido en el espacio de nombres de nuestra aplicación. Por ejemplo, si el espacio
de nombres predeterminado es sinAsistentesCS, tendremos que añadir la siguiente línea al principio de
los ficheros de código en los que vayamos a usar esos
datos de configuración:
Si no añadimos esa importación tendremos que acceder a los valores de configuración indicando el espacio
de nombres en el que está definida la clase Settings:
string cadenaConexion =
Properties.Settings.Default.conexionGuille;
[
NOTA
En Visual Basic 2005, los datos de configuración están incluidos en My.Settings, y podemos acceder a la cadena de conexión usando:
Dim cadenaConexion As String =
My.Settings.conexionGuille
]
Realizar la conexión a la base de datos
Una vez que tenemos preparada la cadena de conexión a la base de datos que queremos usar, es hora de
preparar las clases de ADO.NET que nos permitirán
realizar la conexión y el acceso real a esos datos.
Inicialmente necesitaremos un objeto del tipo
SqlDataAdapter, que será el que se encargue de conectar a la base de datos. También necesitaremos un objeto de tipo DataSet o DataTable, el cual recibirá los datos
que indiquemos en la cadena de selección. Debido a
que solo accederemos a los datos de una tabla, nos
resultará más simple usar un objeto del tipo DataTable,
ya que un objeto DataSet, entre otras cosas, puede
contener varias tablas, las relaciones entre ellas, etc.;
por tanto no lo necesitaremos en esta ocasión.
En el fuente 1 podemos ver el código necesario
para realizar la conexión a la base de datos indicada
en el parámetro de configuración conexionGuille que
anteriormente asignamos en las propiedades de la aplicación; esa cadena de conexión la indicamos en el consstring cadenaConexion =
Properties.Settings.Default.conexionGuille;
string sel = “SELECT * FROM Prueba”;
da = new SqlDataAdapter(sel, cadenaConexion);
dt = new DataTable();
da.Fill(dt);
Fuente 1. Creamos los objetos que usaremos para acceder a los
datos de la base de SQL Server.
<< dnm.inicio.taller
tructor del objeto SqlDataAdapter, al que también le
indicamos la cadena de selección con idea de que sepa
qué datos debe traer de la base de datos para asignarlos al objeto DataTable, acción que indicamos mediante el método Fill del adaptador.
Crear los comandos de actualización,
inserción y eliminación
SqlCommandBuilder cb = new
SqlCommandBuilder(da);
Si usamos una tabla en la que tenemos un índice automático, debemos asignar a la propiedad
MissingSchemaAction del DataAdapter el valor
AddWithKey, de forma que se genere automáticamente el valor del campo autoincremental. La asignación
la haremos de esta forma:
da.MissingSchemaAction =
MissingSchemaAction.AddWithKey;
Figura 2. El formulario principal en modo
de diseño
tros, se guardarán los cambios que hayamos hecho.
Pero si no queremos disponer de esta funcionalidad
“auto-asignadora”, podemos quitar la marca de ese control y será responsabilidad nuestra si guardamos o no
los cambios que realicemos. Para ese caso, tenemos el
botón de actualizar (la imagen con un disquete). Por
supuesto, esas asignaciones se harán solo si los datos
realmente han cambiado, comprobación que hacemos
cada vez que cambia el contenido de las cajas de textos
o el control DateTimePicker. Cuando los eventos de
cambio de esos controles se disparan, lo que hacemos
es comprobar si realmente el contenido ha cambiado
(ver el fuente 2), de forma que si se vuelve a dejar el
mismo contenido que había antes, el registro no debe
marcarse como modificado.
private bool comprobarCambiado()
{
bool cambiado = false;
Dar funcionalidad a la aplicación
Una vez que tenemos los datos en el objeto DataTable,
ya solo nos queda mostrar los datos, añadir nuevos, eliminar y actualizar los cambios y, cuando creamos conveniente, guardar esos cambios en la base de datos.
Debido a que no estamos usando un asistente, será
nuestro trabajo la creación completa de la interfaz del
usuario, por tanto tendremos que agregar los controles en los que mostraremos los datos, así como los
botones que nos permitirán navegar por los registros
de la tabla que vamos a utilizar.
Nuestro formulario de prueba tendrá el aspecto mostrado en la figura 2, que como podemos comprobar es
muy parecido al que el propio asistente de Visual Studio
2005 crearía. Aunque en esta aplicación de ejemplo hay
ciertos cambios, y no nos referimos solo a cambios en
las imágenes usadas, o en el número de botones.
En esta aplicación usaremos un control CheckBox
para indicar si queremos asignar automáticamente los
cambios que realicemos a los datos de la tabla; de esta
forma, cada vez que nos desplacemos entre los regis-
if( txtNombre.Text != dt.Rows[filaActual][“Nombre”].ToString())
cambiado = true;
if( txtEmail.Text != dt.Rows[filaActual][“e-mail”].ToString() )
cambiado = true;
if( Convert.ToDateTime( txtFechaAlta.Text).Date.CompareTo(
Convert.ToDateTime( dt.Rows[filaActual][“FechaAlta”]).Date) != 0 )
cambiado = true;
if( txtComentario.Text != dt.Rows[filaActual][“Comentario”].ToString())
cambiado = true;
return cambiado;
}
Fuente 2. La función que comprueba si se ha modificado el contenido de las cajas de
texto usadas para introducir los datos
Moverse por los registros de la tabla,
actualizando si es necesario
Como podemos comprobar en el código del fuente 2, tenemos una variable (filaActual) que controla la
fila o registro con el que estamos trabajando en cada
momento, y es por medio de esa variable con la que
<<dotNetManía
Si nuestra intención es poder añadir, eliminar y
modificar los datos que manipularemos, tenemos
que indicar los comandos correspondientes para
estas tres acciones. Esos comandos (que no son otra
cosa que instrucciones de Transact-SQL), los podemos crear de forma automática por medio de la clase SqlCommandBuilder, a cuyo constructor le pasaremos un objeto del tipo SqlDataAdapter. Los mencionados comandos se crearán basándose en la cadena de
selección que hemos utilizado, pero de esos detalles
no tenemos que preocuparnos, ya que lo único que
tenemos que hacer es algo como esto:
43
<< dnm.inicio.taller
navegamos usando los primeros cuatro botones de la
barra de herramientas. En cada método de evento de
esos botones hacemos la asignación correspondiente para
mantener adecuadamente el valor de la fila actual, y después simplemente llamamos a un método que será el que
se encargue de mostrar la información en las cajas de
texto correspondientes. En ese mismo método (que podemos ver en el fuente 3), hacemos ciertas comprobaciones adicionales, con idea de que el valor de la fila actual
esté en el rango adecuado, además de comprobar si tenemos que guardar los datos o no.
private void btnPrimero_Click(object sender, EventArgs e)
{
filaActual = 0;
mostrarDatos();
}
private void btnAnterior_Click(object sender, EventArgs e)
{
filaActual—;
mostrarDatos();
}
private void btnSiguiente_Click(object sender, EventArgs e)
{
filaActual++;
mostrarDatos();
}
private void btnUltimo_Click(object sender, EventArgs e)
{
filaActual = dt.Rows.Count - 1;
mostrarDatos();
}
Como podemos comprobar, será en el método
mostrarDatos en el que tendremos que escribir el códi-
go necesario para mostrar los datos en los controles.
Como es de suponer, si la fila que intentamos mostrar
está eliminada, simplemente salimos sin mostrar nada,
aunque debemos comprobar a qué fila debemos desplazarnos; esa parte la veremos a la hora de eliminar los
registros. En ese mismo método asignamos el valor a
otra variable (filaAnt) que nos será de utilidad en el caso
de que haya cambiado el contenido de los controles, y
la usaremos para indicar en qué fila debemos hacer la
asignación de dichos cambios. Esta comprobación la
hacemos en el método comprobarActualizar, desde el
que llamamos al método actualizarDatos, que recibe
como parámetro la fila que hay que actualizar, tal como
podemos comprobar en el fuente 4.
private void comprobarActualizar()
{
if(chkActualizarAuto.Checked && modificado &&
(filaActual != filaAnt))
actualizarDatos(filaAnt);
}
private void actualizarDatos(int fila)
{
dt.Rows[fila][“Nombre”] = txtNombre.Text;
dt.Rows[fila][“e-mail”] = txtEmail.Text;
dt.Rows[fila][“FechaAlta”] =
Convert.ToDateTime(txtFechaAlta.Text);
dt.Rows[fila][“Comentario”] = txtComentario.Text;
modificado = false;
btnGuardarEnBase.Enabled = true;
}
private void mostrarDatos()
{
if( dt.Rows.Count < 1 )
return;
if( filaActual < 0 )
filaActual = 0;
if( filaActual >= dt.Rows.Count - 1 )
filaActual = dt.Rows.Count - 1;
if(dt.Rows[filaActual].RowState == DataRowState.Deleted)
{
// TODO: Comprobar a qué fila podemos desplazarnos
return;
}
comprobarActualizar();
filaAnt = filaActual;
<<dotNetManía
txtID.Text = dt.Rows[filaActual][“ID”].ToString();
txtNombre.Text = dt.Rows[filaActual][“Nombre”].ToString();
txtEmail.Text = dt.Rows[filaActual][“e-mail”].ToString();
txtFechaAlta.Text = dt.Rows[filaActual][“FechaAlta”].ToString();
txtComentario.Text = dt.Rows[filaActual][“Comentario”].ToString();
44
txtActual.Text = (filaActual + 1).ToString();
modificado = false;
Fuente 4.El código para asignar los cambios a la fila correspondiente
y el que comprueba si se deben actualizar los datos
Como vemos, también hay un solo método en el que
hacemos todo lo necesario para asignar los cambios a la
fila que se ha modificado. El método actualizarDatos
recibe un parámetro con el índice de la fila modificada
porque nos servirá también en caso de que pulsemos en
el botón “Actualizar”, aunque en ese caso, el registro que
debemos asignar es el de la fila actual (ver fuente 5). Por
esa razón, en vez de usar una de las variables “globales”
hemos optado por usar un parámetro.
private void btnActualizar_Click(object sender,
EventArgs e)
{
actualizarDatos(filaActual);
}
Fuente 5. El método del evento del botón para actualizar
Eliminar y crear nuevos registros
}
Fuente 3. Los métodos de navegación y el encargado de
mostrar los datos en los controles
Las otras dos acciones que utilizaremos para eliminar datos o para crear nuevos en principio no tienen
<< dnm.inicio.taller
mayores complicaciones; al menos la de crear nuevos
datos, ya que simplemente añadiremos una nueva fila a
la colección de filas de la tabla. Esa acción, tal como vemos
en el fuente 6, consiste en obtener una nueva fila (DataRow)
que nos proporciona el objeto DataTable, asignar los valores predeterminados que creamos conveniente y finalmente añadirla a la colección Rows.
private void btnNuevo_Click(object sender, EventArgs e)
{
// Comprobar si los datos actuales hay que
guardarlos automáticamente
comprobarActualizar();
DataRow dr = dt.NewRow();
dr[“Nombre”] = “Nuevo”;
dr[“FechaAlta”] = DateTime.Now;
dt.Rows.Add(dr);
btnGuardarEnBase.Enabled = true;
habilitarBotones();
btnUltimo.PerformClick();
}
Fuente 6. El código para crear nuevos registros
A la hora de eliminar registros tampoco tendremos que hacer demasiado, ya que como vemos en el
fuente 7, solo tenemos que llamar al método Delete
de la fila actual.
private void btnBorrar_Click(object sender, EventArgs e)
{
// Eliminar la fila actual
// Comprobar si los datos actuales hay que
guardarlos automáticamente
comprobarActualizar();
// Confirmar el borrado
if( MessageBox.Show(“...”) == DialogResult.Yes )
{
dt.Rows[filaActual].Delete();
if( dt.Rows[filaActual].RowState == DataRowState.Deleted )
{
// Comprobar a qué fila podemos desplazarnos
// Si la primera está borrada, buscar la siguiente que no lo esté
if( filaActual == 0 )
{
for( int i = filaActual + 1; i < dt.Rows.Count; i++ )
{
if( dt.Rows[filaActual].RowState == DataRowState.Deleted )
{
filaActual++;
}
else
{
filaActual—;
break;
}
}
btnSiguiente.PerformClick();
return;
}
else
{
// Si la última está borrada, buscar la anterior que no lo esté
if( filaActual == dt.Rows.Count - 1 )
{
for( int i = filaActual - 1; i >= 0; i— )
{
if( dt.Rows[filaActual].RowState == DataRowState.Deleted )
{
filaActual—;
}
else
{
filaActual++;
break;
}
}
btnAnterior.PerformClick();
return;
}
}
if( (filaActual - filaAnt) >= 0 )
btnSiguiente.PerformClick();
else
btnAnterior.PerformClick();
btnGuardarEnBase.Enabled = true;
return;
modificado = false;
btnSiguiente.PerformClick();
}
}
Fuente 8. Comprobación a incluir en el método mostrarDatos, de qué fila
está disponible cuando hemos eliminado algunas
}
Fuente 7. El método para eliminar registros
Para que todo funcione correctamente, debemos
cambiar la comprobación de si la fila está eliminada
que mostramos en el fuente 3 por la del código fuente 8, de esa forma no entraremos en un bucle sin fin
que finalmente resultaría en un error de desbordamiento de la pila (stack overflow).
Guardar los cambios realizados en la base
de datos
La forma en que estamos tratando los datos es de forma desconectada, es decir, esos datos los estamos mani-
<<dotNetManía
Como vemos, el problema de eliminar registros
no está en la forma de eliminarlos, sino a la hora de
navegar entre los registros, ya que es posible que nos
encontremos con un registro eliminado, en cuyo caso
no debemos mostrarlo. En realidad, el problema nos
lo podremos encontrar cuando queramos navegar al
primero o al último y éstos estén eliminados, o incluso si hay varios seguidos que están eliminados. Por
tanto, en el método mostrarDatos debemos tener en
cuenta estas posibilidades y no “intentar” mostrar los
datos de los registros eliminados.
45
<< dnm.inicio.taller
pulando en nuestro equipo, pero los cambios no se están
reflejando en la base de datos. Por tanto, si queremos
que todos esos cambios se hagan efectivos en la base de
datos, debemos pulsar en el botón con el icono de varios
disquetes. Desde el método gestor de ese evento le indicaremos al DataAdapter que use las instrucciones de actualización, eliminación o inserción que correspondan, lo
cual logramos llamando al método Update del objeto
SqlDataAdapter pasándole como parámetro la tabla que
contiene las filas modificadas, y finalmente le indicaremos a la tabla que acepte los cambios. Todo esto lo hacemos por medio de dos líneas de código, tal como podemos ver en el fuente 9.
private void btnGuardarEnBase_Click(object sender, EventArgs e)
{
try
{
// Comprobar si los datos actuales hay que guardarlos automáticamente
comprobarActualizar();
da.Update(dt);
dt.AcceptChanges();
btnGuardarEnBase.Enabled = false;
}
catch(Exception ex)
{
MessageBox.Show(“Error al guardar los datos en la base\n” +
ex.Message, “Error”);
}
private void btnBuscar_Click(object sender, EventArgs e)
{
string cadenaConexion = Properties.Settings.Default.conexionGuille;
try
{
SqlDataAdapter da = new SqlDataAdapter(“StoredProcedure1”,
cadenaConexion);
da.SelectCommand.CommandType = CommandType.StoredProcedure;
da.SelectCommand.Parameters.Add(“@Param1”, SqlDbType.DateTime);
da.SelectCommand.Parameters[“@Param1”].Value =
Convert.ToDateTime(txtFecha.Text);
DataTable dt = new DataTable();
da.Fill(dt);
if( dt.Rows.Count > 0 )
{
dgvDatos.DataSource = dt;
habilitarBotones(true);
}
else
{
dgvDatos.DataSource = null;
habilitarBotones(false);
}
filaActual = filaAnt = 0;
mostrarDatos();
}
catch(Exception ex)
{
MessageBox.Show(“Error\n\n” + ex.Message, “Error”);
}
}
Fuente 10. El método para buscar datos usando un
procedimiento almacenado
}
Fuente 9. Debemos guardar en la base de datos los cambios realizados localmente
Mostrar los datos a partir de una consulta realizada con un procedimiento almacenado
<<dotNetManía
Por razones obvias de espacio no podremos ver con
detalle la parte que nos falta de este proyecto: mostrar
los datos por medio de una consulta usando un procedimiento almacenado de SQL Server; pero al menos
veremos el código que tendremos que usar, que ejecu-
46
Figura 3. El formulario usado para mostrar los datos
a partir de una fecha
taremos desde otro formulario (ver figura 3) en el que
tendremos un control DataGridView y los controles para
navegar entre los registros mostrados, además de la caja
de texto en la que indicaremos la fecha a usar para la consulta y el botón “Buscar” que será el encargado de asignar al grid los datos a mostrar.
En el fuente 10 tenemos el código de ese método
de búsqueda.
Conclusiones
Como hemos visto, no es tan complicado crear código para acceder a datos sin apoyarnos en los asistentes
de Visual Studio 2005, y la ventaja es que sobre este código tenemos más control que en el caso del código generado de forma automática. Sí, tiene un poco de más trabajo, pero en realidad lo más laborioso es el tema del
diseño del formulario de introducción de datos, el cual
aunque lo generara el propio Visual Studio con sus asistentes seguramente acabaríamos modificando para adaptarlo a nuestro gusto. Pero gracias a los nuevos controles y nuevas ayudas del diseñador de formularios de Visual
Studio 2005, esto será una tarea relativamente fácil.
Como siempre, en el ZIP con el código completo
del ejemplo usado en este artículo encontrarás tanto la
versión para C# como para Visual Basic 2005.
dnm.todotnet.qa
Dino Esposito
Informes, autenticación y
actualización por lotes
<< ¿Cuántos de vosotros escribís o mantenéis aplicaciones
Dino Esposito
es mentor de Solid Quality
Learning y autor de “Programming
Microsoft ASP.NET 2.0 Core
Reference” y “Programming
ASP.NET 2.0 Applications Advanced
Topics”, ambos de Microsoft
Press.Afincado en Italia, Dino es
un ponente habitual en los
eventos de la industria a nivel
mundial.Visite su blog en:
http://weblogs.asp.net/despos.
Puede enviarle sus consultas a
[email protected]
que generan informes semanal o mensualmente? Es una
tarea común en muchas compañías y muchos campos
de la industria. Hace unos años, Microsoft introdujo
Reporting Services como un añadido a SQL Server
2000. Hoy la herramienta ha evolucionado y se acompaña con sendos controles Windows y Web que muestran los informes del servidor, pero son también capaces de realizar gran parte del procesamiento en el cliente con una mínima degradación de rendimiento.
¿Cómo crear informes imprimibles con
ASP.NET? ¿Los Reporting Services de SQL Server
son un requisito? Me gustaría crearlo como un PDF
o una página Web navegable.
En Visual Studio 2005, hizo su debut un nuevo
control –el control ReportViewer–. Está diseñado para
permitirte añadir características avanzadas de generación de informes en las aplicaciones. Existen dos
versiones del control, para aplicaciones Windows y
Web. Vamos a centrarnos en el control ASP.NET de
servidor, ya que has mencionado esta opción expresamente. Sin embargo, el comportamiento del control Windows es muy similar.
Como sugiere el nombre, el control ReportViewer
muestra un informe al usuario, pero no suministra
capacidades de manipulación de datos. Esto es, se
precisa de la presencia de un origen de datos válido.
A este respecto, funciona tanto en modo de procesamiento local o remoto.
Cuando se trabaja en modo local, la definición
del informe se toma de un fichero con extensión
.rdlc. El fichero puede se referenciado por su nombre y ser local a la aplicación o funcionar como un
recurso incrustado en el ensamblado. En este caso,
el control abre una definición, la procesa y la carga
en el área de visualización.
En modo de procesamiento remoto, sin embargo,
el control recupera un informe de un servidor con SQL
Server 2005 Reporting Services instalado. Todo el procesamiento de datos e interpretación estructural de los
mismos se realiza en el servidor y requiere de la presencia de informes publicados previamente.
Para usar el visor de informes en modo remoto,
se necesita una copia licenciada de SQL Server 2005
Reporting Services. El procesamiento remoto ofrece una mayor escalabilidad y rendimiento y ofrece
características adicionales, tales como el uso de cachés
y nuevos formatos de salida de informes.
Demos un rápido paseo por el visor de informes,
y veamos cómo se construye un informe local.
Comenzamos por añadir un control ReportViewer a
un formulario Web y establecer su propiedad
ReportPath. La propiedad indica la fuente para el
informe a mostrar. Para proceso local, debe ser un
fichero con extensión .rdlc. ¿Cómo se crea? Añades
un nuevo ítem al proyecto del tipo Informe (Report file).
Después de abrir el RDLC para edición, los contenidos del cuadro de herramientas cambian para mostrar
la lista de ítems disponibles. Añadamos una tabla y un
objeto Chart.
Lo siguiente es que tienes que especificar el origen de datos para el informe. Seleccionamos “Orígenes
de Datos del sitio Web” y optamos por la opción
“Crear un Nuevo Origen de Datos”. El familiar asistente nos guiará en los pasos necesarios para la creación de un DataSet con estructura, a partir de una consulta. Ahí se especifica la consulta a agregar e incluir
desde la base de datos. Pongamos esta misma:
<<dotNetManía
Esta semana, la primera de las 3 preguntas de rigor resuelve problemas relacionados
con Reporting en ASP.NET.Otras preguntas se centran en la autenticación por Internet
y las actualizaciones por lotes en ADO.NET.
47
<< dnm.laboratorio.net
SELECT e.lastname AS Employee, SUM(price) AS Sales FROM
(SELECT o.employeeid, od.orderid, SUM(od.quantity*od.unitprice) AS price
FROM Orders o, [Order Details] od
WHERE Year(o.orderdate) = @year AND od.orderid=o.orderid
GROUP BY o.employeeid, od.orderid ) AS t1
INNER JOIN Employees e ON t1.employeeid=e.employeeid
GROUP BY t1.employeeid, e.lastname1
Fuente 1
La consulta recupera la cantidad total de ventas
para cada uno de los empleados de la base de datos
Northwind en un año en concreto. Los datos recuperados muestran dos columnas, Employee (tipo String)
y Sales (tipo double). Para mostrar los resultados de
la consulta en el área de la tabla del informe, arrastramos los nombres de las columnas desde la ventana del
explorador de orígenes de datos. De igual forma, debemos seleccionar qué columnas suministran los datos
para las series y cuáles las de las categorías. En este
punto la definición del informe está terminada. Puede
mejorársele, posteriormente, incluyendo algún gráfico o información de estilo.
Para ser precisos, el informe simplemente contiene información de correspondencia entre un origen
de datos concreto y sus áreas visuales constituyentes:
la tabla y el objeto Chart. La vinculación física del
informe con sus datos sucede a través del visor de
informes. El siguiente código de marcado expresa la
relación entre ambos:
<rsweb:ReportViewer ID="ReportViewer1" runat="server" Width="100%">
<LocalReport ReportPath="Samples\Core\Live\MyReport.rdlc">
<DataSources>
<rsweb:ReportDataSource DataSourceId="ObjectDataSource1"
Name="DataSet2_Employees" />
</DataSources>
</LocalReport>
</rsweb:ReportViewer>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetData"
TypeName="DataSet2TableAdapters.EmployeesTableAdapter">
<SelectParameters>
<asp:Parameter DefaultValue="1997" Name="year" Type="Decimal" />
</SelectParameters>
</asp:ObjectDataSource>
<<dotNetManía
Fuente 2
48
El visor de informes está enlazado a uno o más controles ObjectDataSource, cada uno de ellos apuntando a
un adaptador de tabla o a un objeto de negocio definido por el usuario. El visor de informes puede enlazar
múltiples orígenes de datos debido a que –a su vez– el
informe puede contener varias vistas de datos, mostrando distintos conjuntos de información. La figura 1 muestra un informe simple en una página ASP.NET.
Como puede verse, la salida del control en pantalla contiene una barra de herramientas donde puede navegarse para seleccionar el formato de expor1
Figura 1. Un informe simple, mostrado mediante
el control ReportViewer
tación a PDF o Excel. Como ya hemos mencionado, hay más formatos disponibles (así como servicios de caché) si el informe se genera mediante
Reporting Services.
Estamos construyendo una aplicación Web y queremos que cualquier usuario se autentique de forma
automática en ASP.NET utilizando su propia cuenta de acceso. Todos los ejemplos de autenticación
Forms que hemos encontrado usan una base de datos
para comprobar las credenciales. ¿Qué estamos
haciendo mal?
En teoría, las aplicaciones ASP.NET soportan
cuatro modos de autenticación: None, Passport,
Windows y Forms. Se selecciona el adecuado en el
fichero Web.Config a través de la sección <authentication> en su atributo mode. En su conjunto, solo tienen sentido los dos últimos para la mayoría de aplicaciones Web.
El modo None, significa que no hay autenticación de ninguna clase. De cualquier forma, se trata de una forma recomendada para aplicaciones de
carácter anónimo ya que deshabilita el módulo de
autenticación haciendo que el proceso de solicitud
sea más rápido.
El modo Passport requiere que el usuario haya pasado por el proceso de adhesión a la iniciativa Passport,
y, cuando se requiera autenticación, el usuario es redirigido al sitio Web de Passport donde se comprueban
sus credenciales. Olvida esta opción si estás construyendo una intranet o si la compañía no es parte del
grupo Passport.
Los dos modos restantes, –Windows y Forms–
apuntan a escenarios distintos. El modo Forms es
para aplicaciones Web en las que el código
ASP.NET es el encargado de comprobar las credenciales contra un almacén de datos administra-
Nota del traductor: tomada de la base de datos Northwind, que se instala de forma predeterminada en SQL Server 2000, pero
no en SQL Server 2005.
“
No hay razón estructural por la
que una actualización por lotes no
soporte actualizaciones multitabla
”
añadida, borrada o modificada. Para cada estatus, define un comando ADO.NET (o procedimiento almacenado) y ejecuta el comando correspondiente para
cada fila. Punto.
No hay razón estructural por la que una actualización por lotes no soporte actualizaciones multitabla. Este tipo de actualización no se basa en
ninguna característica oculta del sistema –es, solamente, código de ayuda escrito por algunos desarrolladores para ahorrar código a otros desarrolladores. ¿Por qué las actualizaciones por lotes
ADO.NET solo soportan escenarios de actualización de tabla única? Porque fue diseñado de esta
forma y porque hacerlo así simplifica notablemente el código necesario.
¿Qué puede hacerse? El método GetChanges() de
la clase DataSet permite la selección de un array con
todas las filas de una tabla con un estatus particular:
añadida, borrada o modificada. De esta forma, es muy
sencillo almacenar en distintos contenedores todas las
filas borradas o actualizadas para cada tabla implicada. A continuación, llamas a una sobrecarga poco
conocida del método Update en el adaptador asociado que –justamente– acepta un array de objetos
DataRow.
int Update(DataRow[] rows);
Mediante la llamada a la sobrecarga de Update con
varios arrays de objetos DataRow se nos permite construir nuestra propia lógica de actualización para múltiples tablas. Por ejemplo, dadas un par de tablas de
Pedidos y Detalles_de_Pedidos, cuando el usuario solicita el borrado de un pedido puedes, primero, actualizar todas las filas de Detalles_de_Pedidos que están
borradas en forma lógica y, posteriormente, actualizar las filas de Pedidos marcadas para borrado. Todavía
se utilizan actualizaciones por lotes, pero usando tablas
relacionadas.
Con toda seguridad, este código parece código
estándar que se implementa de forma manual. Por
otra parte, se trata de una forma de atajo y no es practicable en todos los casos.
Traducción por Marino Posadas
<<dotNetManía
do por el usuario. El modo Windows es para aplicaciones de intranet.
Cuando IIS recibe una petición de ASP.NET, primero acredita al usuario utilizando el esquema de
autenticación activo: Basic, Digest o Integrado con
Windows. A continuación la clave de seguridad se pasa
a ASP.NET junto con la petición. Lo que suceda a
continuación depende de la configuración de la autenticación en ASP.NET.
Cuando la autenticación es Windows, ASP.NET
acepta la credencial enviada por IIS y copia la información al objeto Context de usuario. No se llevan a
cabo más acciones de autenticación. Si la autenticación se establece a Forms, ASP.NET ignora la información enviada por IIS y procede con su propio sistema de autenticación. En la mayoría de aplicaciones
de Intranet, cuando los usuarios se conectan se les
solicita la credencial. Éstas son transmitidas al servidor (dependiendo el esquema de autenticación, en
modo de texto plano o codificado) y validadas contra
el grupo de usuarios autorizados.
Si configuras IIS para soportar Windows Integrado,
no aparece ninguna caja de diálogo, sino Internet
Explorer y la información introducida es transmitida
al servidor automáticamente sin intervención posterior. En este punto, si ASP.NET se configura como
autenticación Windows, el nombre de login del usuario se utiliza para rellenar el campo Name del objeto
User, siempre que éste sea reconocido y aceptado por
el servidor Web.
En suma, para obtener el comportamiento deseado tienes que habilitar la opción “Integrada con
Windows” como esquema de autenticación IIS y dejar
el modo autenticación ASP.NET en su forma predeterminada –Windows.
Por último, hay que recalcar que la autenticación
“Integrada con Windows”, no está soportada fuera de
la familia de navegadores Internet Explorer (aunque
funciona incluso en versiones tan arcaicas como
Internet Explorer 2.0) y es impracticable con la presencia de cortafuegos.
Sé que la opción de actualización por lotes de
ADO.NET está diseñada para actualizar una tabla a
la vez. Sin embargo, tengo un montón de tablas relacionadas y quiero usar esta técnica para persistir los
cambios periódicamente a una base de datos. ¿Alguna
sugerencia?
La opción de actualización por lotes de ADO.NET
es cualquier cosa menos una herramienta mágica que
ahorre a los desarrolladores el esfuerzo de codificar
un montón de código complejo. Puede ahorrarte tiempo, pero no es mágica. Ni siquiera es muy lista. La
actualización por lotes, implementa una especie de
caché de escritura donde volcar los cambios que quieres realizar en la base de datos en un momento dado.
El mecanismo recorre las filas de una tabla dada
y comprueba el estatus de actualización de esas filas:
[email protected] [email protected]
<< dnm.laboratorio.net
49
dnm.laboratorio.net
Lorenzo Ponte
FileHelpers
Es relativamente frecuente que el trasvase de información desde/hacia una aplicación se realice mediante archivos planos generados periódicamente. En tales ficheros, los registros se almacenan en líneas de texto que deben ser interpretadas para
su posterior explotación. En el laboratorio de esta semana analizamos una librería
que permite importar, exportar y explotar con gran comodidad archivos de este
tipo en aplicaciones .NET.
<< FileHelpers es una librería destinada a facilitar el procesamiento de información proveniente de ficheros
planos. Estos ficheros suelen crearse mediante una
planificación temporal y depositarse en una ubicación física. Dentro de los ficheros, los registros se
almacenan en líneas, con los campos delimitados por
caracteres de separación preestablecidos o representados sobre un ancho fijo.
Tradicionalmente, el tratamiento de estos datos
se realiza mediante las conocidas funciones
ReadLine(), Substring(), Split(), Convert(), etc.
FileHelpers evita tener que escribir este tipo de
código, gracias a un potente asistente al que podremos indicarle de qué forma queremos que se haga
la extracción de los datos y que generará automáticamente una estructura de clase para dar soporte al formato.
FileHelpers es una librería
destinada a facilitar el procesamiento
de información proveniente
de ficheros planos
10248|VINET|04071996|32.38
10249|TOMSP|05071996|11.61
10250|HANAR|08071996|65.83
10251|VICTE|08071996|41.34
Fuente 1
Lorenzo Ponte es redactor de
dotNetManía. Es Arquitecto de
Sistemas y Aplicaciones .NET.
Experto en Datawarehousing y
Business Intelligence, Marketing
Intelligence, CRM analítico.
Actualmente es consultor de la
empresa Matchmind y
Webmaster de clikear.com
Veamos un ejemplo muy sencillo. Supongamos que
el archivo a tratar tiene la siguiente estructura:
La clase que se generará para leer esos datos es la
que vemos en el fuente 2.
En nuestro código, el primer paso para
utilizar la librería consistiría en agregar una
referencia al ensamblado FileHelpers.dll.
Para leer y escribir archivos con el formato especificado, debemos crear una instancia de la clase
FileHelperEngine y usarla tal y como podemos ver en
el fuente 3.
<< dnm.laboratorio.net
FileHelpers nos ha dejado muy
buen sabor de boca, destacando su
facilidad de uso y las posibilidades que
ofrece para la explotación de datos
almacenados en ficheros
[DelimitedRecord("|")]
public class Orders
{
// No se necesitan conversores para
// los tipos básicos
public int OrderID;
public string CustomerID;
[FieldConverter(ConverterKind.Date, "ddMMyyyy")]
public DateTime OrderDate;
Fuente 2
FileHelperEngine engine = new
FileHelperEngine(typeof(Orders));
// Para leer usamos:
Orders[] res = (Orders[])
engine.ReadFile("Archivo de Entrada.txt");
// Para escribir usamos:
engine.WriteFile("Archivo de Salida.txt", res);
Fuente 3
La variable res es un array en el que cada elemento se mapea a un registro del archivo original. Con
lo cual podríamos recorrer la información de la
siguiente manera:
foreach (Orders order in res)
{
Console.WriteLine("Información del pedido:");
Console.WriteLine(order.CustomerID + " - " +
order.OrderDate.ToString("dd/MM/yy"));
}
Fuente 4
Algunas de las características principales de
FileHelpers son:
• Fácil de usar.
• Funciona tanto para archivos delimitados como
para los de ancho fijo.
• Ofrece conversores de tipos automáticos y personalizados.
• Trabaja también en modo asincrónico.
• Soporta cualquier lenguaje de .NET: C#,
VB.NET, J#.
• Soporta .NET Compact Framework.
• Soporta plantillas CodeSmith para generar las
clases automáticamente.
• Puede trabajar tanto con archivos o flujos (streams).
• Soporta diferentes tipos de manejo de errores.
• Soporta cadenas entrecomilladas como en MS
Excel.
• Soporta la posibilidad de establecer el tipo de
codificación de los datos.
• Permite interpretar el valor nulo en caso de que
existan campos vacíos.
• Posibilidad de modificar dinámicamente diversas características.
• Documentación en inglés bastante completa.
Conclusiones
Desde el laboratorio de dotNetManía tenemos que
decir que FileHelpers nos ha dejado muy buen sabor
de boca, destacando su facilidad de uso y las posibilidades que ofrece para la explotación de datos almacenados en ficheros. Felicitamos a su creador Marcos Meli
por el gran trabajo realizado y animamos a la comunidad a seguir su ejemplo.
Ficha técnica
Nombre
FileHelpers
Versión
1
Autor
Marcos Meli
Web
http://filehelpers.sourceforge.net
Categoría
Gestión de archivos
Precio
Gratis (código fuente incluido)
Valoración
<< dotNetManía
public decimal Freight;
}
51
dnm.comunidad.eventos
52
eventos.eventos.eventos.eventos.eventos.eventos
<< dotNetManía
<<
dnm.comunidad.eventos
Microsoft celebró el Developer Day de Madrid
Microsoft reunió a más de 600 personas con las que compartió algunas de
las nuevas funcionalidades sobre seguridad para desarrolladores.
Microsoft organizó el día 31 de
mayo en Madrid, el Microsoft Developer
Day, el mayor evento que la compañía
organiza para el colectivo de desarrolladores españoles, al que asistieron más de
600 personas. En esta ocasión estuvo
dedicado a las nuevas funciones de seguridad de Windows Vista para desarrolladores y las ventajas que ofrece la plataforma .NET en materia de seguridad.
Después de la keynote introductoria
de Héctor Sánchez Montenegro, director de seguridad corporativa de Microsoft
Ibérica, empezaron las charlas técnicas
con Marino Posadas de Alhambra-Eidos
y redactor jefe de esta publicación, que
junto a Jesús Villalobos de Certia expusieron su sesión “Procesos para un desarrollo seguro”. En esta sesión se explicó
el modelo de amenazas y las estrategias
de defensa, así como las herramientas
para el desarrollo seguro o cómo se articulan dichas estrategias en una aplicación ASP.NET 2.0.
Continuó Fernando Guerrero,
regional director de Solid Quality Learning,
con su ponencia “Seguridad en SQL Server 2005 para desarrolladores”, empezando por ganarse al público en clave de
humor con una serie de barbaridades que
usuarios y desarrolladores acostumbramos a realizar y que le sirvió para convencernos de lo necesario del principio de menor
privilegio, por el cual la mayor parte de servicios están parados o deshabilitados de
inicio. Aprendimos nuevas características
de seguridad en SQL Server 2005, incluyendo el cifrado de los datos almacenados con certificados digitales y las técnicas de funcionamiento aislado del CLR.
Después de un merecido descanso,
vino la ponencia “Autorización, autenticación y cifrado en .NET” que expuso
Pablo Abbate, de Danysoft, en la que
aprendimos cómo incorporar las técnicas de autorización, autenticación y cifrado de datos que incorpora el nuevo .NET
Framework, en nuestras aplicaciones.
Entonces intervino César de la
Torre, de Renacimiento, uno de los principales expertos de WCF y Web Services
en nuestro país, para exponer su ponencia “Aplicaciones distribuidas seguras con
WS-Security”. La gran de mayoría de
las aplicaciones desarrolladas en la actualidad exponen o utilizan componentes y
servicios distribuidos. César nos mostró
las tecnologías incluidas en WSE 3.0 y
Windows Communication Foundation para
evitar que estas comunicaciones distribuidas sean un punto débil en la seguridad de nuestras aplicaciones.
“Defensa contra ataques Web comunes” era el título de la ponencia de Isabel
Gomez de Microsoft Ibérica y de Miguel
Jiménez de Ilitia, en la que nos enseñaron las técnicas que utilizan los atacan-
“La naturaleza de los ataques a la seguridad es muy variada y,
de hecho,también lo es la defensa contra dichos ataques.Buena
parte de esa defensa tiene que ver con la administración del
propio sistema operativo, pero nuestro código puede, en
ocasiones,permitir lo que el propio sistema impide y eso supone
un planteamiento serio de todo el modelo de amenazas.”
(Marino Posadas, Seguridad en .NET Framework).
El cuaderno técnico “Programación segura con .NET
Framework” de Marino Posadas se regaló a cada
asistente de este evento centrado en la seguridad en
el desarrollo de aplicaciones.
tes en los sitios Web como buffer overrun,
inyección SQL, cross-site scripting, robo de
sesión, etc., y cómo defendernos de ellos.
Ya en el turno de tarde, tuvimos ocasión de escuchar la distendida charla
“Seguridad para el cliente rico. Presente
y futuro” de David Carmona de Microsoft
Ibérica (el cliente) y Pablo Peláez, regional director de Visual Programming (el
rico). El nuevo concepto de smart client
también plantea cuestiones de seguridad
que hay que atajar de raíz. En esta sesión
vimos cómo publicar nuestra aplicación
Windows Forms o Windows Presentation
Foundation para que nuestros usuarios
puedan acceder a su aplicación de una
forma transparente y segura.
Los dos MVP de Windows Security
Chema Alonso, de Informática 64 y Juan
Luis Rambla expusieron su ponencia
“Implantación de una infraestructura
segura” en la que nos explicaron que la
multitud de servicios del sistema operativo y del propio hardware que utilizan
nuestras aplicaciones, también pueden
añadir puntos vulnerables. Aprendimos
las mejores prácticas para que estos sistemas externos a nuestras aplicaciones
estén bien configurados y actualizados
para que no proporcionen una puerta de
entrada a los atacantes.
Para finalizar, “Novedades de seguridad en Windows Vista” de José Parada
Gimeno, ITPro evangelist de Microsoft
Ibérica. Un completísimo repaso a la
seguridad en Windows Vista y las implicaciones que tienen las nuevas características del sistema operativo en el desarrollo de sus aplicaciones.
<< dnm.comunidad.eventos
CODECAMP - VIC 2006
MSDN y Spain.NET han organizado, con el apoyo del Ayuntamiento de Vic,
el segundo CodeCamp, un evento de fin
de semana enmarcado en el proyecto
Emprendia y dirigido a desarrolladores
de software que quieran conocer las oportunidades que la tecnología puede brindarles a la hora de desarrollar sus negocios. Siguiendo este objetivo, entre las
sesiones del CodeCamp se incluyeron
temas como la construcción de un plan de
negocio, la formación de una sociedad o
la búsqueda de subvenciones. Además, se
presentaron casos de éxito contados en
primera persona por los responsables de
empresas emprendedoras.
David Carmona en el momento en que era
entrevistado por la cadena televisiva “La Sexta”
Grupo de Usuarios .NET de Málaga
Durante
los días 17 y
18 de junio
pudimos
asistir a uno
de los eventos más interesantes
celebrados
en nuestro
país. Total- Alfonso Rodríguez y Pep Lluis
mente gra- Baño, los padres del invento
tuito (incluyendo alojamiento, comida y actividades
lúdicas) con ponencias de destacadísimos
oradores entre los que se encontraban:
David Carmona, Aurelio Porras,
Guillermo Som, Salvador Ramos,
Octavio Hernández, Jesús Villalobos,
Vicenç Masanas, Daniel Seara, Dino
Esposito, Nilda Díaz y Marta Santos.
La ciudad de Vic ha sido elegida para
celebrar la segunda edición del CodeCamp
por el vínculo existente entre el municipio y Microsoft, ya que fue aquí donde se
creó en el año 2001 Spain.NET, el primer
Grupo de Usuarios de tecnología Microsoft .NET en España y uno de los primeros en Europa.
En Málaga, el 6 de
junio, tuvo lugar la
reunión inaugural del
Grupo de Usuarios
.NET de Málaga. El
lanzamiento fue todo
un éxito, con más de
35 asistentes. Como
ponente invitado,
Miguel Katrib de- Miguel Katrib
leitó a los asistentes con las novedades más
interesantes en C# 3.0, así como LINQ. Se
explicó los objetivos del grupo y se fijó fecha
para próxima reunión. El grupo de usuarios
de .NET nació en 2006, en un intento de
promover de alguna forma a los usuarios de
tecnología Microsoft .NET y en concreto
desarrolladores que se encuentran en Málaga
y su alrededor. El fundamento del grupo es
la de fomentar la comunicación entre sus
miembros, así como a través de la Web para
una audiencia más amplia. Como cualquier
grupo de usuarios, se hacen reuniones mensuales donde se comparte información, se
discute sobre distintos aspectos relacionados con la vida profesional y, en general,
todo lo que puede ayudar para progresar en
la tecnología .NET.
Más información: www.malagadnug.org.
Solid Quality Learning University celebró el II SQLU Summit
El equipo de mentores de Solid Quality Learning en el Summit de Madrid
De esta forma, Solid Quality Learning continúa con sus
tareas de capacitación y formación para todos los especialistas
relacionados con el mundo de las aplicaciones que administran
información. Capacitación que continuará en sus instalaciones
de formación así como con sus capacidades de entrenamiento
en línea. Para saber más de próximos eventos y entrenamientos, visita www.sqlu.com.
dnm.comunidad.eventos
<< dotNetManía
Durante la semana del 19 al 23 de junio, Solid
Quality Learning repitió su exitoso summit en Madrid.
En esta oportunidad, las distintas sesiones se dividieron en dos grandes grupos: la Sala de los índices
y la Sala de los cubos. En la primera, temas relacionados con la
optimización, alta disponibilidad y programabilidad fueron los
más importantes, mientras que en la segunda se vieron en profundidad temas de inteligencia de negocios, análisis de información y generación de informes.
La calidad de las sesiones ha sido determinada por sus mentores, como Fernando Guerrero, Adolfo Wiernik, Alejandro
Leguizamo, Antonio Soto, Daniel Seara, David Carmona
(Microsoft), Eladio Rincón, Eugenio Serrano, Francisco
González, Guillermo Som, Javier Loría, Jordi Rambla,
Miguel Egea y Salvador Ramos.
Además de los trascendentes temas tratados a nivel de base
de datos, también fue posible estudiar temas relacionados con
el desarrollo de aplicaciones relacionadas con datos, así como
las últimas novedades acerca de la administración de proyectos
de bases de datos con Team System Edición para desarrolladores de bases de datos.
53
dnm.comunidad.net
<<
dnm.comunidad.net
Emprendia
La iniciativa para los e-mprendedores
<<dotNetManía
<< ¿Quién no ha soñado con repetir el éxito de la fre-
54
gona o el chupa-chups? Todos los desarrolladores tenemos
ese gusanillo desde jóvenes, aunque en contadas ocasiones
se hace realidad. Y no suele ser por falta de ideas, que las hay
y muy buenas en España, sino por el momento de empezar
a ponerlas en práctica. Ahí es donde empiezan los problemas: ¿Cómo empiezo a desarrollar? ¿De dónde saco información? ¿Cómo lo doy a conocer? ¿A quién se lo vendo?
En MSDN Comunidades llevamos conociendo a gente con estas inquietudes desde nuestros inicios. Al contrario
que en otros sectores, el perfil de desarrollador emprendedor suele ser muy técnico, con talento, escasos conocimientos
de negocio y trabajador por cuenta ajena que araña tiempo
a los amigos o la familia para seguir desarrollando software
en su casa. Ésta es la magia del software: sin apenas inversión, cualquier persona con ganas y talento puede lanzar al
mercado un producto innovador que consigue competir con
las grandes corporaciones. De hecho la mayoría de estas corporaciones nacieron así, en un garaje americano entre varios
amigos con gafas, pantalones de pana y seguidores de La
Guerra de las Galaxias.
Tengo la gran suerte de trabajar en una empresa que
empezó así. No fue un ejecutivo agresivo recién salido de
un MBA el que fundó Microsoft, sino dos “geeks” que disfrutaban escribiendo código y sin aspecto de empresarios.
Aunque puede sonar a broma, algunas veces todavía se ve
ese espíritu en Microsoft; solo hay que ver algunas iniciativas que se llevan a cabo (véase www.on10.net o www.channel9.msdn.com).
Hace poco me encontré de cerca con este espíritu de
garaje en Microsoft. Desde MSDN Comunidades queríamos ayudar a estos desarrolladores inquietos que se quedan
trabajando por la noche en una idea loca. Cuando solo era
un esbozo, se la contamos a varios miembros de la dirección
de Microsoft Ibérica y el resultado fue increíble. No solo
nos animaron con la idea, sino que nos apoyaron directamente, ilusionados como si fueran ellos los emprendedores
que se encierran en sus garajes.
Así nació Emprendia. Con esta iniciativa queremos ayudar a los desarrolladores de software españoles con ideas
innovadoras en la puesta en marcha de un proyecto empresarial. El objetivo es claro: colaborar con los desarrolladores para que sus ideas puedan convertirse en una realidad.
Para ello dentro del programa Emprendia se ofrecen tres
tipos de ayudas:
• Formación (¡Aprende!): los proyectos de software innovadores requieren en muchas ocasiones tecnologías diver-
sas que utilizan los últimos avances de la industria.
Dispositivos móviles, comunicaciones distribuidas, servicios ofrecidos por Internet o nuevas experiencias de
usuario requieren una formación técnica que no está disponible en muchas ocasiones. El programa Emprendia
incluye múltiples recursos gratuitos para la formación
necesaria en estas tecnologías. Estos cursos se añaden a
los que ya estaban disponibles online en MSDN y complementan la formación requerida por un emprendedor.
No podemos olvidar tampoco la formación de negocio
necesaria para tener éxito: finanzas, subvenciones, constitución de empresas, etc. Este tipo de formación también se añade al porfolio de MSDN, estando disponible
on line para todos los desarrolladores.
• Puesta en marcha (¡Construye!): una vez hayamos
decidido ser emprendedores, llega la hora de empezar a
trabajar. Los participantes del programa tienen acceso a
multitud de recursos subvencionados para la puesta en
práctica del proyecto. En esta línea se ofrecen los
CodeCamps, encuentros de fin de semana donde conocer a otros emprendedores y aprender las tecnologías
más “calientes” del mercado e información de los expertos en cómo formar una empresa. También se ofrece
acceso gratuito a sesiones de negocio intensivas de dos
días impartidas por la prestigiosa escuela de negocios
IDE-CESEM. Tampoco podemos olvidarnos de los
recursos necesarios para desarrollar el software. Los participantes tienen acceso a una subvención íntegra o casi
íntegra (dependiendo del volumen) de todo el software
necesario de Microsoft durante el primer año. Se ofrece también la posibilidad de asistir al Microsoft
Technology Center que Microsoft comparte con el
Gobierno de Aragón para una consultoría tecnológica
sobre el proyecto.
• Comunicación (¡Comunica!): Microsoft ofrece a los
proyectos participantes del programa Emprendia diversos medios de comunicación para dar a conocer su idea.
Los emprendedores que así lo deseen pueden publicar
su proyecto en la Web de Microsoft o participar en eventos de forma conjunta.
Para más información sobre Emprendia puedes acceder
al sitio web www.msdnemprendia.com. ¡Contamos contigo!
David Carmona
Grupo Desarrolladores y Plataforma
Microsoft Ibérica
<< dnm.biblioteca.net
dnm.biblioteca.net
Programming Microsoft ASP.NET 2.0 Core Reference
Dino Esposito
Editorial: Microsoft Press
ISBN: 0735621764
Páginas: 336
Primera edición: Noviembre, 2005
Idioma: Inglés
La obra, que ha tenido una acogida espectacular en Amazon, con 5 estrellas por parte
de todos los comentarios de lectores, es un trabajo perfecto para el que desea saber de
verdad cómo funciona ASP.NET en su interior y cómo eso se refleja en todos los aspectos de nuestras aplicaciones, desde la flexibilidad hasta la escalabilidad o el rendimiento. De obligada lectura, que se dice…
Visual C# 2005:A Developer’s Notebook
Jesse Liberty
Editorial: O'Reilly Media
ISBN: 059600799X
Páginas: 221
Primera edición: Mayo, 2005
Idioma: Inglés
Jesse Liberty es bien conocido por la capacidad divulgativa de sus obras (numerosísimas, sobre la plataforma .NET), dando cobertura tanto a los lenguajes principales (C#
y Visual Basic .NET), como a la plataforma y los más destacados espacios de nombres
para desarrollo (ASP.NET, ADO.NET). Este libro también ha tenido una acogida espléndida por la comunidad de desarrolladores y tiene –además– la ventaja de resultar una
auténtica actualización (sin repeticiones) de la versión anterior.
El autor se centra en todas las novedades del lenguaje, las explica y decora con código
fuente explicativo y nos ofrece aspectos no vistos en otras obras de divulgación sobre
C# 2.0, dentro de un marco conciso pero exacto donde se dice justamente lo que se quiere decir y nada más. Una excelente actualización.
<<dotNetManía
<<
Nuestro admirado colaborador italiano, Dino Esposito, ha reunido algunos de sus mejores consejos sobre el desarrollo en ASP.NET 2.0 dentro de esta obra de calado, donde
nos ilustra con la precisión que en él es característica y, sobre todo, nos permite tener
una auténtica “voz de la experiencia” sobre esta herramienta, con la que lleva trabajando desde las primeras versiones alfa.
55
[ ]
dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>>
dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >>> dnm.club >
<< dnm.desvan
noticias.noticias
Marino Posadas
Microsoft desvela los contenidos de su nueva certificación
de arquitectura (MCA:Microsoft Certified Architect)
La compañía de
Redmond explicaba a
primeros del pasado
mes de junio los contenidos y objetivos perseguidos durante más de
un año de proceso de
diseño de esta certificación, que se prevé, con mucho, la
más exigente de todas las propuestas hasta el momento.
Casualmente, en la entrevista con Arvindra Sehmi que
el lector encontrará en páginas interiores, comentábamos con él esta certificación y nos ampliaba información
al respecto. Independientemente, ya existe una página
Documentos en la Red
oficial sobre MCA: http://www.microsoft.com/learning/
mcp/architect/overview.
Microsoft integrará todas sus herramientas de BI en la
solución PerformancePoint Server 2007
Según BI-Spain.com (http://www.bi-spain.com),
Microsoft está trabajando en la integración de sus herramientas de BI (Business Scorecard Manager 2005 y ProClarity
Analytics Server) en un mismo producto llamado
PerformancePoint Server 2007. La versión beta (se dice),
estará lista para noviembre de este año y el producto, para
mediados de 2007. Además, PerformancePoint Server 2007
mejorará las capacidades de análisis y reporting de SQL
Server 2005, utilizando el nuevo Office 2007.
Sitios del mes
Vídeo de BJ Ostergren, para la CNN,
en el que se muestra qué fácil resulta
robar datos de identidad en Internet.
Entre sus quejas, la más importante
recae sobre los gobiernos, que -a vecesdejan información confidencial en la red. Accesible en
http://www.cnn.com/2006/TECH/internet/06/12/idtheft.internet/index.html.
Nuevos foros MSDN y TechNet
en castellano: Disponibles en las
direcciones
http://forums.
microsoft.com/msdn-es/default.aspx?
siteid=11 y http://forums.microsoft.com/TechNet-ES/default.aspx?
SiteID=30 respectivamente. Puro desarrollo.
Sitio de David
Cervigón, evangelista de Microsoft y ponente habitual en conferencias y eventos, además de especialista en interioridades de los sistemas. Sin desperdicio: http://blogs.technet.com/davidcervigon.
20 Consejos para los autores de una bitácora (Corporate
Weblog Manifesto): Un código de comportamiento eficaz y ético para los autores de bitácoras. Para los no autores, algún consejo interesante en otros campos. Por
Scobleizer (http://scoble.weblogs.com/2003/02/26.html).
Blog de Robert Hensing, miembro de la división Security
Engineering and Communications en Redmond. Buenos
comentarios sobre seguridad, y sobre todo, de primera
mano. En http://blogs.technet.com/robert_hensing.
Utilidades del mes
Blog de Aaron Margosis, de similar corte al anterior, y tam-
<<dotNetManía
Control de usuario de
Google Maps para
ASP.NET. En el sitio
58
http://googlemaps.subgurim.net puede encontrarse
una interesante aportación
de un grupo español. Es
un control que emula Google-Maps, y posee un montón
de opciones de configuración y programación, a través de
una sencilla API. Requiere de un registro, eso sí.
bién con la seguridad en mente (http://blogs.msdn.com/
aaron_margosis). A destacar, varias series de artículos sobre
técnicas seguras de programación y testeo.
Los sitios de Lluís Franco: Este MVP en Visual Basic,
no se conforma con el sitio Web de su empresa (la
recomendable http://www.uyssoft.com), sino que desde hace algún tiempo actualiza una interesante bitácora de
noticias sobre desarrollo en todas las tecnologías .NET:
http://msmvps.com/blogs/lfranco/archive/category/1118.aspx.

Documentos relacionados

Entrevista a Jim Gray Entrevista a Jim Gray

Entrevista a Jim Gray Entrevista a Jim Gray Delphi 2005 ofrece la posibilidad de desarrollar para la plataforma .NET utilizando dos vías diferentes para el acceso a datos: a través de los recursos que ofrece la VCL.NET, una librería de compa...

Más detalles