53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

291
Este texto está pensado para aquellos que, teniendo conocimientos de la tecnología ASP, deseen aumentar la potencia y escalabilidad de sus aplicaciones mediante el uso de componentes compilados. La primera parte del libro consiste en un recordatorio de las características más importantes de ASP, mientras que la segunda se centra en el diseño y uso de componentes. Se tratan temas como la creación de librerías de enlace dinámico (DLLs), uso de componentes desde páginas ASP, modelo COM+, Servicios de Componentes, componentes de acceso a datos, componentes transaccionales, MSMQ y ADSI. Se requieren unos conocimientos básicos de Windows, fundamentos de Internet/Intranet, lenguaje HTML y tecnología ASP, así como ciertas nociones de programación con Visual Basic. D D E E S S A A R R R R O O L L L L O O D D E E A A P P L L I I C C A A C C I I O O N N E E S S C C O O M M + + PARA I INTERNET / /INTRANET CON A A S S P P 3 3 VÍCTOR ARRONDO, ÁNGEL ESTEBAN Desarrollo de software

Transcript of 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Page 1: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Este texto está pensado para aquellos que, teniendo conocimientos de la tecnología ASP, deseen aumentar la potencia y escalabilidad de sus aplicaciones mediante el uso de componentes compilados. La primera parte del libro consiste en un recordatorio de las características más importantes de ASP, mientras que la segunda se centra en el diseño y uso de componentes. Se tratan temas como la creación de librerías de enlace dinámico (DLLs), uso de componentes desde páginas ASP, modelo COM+, Servicios de Componentes, componentes de acceso a datos, componentes transaccionales, MSMQ y ADSI. Se requieren unos conocimientos básicos de Windows, fundamentos de Internet/Intranet, lenguaje HTML y tecnología ASP, así como ciertas nociones de programación con Visual Basic.

DDEESSAARRRROOLLLLOO DDEE AAPPLLIICCAACCIIOONNEESS CCOOMM++

PPAARRAA IINNTTEERRNNEETT//IINNTTRRAANNEETT CCOONN AASSPP 33 VVÍÍCCTTOORR AARRRROONNDDOO,, ÁÁNNGGEELL EESSTTEEBBAANN

Desarrollo de software

Page 2: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 3: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

ADVERTENCIA LEGAL

Todos los derechos de esta obra están reservados a Grupo EIDOS Consultoría y Documentación Informática, S.L.

El editor prohíbe cualquier tipo de fijación, reproducción, transformación, distribución, ya sea mediante venta y/o alquiler y/o préstamo y/o cualquier otra forma de cesión de uso, y/o comunicación pública de la misma, total o parcialmente, por cualquier sistema o en cualquier soporte, ya sea por fotocopia, medio mecánico o electrónico, incluido el tratamiento informático de la misma, en cualquier lugar del universo.

El almacenamiento o archivo de esta obra en un ordenador diferente al inicial está expresamente prohibido, así como cualquier otra forma de descarga (downloading), transmisión o puesta a disposición (aún en sistema streaming).

La vulneración de cualesquiera de estos derechos podrá ser considerada como una actividad penal tipificada en los artículos 270 y siguientes del Código Penal.

La protección de esta obra se extiende al universo, de acuerdo con las leyes y convenios internacionales.

Esta obra está destinada exclusivamente para el uso particular del usuario, quedando expresamente prohibido su uso profesional en empresas, centros docentes o cualquier otro, incluyendo a sus empleados de cualquier tipo, colaboradores y/o alumnos.

Si Vd. desea autorización para el uso profesional, puede obtenerla enviando un e-mail [email protected] o al fax (34)-91-5017824.

Si piensa o tiene alguna duda sobre la legalidad de la autorización de la obra, o que la misma ha llegado hasta Vd. vulnerando lo anterior, le agradeceremos que nos lo comunique al e-mail [email protected] o al fax (34)-91-5017824). Esta comunicación será absolutamente confidencial.

Colabore contra el fraude. Si usted piensa que esta obra le ha sido de utilidad, pero no se han abonado los derechos correspondientes, no podremos hacer más obras como ésta.

© Victor Arrondo y Ángel Esteban, 2000 © Grupo EIDOS Consultaría y Documentación Informática, S.L., 2000

ISBN 84-88457-20-0

Desarrollo de Aplicaciones COM+ para Internet/Intranet con ASP 3

Victor Arrondo y Ángel Esteban Responsable editorial Paco Marín ([email protected]) Autoedición Magdalena Marín ([email protected]) Victor Arrondo ([email protected]) Ángel Esteban ([email protected])

Coordinación de la edición Antonio Quirós ([email protected])

Grupo EIDOS C/ Téllez 30 Oficina 2 28007-Madrid (España) Tel: 91 5013234 Fax: 91 (34) 5017824 www.grupoeidos.com/www.eidos.es www.LaLibreriaDigital.com

Page 4: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 5: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Índice

ÍNDICE................................................................................................................................................... 5 INTRODUCCIÓN A ASP................................................................................................................... 11

ANTECEDENTES DE ASP: LA ESPECIFICACIÓN CGI .......................................................................... 11 DEFINICIÓN DE ASP........................................................................................................................... 12 APLICACIONES ASP........................................................................................................................... 13 APORTACIONES DE ASP..................................................................................................................... 14 SINTAXIS DE ASP............................................................................................................................... 15 OBJETOS INTEGRADOS EN ASP 3.0.................................................................................................... 17 COMPONENTES DE SERVIDOR ............................................................................................................ 18 NOVEDADES DE ASP 3.0 ................................................................................................................... 19

Mejoras generales en ASP 3.0....................................................................................................... 19 El objeto Response......................................................................................................................... 20 El objeto Server ............................................................................................................................. 20 El objeto ASPError........................................................................................................................ 24 Componente de registro de IIS (Logging Utility) .......................................................................... 26 Aplicaciones ASP con IIS 5.0 ........................................................................................................ 30 Otros cambios................................................................................................................................ 32

MODELO DE OBJETOS DE ASP. PARTE I .................................................................................. 35 INTRODUCCIÓN .................................................................................................................................. 35 EL OBJETO RESPONSE ........................................................................................................................ 36

Colecciones del objeto Response................................................................................................... 37 Propiedades del objeto Response .................................................................................................. 39 Métodos del objeto Response......................................................................................................... 41

EL OBJETO REQUEST.......................................................................................................................... 44

Page 6: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

6

Colecciones del objeto Request ..................................................................................................... 44 MODELO DE OBJETOS DE ASP. PARTE II ................................................................................ 49

EL OBJETO APPLICATION ................................................................................................................... 49 Colecciones del objeto Application ............................................................................................... 51 Métodos del objeto Application ..................................................................................................... 52 Eventos del objeto Application. El GLOBAL.ASA......................................................................... 53

EL OBJETO SESSION ........................................................................................................................... 56 Colecciones del objeto Session...................................................................................................... 56 Propiedades del objeto Session ..................................................................................................... 58 Métodos del objeto Session............................................................................................................ 60 Eventos del objeto Session............................................................................................................. 60

EL OBJETO SERVER ............................................................................................................................ 61 Propiedades del objeto Server....................................................................................................... 61 Métodos del objeto Server ............................................................................................................. 62

EL OBJETO OBJECTCONTEXT............................................................................................................. 64 Métodos del objeto ObjectContext................................................................................................. 66

EVENTOS DEL OBJETO OBJECTCONTEXT........................................................................................... 66 EL OBJETO ASPERROR ...................................................................................................................... 67

Propiedades del objeto ASPError ................................................................................................. 67 COMPONENTES DE SERVIDOR ................................................................................................... 69

INTRODUCCIÓN .................................................................................................................................. 69 COMPONENTE ADROTATOR .............................................................................................................. 71 COMPONENTE FUNCIONES DEL NAVEGADOR .................................................................................... 74 COMPONENTE NEXTLINK................................................................................................................... 77 COMPONENTE CONTENT ROTATOR ................................................................................................... 80 COMPONENTE PAGECOUNTER ........................................................................................................... 83 COMPONENTE COUNTERS.................................................................................................................. 86 COMPONENTE MYINFO...................................................................................................................... 87 COMPONENTE TOOLS......................................................................................................................... 88 COMPONENTE PERMISSIONCHECKER ................................................................................................ 91

COMPONENTES DE ACCESO A DATOS. ADO .......................................................................... 93 INTRODUCCIÓN .................................................................................................................................. 93 MODELO DE OBJETOS DE ADO .......................................................................................................... 96 EL OBJETO CONNECTION ................................................................................................................... 97

Abrir una conexión ........................................................................................................................ 98 Ejecutar comandos sobre una conexión ...................................................................................... 102 Cerrar la conexión....................................................................................................................... 104

EL OBJETO COMMAND ..................................................................................................................... 104 Crear un objeto Command .......................................................................................................... 105 La colección Parameters ............................................................................................................. 107 Ejecutar un comando................................................................................................................... 109

EL OBJETO RECORDSET ................................................................................................................... 111 Creación y apertura de un objeto Recordset ............................................................................... 114

CDONTS Y ASP ................................................................................................................................ 119 INTRODUCCIÓN ................................................................................................................................ 119 MODELO DE OBJETOS DE CDONTS................................................................................................. 121 EL OBJETO NEWMAIL....................................................................................................................... 122 EL OBJETO SESSION ......................................................................................................................... 127 EL OBJETO FOLDER.......................................................................................................................... 130 EL OBJETO MESSAGE ....................................................................................................................... 133

EL MODELO COM.......................................................................................................................... 143

Page 7: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

7

INTRODUCCIÓN A LOS COMPONENTES ............................................................................................. 143 CONCEPTOS...................................................................................................................................... 144 ESPECIFICACIÓN COM..................................................................................................................... 144 VENTAJAS DEL USO DE COMPONENTES............................................................................................ 145 LOS INTERFACES .............................................................................................................................. 146 IDENTIFICADORES ÚNICOS GLOBALES (GUIDS)............................................................................. 147 ENLACE TEMPRANO Y TARDÍO......................................................................................................... 148 ESPACIO DE PROCESO DE UN COMPONENTE..................................................................................... 149 EL INTERFAZ IUNKNOWN ................................................................................................................ 150 WINDOWS DNA............................................................................................................................... 150

COMPONENTES EN VISUAL BASIC .......................................................................................... 153 INTRODUCCIÓN ................................................................................................................................ 153 COMPONENTES EN VISUAL BASIC Y VISUAL C++........................................................................... 153 UN PRIMER EJEMPLO DE COMPONENTE............................................................................................ 154

Fases en el diseño del componente.............................................................................................. 154 Creación del proyecto ActiveX DLL............................................................................................ 155 Diseño del interfaz....................................................................................................................... 156 Generación de la DLL y registro del componente....................................................................... 159 Rediseño del componente ............................................................................................................ 161 Reutilización del componente ...................................................................................................... 164

TIPOS DE COMPONENTES.................................................................................................................. 167 MODELOS DE APLICACIONES CLIENTE/SERVIDOR.......................................................... 171

INTRODUCCIÓN ................................................................................................................................ 171 ARQUITECTURA CLIENTE/SERVIDOR EN DOS CAPAS........................................................................ 171 ARQUITECTURA CLIENTE/SERVIDOR EN TRES CAPAS ...................................................................... 172 EJEMPLO DE UNA APLICACIÓN ASP EN TRES CAPAS ....................................................................... 174 COMPONENTIZACIÓN DE LA CAPA INTERMEDIA .............................................................................. 175

Diseño de la capa intermedia con un componente ...................................................................... 175 Rediseño del componente de la capa intermedia......................................................................... 178 Un segundo rediseño del componente de la capa intermedia ..................................................... 178

ARQUITECTURA CLIENTE/SERVIDOR EN N CAPAS............................................................................ 180 DISEÑO DE COMPONENTES PARA ASP................................................................................... 181

INTRODUCCIÓN ................................................................................................................................ 181 TIPOS VARIANT................................................................................................................................ 181 ACCESO AL MODELO DE OBJETOS DE ASP DESDE UN COMPONENTE .............................................. 185

Acceso al objeto Application ....................................................................................................... 185 Acceso a los objetos Request y Response .................................................................................... 187 Recompilación de componentes con enlace temprano ................................................................ 192

IMPLEMENTACIÓN DE INTERFACES EN VISUAL BASIC .................................................................... 193 SERVICIOS DE COMPONENTES ................................................................................................ 197

INTRODUCCIÓN ................................................................................................................................ 197 CARACTERÍSTICAS DEL MTS (MICROSOFT TRANSACTION SERVER).............................................. 197 SERVICIOS QUE APORTA EL MTS..................................................................................................... 198

Transacciones para componentes................................................................................................ 199 Comercio de objetos .................................................................................................................... 199 Independencia entre procesos ..................................................................................................... 199 Fondo común de recursos............................................................................................................ 199 Activación en el momento (Just-In-Time).................................................................................... 199 Seguridad..................................................................................................................................... 200

CONCEPTOS PRINCIPALES DEL MTS................................................................................................ 200 La intercepción ............................................................................................................................ 200

Page 8: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

8

Propiedades declarativas. El catálogo del MTS.......................................................................... 200 FUNCIONAMIENTO DEL MTS ........................................................................................................... 201

El objeto Context Wrapper .......................................................................................................... 201 El objeto de contexto ................................................................................................................... 201 El interfaz ObjectContext ............................................................................................................ 202 El interfaz ObjectControl ............................................................................................................ 203

INSTANCIAR UN OBJETO A PARTIR DE UN COMPONENTE MTS ........................................................ 204 Instanciar un objeto desde otro objeto de Visual Basic .............................................................. 204 Instanciar un objeto desde una página ASP con VBScript.......................................................... 204

INTRODUCCIÓN A LAS TRANSACCIONES .......................................................................................... 205 Duración y resultado de una transacción.................................................................................... 206

ACTIVACIÓN EN EL MOMENTO......................................................................................................... 206 ALMACENAR EL ESTADO DEL OBJETO ............................................................................................. 208 ADMINISTRADOR DE PROPIEDADES COMPARTIDAS (SPM)............................................................. 208

Obtener una referencia al SPM................................................................................................... 209 Crear un grupo de propiedades compartidas.............................................................................. 210 Crear una propiedad compartida................................................................................................ 212

SERVICIOS DE COMPONENTES Y COM+.......................................................................................... 213 La intercepción en COM+........................................................................................................... 215

DISEÑO DE COMPONENTES COM+ .......................................................................................... 219 EL INTERFAZ OBJECTCONTROL ....................................................................................................... 219 ACTIVACIÓN JUST-IN-TIME (JIT) .................................................................................................... 227 INICIALIZACIÓN DEL COMPONENTE ................................................................................................. 229 ESTADO DE UN COMPONENTE .......................................................................................................... 232 CADENA DEL CONSTRUCTOR ........................................................................................................... 238

COMPONENTES TRANSACCIONALES..................................................................................... 241 INTRODUCCIÓN ................................................................................................................................ 241 EL CONTEXTO Y LAS TRANSACCIONES ............................................................................................ 242 PAUTAS PARA EL DESARROLLO DE COMPONENTES TRANSACCIONALES ......................................... 242 CASOS PRÁCTICOS ........................................................................................................................... 243

La página contiene todo el código transaccional........................................................................ 243 PARTE DEL CÓDIGO TRANSACCIONAL EN UN COMPONENTE............................................................ 245 VOTO TRANSACCIONAL DE UN COMPONENTE ................................................................................. 249 DOS COMPONENTES TRANSACCIONALES INVOCADOS DESDE ASP.................................................. 251 UN COMPONENTE TRANSACCIONAL INVOCA A OTRO ...................................................................... 253

ACCESO A MSMQ DESDE ASP .................................................................................................... 257 SERVICIOS DE MENSAJERÍA ENTRE APLICACIONES.......................................................................... 257 MSMQ (MESSAGE QUEUING SERVER)............................................................................................ 258 FUNCIONAMIENTO DEL MSMQ ....................................................................................................... 259

Creación de una cola................................................................................................................... 260 Modelo de objetos de MSMQ....................................................................................................... 261 Envío de mensajes........................................................................................................................ 262 Prioridad de los mensajes ........................................................................................................... 265 Recepción de mensajes ................................................................................................................ 266 Colas de diario ............................................................................................................................ 269

ENVÍO DE UN COMPONENTE COM+................................................................................................. 271 ACCESO A ADSI DESDE ASP ....................................................................................................... 277

DIRECTORIOS Y SERVICIOS DE DIRECTORIO.................................................................................... 277 ACTIVE DIRECTORY DE MICROSOFT ............................................................................................... 278 ADSI (ACTIVE DIRECTORY SERVICES INTERFACE) ........................................................................ 279 ESTRUCTURA DE ACTIVE DIRECTORY............................................................................................. 280

Page 9: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

9

PROVEEDOR ADSI PARA WINNT .................................................................................................... 281 CONTENEDORES............................................................................................................................... 283 PROPIEDADES DE LOS OBJETOS DEL DIRECTORIO ............................................................................ 285 PROPIEDADES CON VALORES MÚLTIPLES ........................................................................................ 287 MODIFICACIÓN DE PROPIEDADES .................................................................................................... 288

Page 10: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 11: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Introducción a ASP

Antecedentes de ASP: La especificación CGI ASP no es una idea realmente nueva, encontramos un antecedente muy importante y muy utilizado en Internet denominado comúnmente scritps CGI.

Las siglas CGI se corresponden en inglés a Common Gateway Interface, es decir, interfaz de pasarela común. Vamos a ir viendo paso a paso que significan cada unas de estas palabras, que realmente son las que definen el concepto de CGI.

La especificación Common Gateway Interface permite a los servidores Web ejecutar y comunicarse con otros programas, llamados programas CGI, e incorporar la salida de los mismos a los gráficos, texto o audio enviados a un navegador Web.

La programación en CGI implica diseñar programas que se ejecutarán en el entorno de Internet, y más concretamente en el entorno World Wide Web.

El programa CGI se ejecutará dentro del entorno ofrecido por el servidor Web que lo contiene. El servidor Web creará una información especial para el CGI cuando pasa a ejecutarlo, y el servidor esperará una respuesta del programa CGI como resultado de su ejecución. Es esta comunicación o interacción entre el servidor Web y el programa CGI es lo que define realmente la especificación CGI.

Los programas CGI también se suelen denominar scripts CGI, esto es debido a que los primeros programas CGI fueron escritos utilizando scripts de la shell de UNIX y Perl.

Antes de que el programa CGI se ejecute, el servidor Web que lo contiene se encargará de crear un entorno con el que podrá interactuar el programa CGI. Este entorno comprende la traducción de

Page 12: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

12

cabeceras de peticiones del protocolo HTTP (HyperText Transfer Protocol) en variables de entorno a las que podrá acceder nuestro programa CGI. Estas variables de entorno contendrán una información muy variada acerca del cliente que ha realizado la petición o del propio servidor Web en el que se ejecuta el programa CGI.

Una vez que el servidor ha iniciado la ejecución del programa CGI esperará un resultado de la ejecución del mismo. Este resultado suele ser una serie de encabezados de respuesta del protocolo HTTP y código HTML. Estos encabezados y código HTML serán recogidos por el servidor Web y enviados al cliente que realizó la petición, es decir, al navegador o cliente Web.

Después de ver esta pequeña introducción podemos definir un programa CGI como un programa que se encuentra en un servidor Web y que recibe peticiones desde un cliente Web través del servidor Web. Y gracias al entorno que le ofrece el servidor Web el programa CGI puede obtener información sobre la petición realizada, además de otra información útil, que le permitirá procesar la petición. La respuesta a esta petición será generada por el programa CGI en forma de cabeceras de respuesta del protocolo HTTP y etiquetas del lenguaje HTML (HyperText Markup Language), que serán enviadas por el servidor Web al navegador Web que realizó la petición.

CGI no es un lenguaje de programación sino que es una especificación. La especificación CGI va a realizar la función de interfaz o pasarela entre el servidor Web y los programas CGI, haciendo uso del protocolo HTTP y el lenguaje de hipertexto HTML.

Un programa CGI será aquel que cumpla la especificación CGI, es decir, interactuará con el servidor atendiendo a unos principios establecidos por la especificación CGI.

CGI ya lleva siendo utilizado muchos años en la red y todavía se sigue utilizando en muchos sitios Web a la hora de acceder a datos o construir páginas dinámicas, pero cada vez más los sitios Web van adoptando la utilización de Active Server Pages.

Active Server Pages (ASP) es el nombre que reciben las páginas activas de servidor, es decir, las páginas que se ejecutan en el servidor. ASP se basa en la especificación CGI, podemos considerar que ASP es una evolución de la especificación CGI.

Definición de ASP La filosofía de ASP resulta muy sencilla, en pocas palabras se puede definir de la siguiente forma: las páginas ASP, también llamadas páginas activas, son páginas que contienen código HTML, script de cliente y un script que se ejecuta en el servidor, dando como resultado código HTML. Por lo tanto al cargar una página ASP en nuestro navegador, en realidad no estamos cargando la página ASP como tal, sino el resultado de la ejecución de la página ASP, es decir la salida de la página ASP, y como se ha apuntado anteriormente se trata de código HTML. Es decir, son páginas que se ejecutan en el servidor enviando como resultado al cliente código HTML.

Antes de seguir vamos a definir de forma sencilla lo que se considera un lenguaje de script o de secuencia de comandos. Un lenguaje de script es un subconjunto de otro lenguaje más general y que se utiliza para un entorno muy determinado, en este caso el entorno es la Web.

Una página ASP podrá contener los siguientes elementos: texto, componentes ActiveX, código HTML y comandos de script. Este script puede ser de dos tipos: script de cliente o script de servidor. El script de servidor es la nueva idea que introduce ASP, se debe tener en cuenta que en el script de servidor se tiene acceso a diferentes objetos y no está orientado a eventos.

Page 13: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

13

El script de servidor utilizado en ASP utiliza la misma sintaxis que el script de cliente, la diferencia está en que con ASP el script de servidor es compilado y procesado por el servidor Web antes de que la página sea enviada al navegador.

ASP no es un lenguaje de script, ASP ofrece un entorno para procesar scripts que se incorporan dentro de páginas HTML, es decir, un entorno de procesamiento de scripts de servidor.

La propia Microsoft define ASP de la siguiente manera: "...es un entorno de secuencias de comandos en el lado del servidor que puede utilizar para crear y ejecutar aplicaciones de servidor Web dinámicas, interactivas y de alto rendimiento...".

Realmente, ASP es un componente (asp.dll) que se instala en un servidor Web y cuya misión es la de procesar ficheros que terminan con la extensión .asp y transmitir el resultado al cliente que solicitó la página ASP.

El script de servidor incluido en una página ASP empieza a ejecutarse cuando un navegador solicita el archivo .asp al servidor Web. El servidor Web llama entonces a ASP, el cual lee el archivo solicitado de arriba a abajo, ejecuta los comandos y envía una página HTML al explorador. ASP incluye un motor de interpretación de scripts del lado del servidor.

Las páginas ASP son ficheros con la extensión asp. Crear un fichero .asp resulta muy sencillo, se puede crear a partir de una página HTML existente, simplemente renombrando el fichero .html o .htm a un fichero .asp. Para hacer esta página ASP disponible para los usuarios de la Web, el fichero .asp se debe almacenar en un directorio de publicación en Internet, se debe tener en cuenta que el directorio virtual asociado debe tener permisos de ejecución de secuencias de comandos.

La última versión de la tecnología ASP es la versión 3.0. Esta versión es muy similar a su predecesora, y todas las nuevas características que presenta se deben a que se utiliza una nueva versión del servidor Web (Internet Information Services 5.0), recordemos que las páginas ASP son procesadas por el servidor.

En el tema siguiente se ofrece una comparativa de ASP 2.0 con ASP 3.0 comentando brevemente todas sus novedades, se recomienda la lectura del segundo capítulo sobretodo a los alumnos que ya conozcan ASP 2.0.

Aplicaciones ASP Una aplicación basada en ASP consta de un directorio virtual en un servidor Web y de todos los subdirectorios y archivos contenidos en él. Una aplicación puede ser una página principal sencilla, o bien puede estar formada por un conjunto completo de páginas interrelacionadas entre sí.

Al usar aplicaciones en ASP es posible mantener un estado, es decir, se tiene la capacidad de mantener información. Dentro de una aplicación ASP se pueden mantener dos tipos de estado:

• Estado de la aplicación, en la que toda la información relativa a una aplicación está disponible para todos los usuarios de la misma.

• Estado de sesión, en la que la información sólo está disponible para un usuario o sesión específicos. Una sesión por lo tanto, pertenece a un solo usuario.

Un ejemplo práctico de una aplicación ASP puede ser este mismo sitio Web. Almagesto está completamente realizado con páginas ASP constituyendo por lo tanto una aplicación ASP, este sitio

Page 14: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

14

Web demuestra los diferentes usos que puede tener la tecnología ASP y las necesidades que puede cubrir.

Las aplicaciones ASP no son aplicaciones al uso, ya que en realidad no se dispone de un ejecutable sino de un conjunto de páginas, imágenes y recursos, por lo tanto se trata de aplicaciones muy particulares que requieren para su ejecución de un servidor Web que soporte las páginas ASP.

Aportaciones de ASP En este apartado se comentan las aportaciones que ofrece ASP desde su primera versión, es decir, se trata de aportaciones muy genéricas de la tecnología ASP.

Para entender las aportaciones que ofrecen las páginas ASP se deben tener en cuenta una serie de características del protocolo HTTP (HyperText Transfer Protocol). Se dice que le protocolo HTTP es un protocolo sin estado, es decir, no se puede mantener un estado entre diferentes peticiones. El protocolo HTTP se basa en el paradigma cliente/servidor o petición/respuesta.

Se deben tener en cuenta un par de puntos a la hora de establecer la comunicación entre clientes (navegadores Web) y servidores (servidores Web) del protocolo HTTP:

• Después de realizar una petición el cliente se desconecta del servidor y espera una respuesta. El servidor debe restablecer la conexión después de que haya procesado la petición.

• El servidor y el cliente sólo se tienen en cuenta durante la conexión, después, se olvidan el uno del otro. Por esta razón, ni el cliente ni el servidor pueden retener información entre diferentes peticiones o a través de diferentes páginas Web. Sin embargo, ASP permite al servidor almacenar información, o mantener el estado, entre las diferentes peticiones del cliente.

El cliente y el servidor Web se comunican utilizando cabeceras HTTP, estas cabeceras son colecciones de datos que intercambian el cliente y el servidor para asegurar que la transacción es coherente y completa. Como petición del usuario se envía una cabecera y el servidor interpreta esta cabecera y envía una respuesta HTTP cuyo cuerpo sería el contenido del recurso demandado por el cliente.

ASP permite al desarrollador intervenir en todo el proceso de comunicación del protocolo HTTP. Los objetos integrados dentro de ASP Request y Response interactúan con las peticiones y respuestas del protocolo HTTP, respectivamente.

Dentro de los objetos integrados de ASP podemos encontrar la forma de acceder al servidor, obtener información del mismo, así como del usuario. Y también se permite, como se había comentado anteriormente, mantener el estado entre diferentes peticiones del cliente.

Se puede considerar ASP como una nueva (aunque ya no tan nueva) aproximación a la creación de páginas web complejas que pueden acceder a bases de datos o a otros objetos del servidor. Ofrece lo siguiente:

• Independencia del navegador, ASP puede ejecutar complejas operaciones en el servidor y enviar solamente los resultados al cliente.

• Construcción de páginas basadas en bases de datos que permiten realizar operaciones sobre las bases de datos del servidor de forma bastante sencilla.

• Es una de las soluciones más versátiles para el desarrollo de aplicaciones en el entorno de Internet/Intranet.

Page 15: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

15

• Desarrollo de complejas aplicaciones Web.

• Facilidad de uso de componentes de terceras partes ejecutándose en el servidor, es decir, se pueden utilizar componentes para liberarnos de realizar tareas complejas. Estos componentes se deben registrar en el servidor y podrán ser utilizados desde el script correspondiente. Estos componentes se denominan componentes ActiveX de servidor.

• Posibilidad de definir páginas ASP transaccionales para realizar todas las operaciones contenidas en la misma dentro de una transacción.

• Una tecnología en constante evolución y mejora.

A lo largo del curso se profundizará más en todos estos puntos, aquí se han comentado simplemente los más evidentes y también para poseer una visión general de lo que supone la tecnología ASP.

Sintaxis de ASP Como se ha comentado anteriormente ASP no es un lenguaje de script, sino que ofrece un entorno para la ejecución de estos lenguajes que se encuentran dentro de páginas ASP. ASP posee una sintaxis para poder distinguir cada uno de los elementos que nos podemos encontrar dentro de una página ASP.

Encerrado dentro de los delimitadores <%%> se va a encontrar todo el código de script de servidor, de esta forma el comando <%nombre="Pepe"%> asigna el valor Pepe a la variable nombre; y dentro de los delimitadores <%=%> se encuentran expresiones de salida, así por ejemplo la expresión <%=nombre%> enviará al navegador el valor Pepe, es decir, el valor actual de la variable, más adelante se verá una equivalencia de estos delimitadores con un método de un objeto integrado de ASP.

Entre los delimitadores <%%> se puede y debe incluir varias sentencias en distintas líneas de código del lenguaje de secuencias de comandos, sin embargo los delimitadores <%=%> sólo podemos encerrar una sentencia por línea.

Entre los delimitadores de ASP se puede incluir cualquier tipo de expresión válida en el lenguaje de script principal. Por ejemplo el Código fuente 1 genera un texto que contiene la hora actual del servidor.

Esta página se actualizó a las <%=Now%>

Código fuente 1

En este caso el servidor Web devuelve al navegador el valor de la función Now de VBScript junto con el texto. Dentro de los delimitadores de script de servidor se pueden encontrar también instrucciones del lenguaje de script correspondiente, así por ejemplo puede aparecer una instrucción If...Then...Else del lenguaje VBScript como se puede apreciar en el Código fuente 2.

<%If nombre="" Then

variable="Nombre desconocido"

Page 16: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

16

Elsevariable="Hola amigo "&nombre

End If%><FONT COLOR="GREEN"><%=variable%></FONT>

Código fuente 2

En el código anterior se comprueba si la variable nombre tiene algún valor, si lo tiene saludamos con el valor de la variable, mostrando el saludo en color verde.

También se puede incluir código HTML entre las instrucciones del script. Por ejemplo la secuencia de comandos del Código fuente 3 mezcla HTML con una instrucción condicional y produce el mismo resultado que la secuencia anterior.

<FONT COLOR="GREEN"><% If nombre="" Then%>

Nombre desconocido<%Else%>

Hola amigo <%=nombre%><%End If%></FONT>

Código fuente 3

Para poder realizar una lectura más sencilla del código ASP se recomienda utilizar los delimitadores de script de servidor encerrando varias líneas de código en lugar de un par de delimitadores por cada línea. Así, en lugar de escribir lo que se muestra en el Código fuente 4, se debería escribir lo que se muestra en el Código fuente 5.

<%strNombre=Session("nombre")%><%strApellidos=Session("apellidos")%><%strEdad=Session("edad")%>

Código fuente 4

<%strNombre=Session("nombre")strApellidos=Session("apellidos")strEdad=Session("edad")

%>

Código fuente 5

Page 17: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

17

Objetos integrados en ASP 3.0 ASP en su versión 3.0 contiene siete objetos integrados que liberan al programador de la realización de tareas complejas. Estos seis objetos no requieren que sean instanciados siempre se encuentran disponibles en nuestras páginas ASP.

Estos objetos son los siguientes: Application, Session, Request, Response, Server, ASPError y ObjectContext.

Cada uno de estos objetos posee una serie de métodos y propiedades para poder ser utilizados por el script de servidor, además cada objeto posee una función determinada, básicamente estas funciones son las siguientes:

• Request: obtención de información del cliente.

• Response: envío de información al cliente.

• Server: acceso a los recursos del servidor, como puede ser la creación de componentes .

• Session: almacena información sobre la sesión de un usuario.

• Application: almacena información común para todos los usuarios de la aplicación ASP.

• ObjectContext: gestión de transacciones en páginas ASP.

• ASPError: contiene información detallada acerca del último error que se ha producido.

Cada uno de estos objetos se explicarán con una mayor profundidad más adelante.

La sintaxis utilizada para poder acceder a los métodos y propiedades de los objetos depende del lenguaje de script que estemos utilizando. Debido que el lenguaje de script por defecto de ASP es VBScript (subconjunto de Visual Basic) en este curso nos vamos a centrar en este script.

Los objetos Request y Response contienen colecciones. Una colección es un conjunto de elementos de información relacionados y que se accede a ellos de una misma forma.

Se puede acceder a cada elemento de una colección mediante el bucle For...Each. La utilización de colecciones se verá en detenimiento en los capítulos dedicados a estos dos objetos integrados.

Un método es un procedimiento que actúa sobre un objeto, la sintaxis para poder invocar un método de un objeto es la del Código fuente 6.

Objeto.metodo parametros

Código fuente 6

Donde el tipo de parametros dependerá del método invocado.

Una propiedad es un atributo de un objeto. Las propiedades son características de un objeto que describen su estado, así por ejemplo un objeto podría tener las características tamaño, nombre, color, etc. Para obtener el valor de una propiedad utilizamos la sintaxis del Código fuente 7.

Page 18: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

18

Objeto.propiedad

Código fuente 7

Y para asignarle un valor a una propiedad de un objeto debemos utilizar la sintaxis del Código fuente 8.

Objeto.propiedad=valor

Código fuente 8

Donde valor depende de la propiedad del objeto.

Componentes de servidor ASP incluye una serie de componentes ActiveX de servidor (o componentes de servidor), llamados componentes ActiveX Server, anteriormente conocidos como servidores de Automatización. Estos componentes están diseñados para ejecutarse en un servidor Web y contienen una serie de funciones bastante útiles para que el programador no tenga que construirlas, una de estas funciones puede ser el acceso a bases de datos. Estos componentes los invocaremos desde nuestras páginas ASP.

No se deben confundir los componentes de servidor con los objetos integrados en ASP.

Para poder tener acceso a alguno de los componentes ActiveX de servidor primero se deberá crear una instancia del componente correspondiente. Una vez creada la instancia, se pueden usar los métodos asociados al componente o establecer y leer sus propiedades.

Los componentes ActiveX Server que incluye ASP en su versión 3.0 son los siguientes:

• Componente de acceso a bases de datos, ADO (ActiveX Data Objects). A través de la utilización de este componente se puede ofrecer acceso a bases de datos desde una página ASP, así por ejemplo, se puede mostrar el contenido de una tabla, permitir que los usuarios realicen consultas y otras operaciones sobre una base de datos.

• Componente Ad Rotator. Este componente permite mostrar una serie de imágenes alternativas con un vínculo a otra dirección desde la imagen presentada. Este componente se suele utilizar para mostrar diferentes anuncios de forma alternativa dentro de una página ASP.

• Componente Funciones del explorador. A través de este componentes podemos recuperar datos acerca del tipo de navegador del cliente y que capacidades o funciones tiene.

• Componente vínculo de contenidos. Facilita el desplazamiento lógico entre las diferentes páginas ASP de una aplicación ASP.

• Componente Content Rotator (rotador de contenidos). Este componente permite hacer rotaciones de cadenas de contenido HTML en una página.

Page 19: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

19

• Componente Page Counter (contador de páginas). Permite llevar una cuenta del número de veces que se ha accedido a una página determinada dentro de nuestro sitio Web.

• Componente Counters. A través de este componente podremos almacenar, crear, incrementar y consultar cualquier contador.

• Componente MyInfo. Nos permite almacenar información personal que será ofrecida por el administrador del sitio Web.

• Componente Tools. Es el denominado componente de utilidades. Ofrece una serie de funciones diversas, como la generación de números aleatorios o la comprobación de la existencia de un fichero en el servidor.

• Componente Permission Checker. A través de este componente podremos determinar si a un usuario se le ha dado permisos para acceder a un fichero determinado.

• Componente Status. Este componente, de momento, únicamente está disponible para el servidor Personal Web Server en plataformas Macintosh. Resulta extraño pero es así. Nos ofrece una información variada acerca del estado del servidor Web.

• Componente de registro de IIS. Mediante este componente tenemos acceso a la información y manipulación de los ficheros de registro (log) generados por el servidor Web IIS 5.0.

Además de todos estos componentes, el programador puede crear sus propios componentes ActiveX Server. Estos componentes se pueden desarrollar en lenguajes de programación como Visual Basic, Java o C++, una vez creado el componente se transforma a una DLL que se registrará en el servidor.

Todos los componentes de servidor que no es encuentran incluidos en ASP deben ser registrados. Una vez registrado el componente en el servidor Web lo podemos instanciar desde el lenguaje de secuencias de comandos de una página ASP, al igual que hacíamos con los componentes que vienen por defecto con ASP.

También se puede adquirir estos componentes a terceros, existen empresas que se dedican al diseño de componentes para que sean utilizados desde páginas ASP.

Novedades de ASP 3.0 Aquí se pretende mostrar de forma muy general las mejoras y novedades que aporta ASP 3.0 sobre la versión anterior de las páginas activas ASP 2.0, no se va a entrar en detalles y se supone que el lector tiene ya algún conocimiento de ASP 2.0.

A continuación vamos a ir comentando en cada apartado cada uno de los cambios y mejoras que aporta ASP 3.0, para ello se apoya en Internet Information Server 5.0.

Mejoras generales en ASP 3.0 En este epígrafe se va a reunir una serie de cambios y novedades que ofrece ASP 3.0, que son de carácter general y que afectan al rendimiento y funcionamiento de las aplicaciones ASP.

En esta nueva versión de ASP se ofrece un mejor funcionamiento y escalabilidad de la tecnología ASP, basándose en las nuevas características y mejoras de Internet Information Server 5.0.

Page 20: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

20

• Se ha producido una mejora en el procesamiento de las páginas ASP por parte de la librería ASP.DLL.

• Se ofrece lo que se denomina ajuste automático, que consiste en detectar cuándo una petición está bloqueada por recursos externos, en ese caso se proporcionan automáticamente más subprocesos para ejecutar peticiones adicionales y continuar de esta forma con el procesamiento normal de forma simultánea.

• Los objetos COM se liberan más rápidamente y por defecto los componentes COM se ejecutan out-of-process, es decir, en un espacio de memoria distinto al del servidor Web.

• Con ASP 3.0 se ofrecen los objetos COM que se ofrecían con ASP 2.0 (componentes de servidor, como Content Rotator) pero con su rendimiento mejorado, es decir, aparecen versiones mejoradas de los componentes anteriores.

• El servidor transaccional Microsoft Transaction Server (MTS) ya no existe como una entidad separada en Windows 2000, y pasa a formar parte de Servicios de componentes (Microsoft Component Services). IIS 5.0 y Servicios de componentes funcionan conjuntamente para formar la arquitectura básica para la creación de aplicaciones Web.

El objeto Response Los únicos objetos integrados dentro de ASP que han sufrido alguna modificación han sido el objeto Response, que vemos en este apartado, y el objeto Server.

Por defecto la propiedad Buffer del objeto Response tiene el valor True (verdadero), en ASP 2.0 y 1.0 esta propiedad del objeto Response tenía por defecto el valor de False (falso). Debido a esto, en ASP 3.0 el resultado de la ejecución de una página ASP únicamente es enviado al cliente cuando se termina de procesar la página ASP correspondiente, o bien cuando se utilizan los métodos Flush o End del objeto Response.

Por lo tanto, a no ser que se indique otra cosa, de forma predeterminada el resultado de la ejecución de la página ASP se enviará al búfer. Según afirma Microsoft la técnica del búfer ofrece una entrega de páginas más eficiente al cliente.

En el objeto Response también cambia la forma de utilizar la propiedad IsClientConnected, mediante esta propiedad podemos consultar si un cliente se encuentra todavía conectado a nuestro servidor o por el contrario si ha finalizado su sesión con el mismo. En ASP 2.0 podíamos consultar esta propiedad sólo si antes habíamos enviado ya alguna salida o contenido al cliente, ahora con ASP 3.0 podemos utilizar IsClientConnected antes de enviar cualquier contenido al navegador.

El objeto Server Este es otro de los objetos de ASP que ha experimentado cambios. Presenta dos nuevos métodos: Transfer y Execute, que permiten controlar el control de flujo del programa, ampliando las capacidades de control de flujo de las páginas ASP, anteriormente sólo se disponía del método Redirect del objeto Response.

En ASP 2.0 si queríamos transferir la ejecución a otra página ASP teníamos que utilizar el método Redirect del objeto Response, pero esto suponía enviar una respuesta al cliente para indicarle la carga de una nueva página, que es la página a la que pasamos la ejecución.

Page 21: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

21

La utilización del método Redirect es bastante costosa y problemática ya supone un envío de información más del servidor al cliente para indicarle mediante una cabecera HTTP de redirección que la página ha cambiado de localización, siendo la nueva localización la página que deseamos cargar. Esto es problemático ya que en algunos navegadores como Netscape Communicator aparace un mensaje del tipo El objeto requerido se ha movido y se puede encontrar aquí, esto también ocurre cuando la conexión la realiza el cliente a través de proxy.

Pero ahora con ASP 3.0 podemos evitar esta redirección, que como hemos visto, tiene lugar en el cliente, mediante los métodos Execute y Transfer del objeto Server que permiten que la redirección tenga lugar en el servidor, quedando el cliente completamente ajeno. Ambos métodos reciben como parámetro la ruta de la página a la que queremos redirigir al cliente.

La utilización del método Execute es muy similar a realizar una llamada a un procedimiento o función. Cuando lanzamos el método Execute se empieza a ejecutar la página que indicamos por parámetro, y cuando termina la ejecución de esta nueva página, el control pasa a la siguiente sentencia después de la llamada al método Execute en la página inicial, siguiendo a partir de aquí con la ejecución de la página, es decir, el navegador del cliente recibe una salida formada por la combinación de la ejecución de ambas páginas.

El método Transfer se comporta de distinto modo, al lanzar este método se pasa la ejecución a la nueva página, pero una vez que finaliza la ejecución de la misma no se vuelve a la página inicial, como ocurría con el método Execute.

En ambos métodos se mantiene el contexto de la página inicial, es decir, en la nueva página tenemos acceso a las variables, objetos y a todos los objetos intrínsecos de ASP (Request, Session, Response...) de la página inicial o página de origen. También se mantienen las transacciones entre distintas páginas, siempre que proceda, atendiendo a la directiva @TRANSACTION.

De esta forma como la redirección entre páginas se produce en el servidor, el navegador cree que sigue recibiendo todavía la página original que habia demandado, incluso en la barra de direcciones del navegador sigue apareciendo la misma URL y los botones Atrás y Adelante funcionan correctamente.

Vamos a ofrecer un sencillo código de una página ASP que utiliza los métodos Transfer y Execute para ejecutar otra página, y así se puede ver más claramente la utilización de estos dos nuevos métodos del objeto Server.

Nuestra página, llamada PaginaInicial.asp, va a constar de un formulario con dos botones, y según el botón que se pulse se lanzará el método Execute o Transfer para ejecutar la página OtraPagina.asp. El código de de la página PaginaInicial.asp se muestra en el Código fuente 9, y el de OtraPagina.asp en el Código fuente 10.

<%If Request.Form("Execute")<>"" ThenResponse.Write "Se está ejecutando la página "_

& Request.ServerVariables("SCRIPT_NAME") & "<br>"Server.Execute "OtraPagina.asp"Response.Write "Se está ejecutando de nuevo la página "_

& Request.ServerVariables("SCRIPT_NAME") & "<br>"ElseIf Request.Form("Transfer")<>"" Then

Response.Write "Se está ejecutando la página "_& Request.ServerVariables("SCRIPT_NAME") & "<br>"

Server.Transfer "OtraPagina.asp"Response.Write "Se está ejecutando de nuevo la página "_

& Request.ServerVariables("SCRIPT_NAME") & "<br>"End if%><FORM ACTION="PaginaInicial.asp" METHOD="POST">

<input type="submit" name="Execute" value="Lanza Server.Execute"><br>

Page 22: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

22

<input type="submit" name="Transfer" value="Lanza Server.Transfer"></FORM>

Código fuente 9

<hr>

Se está ejecutando la página OtraPagina.asp<br>Esta página se ha cargado con el método

<%If Request.Form("Execute")<>"" Then%><b>EXECUTE</b>

<%ElseIf Request.Form("Transfer")<>"" Then%><b>TRANSFER</b>

<%End If%><br>La variable Request.ServerVariables("SCRIPT_NAME") sigue teniendo el valor:<%=Request.ServerVariables("SCRIPT_NAME")%><br>

Termina la ejecución de OtraPagina.asp<br>

<hr>

Código fuente 10

Si ejecutamos la página PAGINAINICIAL.ASP y pulsamos cada uno de sus botones, vemos el distinto comportamiento de los método Execute y Transfer, en el primer caso se intercala el resultado ejecución de ambas páginas, y en el segundo paso una vez que se ha terminado de ejecutar la segunda página finaliza también la ejecución de la secuencia de comandos, sin retornar a la página inicial.

Las siguientes figuras muestran estas dos situaciones.

La Figura 1 muestra la página PAGINAINICIO.ASP cuando todavía no se ha pulsado ningún botón. En la Figura 2 se muestra cuando se ha pulsado el botón Execute. Y en la Figura 3 cuando se ha pulsado el botón Transfer.

Figura 1

Page 23: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

23

Figura 2

Figura 3

Otro nuevo método que ofrece el objeto Server, y que está relacionado con el tratamiento de errores, es el método GetLastError. Mediante el uso del método GetLastError podemos tener acceso a toda la información referente al último error que se ha producido en la página ASP actual. Pero es necesario aclarar que su utilización no es similar al tratamiento de errores que realizábamos con la sentencia On Error Resume Next y el objeto Err de VBScritp, que preguntábamos por la propiedad Number del objeto Err para averiguar si se había producido algún error, el método GetLastError se puede utilizar

Page 24: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

24

únicamente dentro de una página de error personalizada, es decir, cuando el error ya se ha producido y lo ha detectado el servidor Web.

Mediante Internet Information Services 5 podemos indicar las páginas de error personalizadas y es en estas páginas dónde podemos hacer uso de este método.

El método GetLastError devuelve un nuevo objeto de ASP llamado ASPError, son las propiedades de este nuevo objeto las que nos permiten acceder de forma detallada a toda la información referente al error que se ha producido. Este nuevo objeto lo trataremos con más detalle en el siguiente apartado.

El objeto ASPError Como ya hemos visto en el apartado anterior, este es un nuevo objeto del modelo de objetos incluido dentro de ASP 3.0. Tendremos acceso al objeto ASPError a través de la llamada al método GetLastError del objeto Server. La función de este objeto es la de ofrecer de forma detallada toda la información disponible del último error que se ha producido.

El objeto ASPError únicamente dispone de una serie de propiedades de sólo lectura, que contienen la información relativa al último error que se ha producido. Estas propiedades se comentan de forma breve en la Tabla 1.

Propiedad Descripción

ASPCode Un entero generado por IIS.

ASPDescription Una cadena que es una descripción detallada del error si está relacionado con ASP.

Category Cadena que indica si se trata de una error interno de ASP, del lenguaje de secuencia de comandos o de un objeto.

Column Entero que indica la posición de la columna del archivo ASP que generó el error.

Description Breve descripción del error.

File Nombre del archivo ASP que se estaba procesando cuando se produjo el error.

Line Línea del archivo ASP que generó el error.

Number Código de error estándar de COM.

Source Devuelve el código fuente real, si está disponible, de la línea que causó el error.

Tabla 1

Page 25: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

25

En el Código fuente 11 se muestra un sencillo código de ejemplo que hace uso del objeto ASPError, y que podría pertenecer a una página de error personalizada de IIS 5.0. Primero se obtiene una referencia al objeto ASPError mediante el método GetLastError del objeto Server, y a continuación se muestra los valores de las propiedades del objeto ASPError para informar al cliente acerca del error que se ha producido.

<%@ language="VBScript" %><html><body><head><title>The page cannot be displayed</title></head><%Set objASPError=Server.GetLastError%><b>Detalles del error que se ha producido</b><br>Código de error ASP: <i><b><%=objASPError.ASPCode%></b></i><br>Número de error: <i><b><%=objASPError.Number%></b></i><br>Código fuente que lo ha producido:

<i><b><%=Server.HTMLEncode(objASPError.Source)%></b></i><br>Categoría del error: <i><b><%=objASPError.Category%></b></i><br>Fichero en el que se producido el error: <i><b><%=objASPError.File%></b></i><br>Línea y columna en la que se ha producido el error:

<i><b><%=objASPError.Line%>, <%=objASPError.Column%></b></i><br>Descripción del error: <i><b><%=objASPError.Description%></b></i><br></body></html>

Código fuente 11

Un ejemplo de la ejecución del código anterior se puede ver en la Figura 4, y se produce cuando hay un error de ASP, es decir un error interno de servidor del tipo 500;100.

Figura 4

Page 26: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

26

Componente de registro de IIS (Logging Utility) Otras de las novedades de ASP 3.0, abandonado ya los objetos integrados en ASP, es que ofrece un nuevo componente de servidor (componente ActiveX de servidor). El nuevo componente de servidor es denominado componente de registro o programa de registro de IIS. Mediante este componente tenemos acceso a la información y manipulación de los ficheros de registro (log) generados por el servidor Web IIS 5.0.

Este componente, al igual que todos los existentes en ASP 2.0, se instala conjuntamente con el servidor Web Internet Information Server 5.0. El fichero DLL que contiene a este nuevo componente es LOGSCRPT.DLL.

Para instanciar un componente de registro debemos utilizar la sentencia que muestra el Código fuente 12.

Set objRegistro=Server.CreateObject("MSWC.IISLog")

Código fuente 12

Es importante señalar que el usuario que tiene acceso a la secuencia de comandos ASP que crea la instancia del componente de registro debe autenticarse como Administrador u Operador en el servidor donde se ejecuta IIS, si es un usuario anónimo, el componente de registro de IIS no funcionará correctamente.

Para manipular los ficheros de registro de IIS el componente IISLog ofrece una serie de métodos que se muestran en la Tabla 2.

Método Descripción

AtEndOfLog Indica si se leyeron o no todos los registros del archivo.

CloseLogFiles Cierra todos los archivos de registro abiertos.

OpenLogFile Abre un archivo de registro para lectura o escritura.

ReadFilter Filtra los registros del archivo según la fecha y la hora.

ReadLogRecord Lee el siguiente registro disponible del archivo de registro actual.

WriteLogRecord Escribe un registro en el archivo actual.

Tabla 2

Page 27: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

27

Para obtener la información del registro actual el componente IISLog ofrece veinte propiedades de sólo lectura, como se muestra en la Tabla 3, que se corresponden con los distintos campos de un registro de un archivo de registro.

Propiedad Descripción

BytesReceived Número de bytes recibidos del navegador como una petición.

BytesSent Número de bytes enviados al navegador como una respuesta.

ClientIP Dirección IP del cliente.

Cookie Indica los contenidos de cualquier cookie enviada en la petición.

CustomFields Un vector de cabeceras personalizadas que se añadieron a la petición.

DateTime La fecha y hora de la petición en formato GMT.

Method El tipo de operación, tal como puede ser GET o POST.

ProtocolStatus El mensaje de estado devuelto al cliente, por ejemplo 200 OK.

ProtocolVersion Una cadena con la versión del protocolo utilizado, por ejemplo HTTP/1.1.

Referer La URL de la página que contiene el enlace que inició la petición, si está disponible.

ServerIP La dirección IP del servidor Web.

ServerName El nombre del servidor Web.

ServerPort El número de puerto por el que se recibió la petición.

ServiceName Nombre del servicio, como puede ser el servicio FTP (MSFTPSVC) o Web (W3SVC).

TimeTaken El tiempo de procesamiento total para devolver y crear la página devuelta.

URIQuery Cualquier parámetro añadido a la cadena de consulta (QueryString) de la URL en la petición.

Page 28: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

28

URIStem La URL que demandó el cliente.

UserAgent La cadena de agente de usuario (tipo de navegador) enviada por el cliente.

UserName Nombre de inicio de sesión del usuario si no ha accedido de forma anónima.

Win32Status Código de estado Win32 después de haber procesado la petición.

Tabla 3

Se puede configurar el tipo de registro que queremos en nuestro servidor a través de IIS 5.0, de esta forma podremos añadir o eliminar de nuestro fichero de registro los campos descritos anteriormente. Para ello acudiremos a las propiedades del sitio Web y en la pestaña sitio Web pulsaremos el botón Propiedades contenido en el epígrafe de Habilitar registro, como se ve en la Figura 5. Se debe seleccionar uno de los formatos de registro que se corresponden con un fichero de registro, por lo tanto la opción registro ODBC no sería válida.

Figura 5

Page 29: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

29

En el Código fuente 13 se muestra la utilización de este nuevo objeto ActiveX de servidor. En este sencillo código se utiliza el componente de registro para mostrar algunos de los campos contenidos en el fichero de registro.

<html><head><!--METADATA TYPE="TypeLib" FILE="c:\winnt\system32\inetsrv\logscrpt.dll"--></head><body><%Set objRegistro=Server.CreateObject("MSWC.IISLog")objRegistro.OpenLogFile "c:\winnt\system32\logfiles\w3svc1\ex000517.log"_

,ForReading,"W3SVC",1,0objRegistro.ReadFilter DateAdd("d",-1,Now),Now%><table align="center" border="0" cellspacing="2" cellpadding="5"><tr>

<th>Fecha/Hora</th><th>IP del cliente</th><th>Método</th><th>URL</th>

</tr><%While Not objRegistro.AtEndOfLog

objRegistro.ReadLogRecord%><tr>

<td><%=objRegistro.DateTime%></td><td><%=objRegistro.ClientIP%></td><td><%=objRegistro.Method%></td><td><%=objRegistro.URIStem%></td>

</tr><%WendobjRegistro.CloseLogFiles(ForReading)%></body></html>

Código fuente 13

Se ha utilizado un filtro para recuperar la información del fichero de registro referente al servicio Web y únicamente de las últimas 24 horas.

También se puede observar que se utiliza una directiva METADATA, más tarde comentaremos su utilidad y sintaxis, de momento diremos únicamente que nos permite incluir las constantes definidas en la librería que contiene al componente de registro.

La información que se va a mostrar del fichero de registro va a ser la fecha y hora de la petición, la dirección IP del cliente que ha realizado la petición, el método que se ha utilizado y la URL correspondiente. En la Figura 6 se puede ver un ejemplo de ejecución de la página anterior.

El nombre del fichero de registro variará según sea nuestra configuración del registro en el sitio Web correspondiente, la ubicación de estos ficheros de registro suele ser el directorio C:\WINNT \SYSTEM32\LOGFILES\W3SVc1 para el servicio Web.

Esta página ASP que utiliza el componente de registro se puede utilizar únicamente restringiendo el acceso anónimo a la propia página o al directorio que la contiene a nivel de permisos de NTFS, en caso contrario no podremos acceder al fichero de registro, ya sea para leer o escribir datos.

Page 30: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

30

Figura 6

Aplicaciones ASP con IIS 5.0 En IIS 4.0 ya podíamos definir aplicaciones ASP y su directorio de inicio, también podíamos indicar a través de la configuración de los directorios de un sitio Web si la aplicación se ejecutaba en otro espacio de memoria como un proceso aislado.

Con IIS 5.0 el concepto de aplicación ASP no ha variado, es decir, una aplicación es un conjunto de páginas ASP que se ejecutan en un conjunto de directorios definidos dentro de un sitio Web, tampoco ha variado excesivamente la forma de configurar las aplicaciones ASP. Lo más destacable que ofrece IIS 5.0 con respecto a las aplicaciones ASP es la posibilidad de definir tres niveles de protección distintos para dichas aplicaciones.

En IIS 4.0 podíamos indicar que nuestra aplicación se ejecutara en el mismo espacio de memoria que el servidor Web o que se ejecutara en un proceso aislado, pero con IIS 5.0 tenemos otra posibilidad intermedia, que consiste en que la aplicación se ejecuta en un proceso agrupado con el resto de las aplicaciones ASP.

Los tres grados de protección que ofrece IIS 5.0 para las aplicaciones ASP se denominan bajo, medio y alto, y se muestran en la Tabla 4.

Protección Descripción

Baja (proceso IIS) Las aplicaciones ASP se ejecutan todas en el mismo espacio de memoria que el servidor Web IIS 5.0. Si una aplicación ASP falla afectará a todo el servidor Web, poniendo en peligro la ejecución de la aplicacion InetInfo.exe, que es el ejecutable del servidor Web. Ofrece la ejecución más rápida y eficiente de las aplicaciones ASP, pero tambiénes la que ofrece más riesgos.

Page 31: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

31

Media (agrupada) Esta es la protección por defecto, todas las aplicaciones ASP se ejecutan agrupadas en un espacio de memoria distinto que el del servidor Web, en este caso todas las aplicaciones ASP del servidor Web utilizan una instancia compartida del ejecutable DLLHost.exe. De esta forma se proteje al ejecutable InetInfo.exe de los posibles fallos de las aplicaciones ASP. Si se produce un fallo en una aplicación ASP no afecta al servidor Web, pero sí a resto de las aplicaciones ASP.

Alta (aislada) Cada aplicación ASP se ejecuta en un espacio de memoria distinto, es decir, cada aplicación se ejecuta en una instancia distinta y exclusiva del ejecutable DLLHost.exe. De esta forma si una aplicación falla no afectará al resto de las aplicaciones ASP ni tampoco al servidor Web, ya que se ejecuta en su propio espacio de memoria. Microsoft recomienda que por cada servidor Web no se definan más de diez aplicaciones aisladas. Este tipo de protección es recomendable para aplicaciones ASP de alto riesgo o críticas.

Tabla 4

Por defecto el sitio Web predeterminado se define como una aplicación ASP agrupada o con grado de protección medio, este es el modo de protección de la aplicación más usual y recomendable, ya que ofrece una buena relación en lo que a rendimiento y seguridad se refiere, con el grado de protección alto comprometemos el rendimiento y con el grado de protección bajo se compromete la seguridad del funcionamiento del servidor Web. En la Figura 7 se puede ver la forma de configurar el grado de protección de una aplicación.

Figura 7

Page 32: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

32

Otros cambios En la versión anterior de ASP si necesitábamos utilizar las constantes definidas en una librería de componentes, como puede ser ADO, teníamos que incluir un fichero con la definición de dichas constantes mediante la también conocida directiva INCLUDE de ASP, en el caso de ADO se trataba del famoso fichero ADOVBS.INC. Pero con ASP 3.0 esta situación ha cambiado, podemos incluir las constantes definidas en una librería de forma directa desde la propia librería, sin tener que crear un fichero de definición de constantes diferenciado.

Para incluir una referencia a una librería un componentes utilizamos la nueva directiva METADATA, cuya sintaxis se muestra en el Código fuente 14.

<!-- METADATA TYPE="TypeLib"FILE="camino y nombre del fichero"UUID="identificador de la librería"VERSION="numVersionMayor.numVersionMenor"LCID="identificador de localización"

-->

Código fuente 14

Las propiedades que son obligatorias son FILE o UUID, siempre deberemos indicar uno u otro para identificar la librería, el resto de las propiedades son de tipo opcional De esta forma para incluir las constantes de ADO y poder utilizarlas, escribiremos lo que indica el Código fuente 15.

<!-- METADATA TYPE="TypeLib"FILE="c:\Archivos de Programa\Archivos

comunes\System\ado\msado15.dll"-->

Código fuente 15

Se debe señalar que o bien podemos utilizar la directiva METADATA en cada una de las páginas ASP en las que necesitemos incluir las constantes o también se puede incluir en el fichero GLOBAL.ASA y de esta forma estar disponible la definición de constantes y la referencia a la librería para todas las páginas de la aplicación ASP. Como curiosidad hago notar que le nombre de la librería de ADO sigue siendo MSADO15.DLL cuando lógicamente debería ser MSADO25.DLL, ya que ya nos encontramos en la versión 2.5 de ADO, aunque de todas formas esta librería contiene la última versión de ADO.

Para incluir archivos en nuestras páginas ASP ya hemos visto que utilizamos la directiva INCLUDE, pero en ASP 3.0 hay otra alternativa que es la utilización de la etiqueta <SCRIPT> como muestra el Código fuente 16.

<SCRIPT RUNAT="SERVER" SRC="ruta relativa, física o virtual al fichero descrip"></SCRIPT>

Código fuente 16

Page 33: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 1. Introducción a ASP

33

El fichero que incluimos, a diferencia de la directiva INCLUDE, únicamente puede contener secuencias de comandos, no puede contener texto ni código HTML, además no debe existir ningún elemento entre las etiquetas <SCRIPT></SCRIPT>.

Si un usuario accede a un sitio Web indicando únicamente el nombre del mismo, sin indicar ninguna página, se enviará al usuario el documento o página por defecto. Sin embargo, si se añadía una cadena de consulta (QueryString) a esta URL en la versión anterior de ASP esta cadena era ignorada. Pero ahora con ASP 3.0 y combinación con IIS 5 la cadena de consulta si es considerada por la página predeterminada. De esta forma en ASP 3.0 escribir http://www.eidos.es/?prueba=true es equivalente a escribir la URL http://www.eidos.es/default.asp?prueba=true, siendo default.asp la página prede-terminada del sitio Web del Grupo EIDOS.

Page 34: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 35: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Modelo de objetos de ASP. Parte I

Introducción Este tema pretende ser un simple recordatorio de los objetos integrados de ASP, y sus principales colecciones, métodos y propiedades. Sólo se entrará en detalle en aquéllos que sean más utilizados.

ASP nos proporciona una serie de objetos integrados, a los que siempre tenemos acceso sin necesidad de instanciarlos, son objetos que constituyen lo que se denomina el modelo de objetos de ASP. Estos objetos son bastante interesantes ya que gran parte de la programación de aplicaciones ASP se basa en la utilización de los mismos.

Estos objetos ponen a disposición del programador una serie de métodos y propiedades que pueden ser utilizados desde el script de servidor, es decir, son directamente accesibles y manipulables desde VBScript. Cada uno de estos objetos cubre unas funciones determinadas.

Antes de comenzar a explicar cada unos de los objetos integrados se considera necesario repasar el concepto de objeto, método y propiedad dentro del entorno de la programación orientada a objetos y desde el punto de vista que nos interesa, es decir desde las páginas activas de servidor.

Un objeto es un componente que posee una serie de comportamientos y que tiene un estado. El estado de un objeto se encuentra definido por sus propiedades y sus comportamientos a través de los métodos. Un objeto puede contener otros objetos.

Cada objeto tiene unas propiedades que definen sus atributos. Las propiedades de un objeto nos indican algo sobre el objeto o sus contenidos. Las propiedades diferencian un objeto de otro y determinan su estado y características. Los métodos que poseen los objetos definen su comportamiento interno y frente a otros objetos.

Page 36: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

36

Los objetos integrados además de poseer métodos y propiedades, también ofrecen colecciones. Una colección es un grupo de objetos del mismo tipo. Un objeto y una colección son ambos contenedores, pero de distinto tipo. Un objeto contendrá cero o más colecciones de diferente tipo, mientras que una colección contendrá cero o más objetos de naturaleza similar.

Por ejemplo, ASP ofrece el objeto Request que contiene diferentes propiedades y colecciones de distinto tipo. Una de estas colecciones es la colección Form, esta colección contiene información sobre los elementos del formulario que se ha enviado. Aquí se puede observar la diferencia entre objetos y colecciones en ASP, un objeto puede siempre contener otro nivel de información variada pero las colecciones no.

La mayoría de los objetos integrados de ASP proporcionan colecciones. Una colección es una estructura de datos, similar a una matriz, que almacena cadenas, números, objetos y otros valores. A diferencia de las matrices, las colecciones se amplían y reducen automáticamente al recuperar o almacenar elementos. La posición de un elemento también cambia al modificar la colección. Es posible tener acceso a un elemento de una colección por su clave de cadena única, por su índice (posición) en la colección o si se iteran todos los elementos de la colección.

El acceso a las colecciones, su sintaxis y utilización la veremos según vayamos avanzando en el temario con distintos ejemplos.

Todas las colecciones ofrecen una serie de métodos comunes a todas ellas y son los siguientes:

• Count: devuelve número de elementos contenidos en la colección.

• Item: devuelve el elemento que se corresponde con el índice o cadena clave que se pasa por parámetro.

• Key: devuelve el nombre de una clave dado su índice.

Las colecciones que no son sólo de lectura, sino también de escritura, permiten además los métodos:

• Remove: elimina un elemento determinado de la colección, del que indicamos su clave o índice. La colección debe ser de escritura.

• RemoveAll: elimina todos los elementos presentes en una colección. Al igual que el método anterior requiere que la colección sea de escritura.

Las colecciones comienzan en el índice 1, a diferencia de los arrays que empiezan en el índice cero.

Antes de poder utilizar un objeto se debe instanciar, es decir, crear el objeto y asignárselo a una variable que va a representar una instancia de ese objeto, en realidad, hasta que no se instancia un objeto, el objeto no existe. Pero en el caso de los objetos integrados no hay que instanciarlos, se puede considerar que son creados al iniciar la ejecución la aplicación ASP.

El objeto Response Este objeto integrado en el modelo de objetos de ASP tiene la función de enviar datos al cliente, es decir, al navegador que ha cargado la página ASP. A través de este objeto podremos escribir en la página que visualizará el usuario e incluso podremos redirigir al usuario a otra dirección en Internet. También a partir de este objeto podremos definir cookies para el usuario y asignarles un valor. En definitiva, representa la respuesta que el servidor web devuelve al navegador del cliente como resultado de su petición.

Page 37: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 2. Modelo de objetos de ASP. Parte I

37

Colecciones del objeto Response El objeto Response posee una única colección llamada Cookies, que le permite crear y asignar valores a una cookie. Una cookie, físicamente, es un fichero que se escribe en la máquina local del cliente que se conecta a un sitio Web y que contiene información relativa a la conexión.

Una cookie es utilizada para mantener información entre diferentes conexiones HTTP. Se debe recordar que el protocolo HTTP es un protocolo sin estado, es decir, no se retiene información entre las diferentes conexiones que se realicen. Por esta razón, ni el cliente ni el servidor pueden mantener información entre diferentes peticiones o a través de diferentes páginas Web.

Este mecanismo para mantener información entre diferentes conexiones HTTP fue propuesto e implementado en un principio por la compañía Netscape.

Existen varios usos prácticos de las cookies, a continuación se van a comentar los más destacados:

• Para almacenar información acerca de las preferencias del cliente que se conecta a nuestro sitio Web, por ejemplo el color seleccionado de la página, el tipo de letra, etc.

• Para conservar información personal, no sensible, del usuario, como puede ser el nombre, el país de origen, código postal, el número de veces que ha accedido a nuestro sitio Web, etc.

Por lo tanto el uso de cookies nos puede permite personalizar las páginas ASP según el cliente que se haya conectado atendiendo a sus preferencias y datos personales. Por ejemplo podemos saludar al usuario con su nombre y asignar al color de fondo de la página su color favorito o también podremos indicarle el número de veces que ha accedido a nuestro sitio Web.

De esta forma podemos evitar preguntar al usuario sus preferencias o datos personales cada vez que entra en nuestro sitio Web.

Siempre debe haber una primera ocasión en la que el cliente conectado especifique el valor de la cookie, una vez especificado este valor ya puede ser utilizada la cookie en las diferentes conexiones que realice ese cliente, ya que la información ha quedado almacenada en la cookie. Esta información se almacena físicamente en un fichero del disco duro local del cliente. En el caso del navegador Internet Explorer de Microsoft cada cookie se corresponde con un fichero.txt que se encuentra en el directorio Documents and Settings (en el caso de Windows 2000) y en el subdirectorio Cookies, y en el caso del Communicator de Netscape las cookies se almacenan todas en un fichero llamado cookies.txt en el subdirectorio Netscape\User\usuario.

Hay una serie de consideraciones que se deben tener en cuenta a la hora de utilizar cookies en nuestra aplicación ASP:

• Las cookies se pueden perder, por lo tanto nunca se debe depender de las cookies para almacenar una información que no se pueda volver a generar. Este tipo de información se debería almacenar en una base de datos del servidor. No se debe olvidar que las cookies se almacenan en el disco local del cliente en ficheros, y por lo tanto estos ficheros se pueden dañar, ser borrados o sobreescritos.

• Las cookies pueden ser modificadas por el cliente, por lo tanto nunca se debe considerar que la información ofrecida por una cookie es auténtica. Si estamos usando una cookie para determinar la fecha de la última vez que un usuario visitó nuestro sitio Web podemos considerar como auténtica esta información sin ningún problema, pero sin embargo no es nada recomendable considerar auténtica una cookie que posee el número de cuenta de un usuario. Como regla general nunca se debe utilizar una cookie para almacenar información

Page 38: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

38

confidencial, este tipo de información se debería almacenar en una base de datos en el servidor Web.

• Las cookies pueden ser copiadas sin el consentimiento del propietario, nunca se debería utilizar una cookie para identificar a un usuario, una solución mejor es utilizar una contraseña y validarla con una base de datos del servidor.

• Algunos navegadores no reconocen las cookies. Incluso los más populares como el Internet Explorer y el Communicator, se pueden configurar para no utilizar cookies.

Se debe señalar que ASP para mantener estados, es decir, valores de variables, objetos..., entre diferentes páginas de una aplicación ASP utiliza cookies desde los objetos integrados Session y Application.

El uso de estas cookies por parte de ASP, se oculta completamente al programador para que se abstraiga de la utilización lógica de las cookies, todo ello gracias a los objetos Session y Application que las gestionan internamente (estos dos objetos los trataremos en los capítulos correspondientes). Así por ejemplo, cuando se inicia una sesión se crea la cookie ASPSSESIONID, aunque esta cookie no se grabará en el disco duro del cliente, sino que permanecerá en memoria, por lo tanto podemos asegurar al usuario que no vamos a acceder a su disco.

De esta forma si un navegador no acepta cookies, la aplicación ASP no podrá mantener el estado entre diferentes páginas. Si tenemos configurado nuestro navegador para que nos avise cuando recibe una cookie, al iniciar una sesión con una aplicación ASP aparecerá una ventana similar a la que se muestra en la Figura 8.

Figura 8

La colección Cookies también aparece en el objeto Request, pero en el objeto Request la colección es sólo de lectura, mientras que en el objeto Response es sólo de escritura. De esta forma en el objeto Response la colección Cookies será utilizada para crear las cookies o para modificar su valor, y en el objeto Request para recuperar el valor de las cookies.

Page 39: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 2. Modelo de objetos de ASP. Parte I

39

Para crear una cookie se utiliza la sintaxis del Código fuente 17.

Response.Cookies(NombredelaCookie)=ValordelaCookie

Código fuente 17

Si la cookie ya existe modifica su valor.

La sintaxis general es Response.Cookies(cookie)[(clave)|atributo]=valor, donde cookie, es el nombre de la cookie a la que hacemos referencia, clave es un parámetro opcional que se utiliza cuando la cookie es un diccionario, es decir puede contener diferentes datos, y atributo especifica una propiedad de la cookie. Las propiedades que poseen las cookies son:

• Expires: sólo de escritura, indica la fecha en la que caduca la cookie. Si no se especifica ningún valor, por defecto caduca cuando termina la sesión.

• Domain: sólo de escritura, especifica a que dominio es enviada la cookie. Por defecto será el nombre del dominio del servidor del que proviene la cookie.

• Path: sólo de escritura, indica la ruta del servidor de la que proviene la cookie. Si no se especifica, por defecto se toma la ruta de la página ASP que generó la cookie.

• Secure: sólo de escritura, para indicar si la cookie es segura.

• HasKeys: sólo de lectura, especifica si la cookie tiene claves, es decir, si es un diccionario.

Si queremos crear una cookie que tenga claves, por ejemplo que contenga los datos nombre, apellidos y edad, y que caduque a finales del 2001 se debería escribir lo que indica el Código fuente 18.

<%Response.Cookies("datosPersonales").Expires= #December 31, 2001#Response.Cookies("datosPersonales")("nombre")="Angel"Response.Cookies("datosPersonales")("apellidos")="Esteban Núñez"Response.Cookies("datosPersonales")("edad")=25

%>

Código fuente 18

En el caso de que se quiera eliminar una cookie que ya exista, basta con cambiar el valor de su propiedad Expires, asignándole una fecha anterior a la actual.

Las cookies se envían desde el servidor al navegador del cliente como un encabezado del protocolo HTTP.

Propiedades del objeto Response En este apartado vamos a comentar cada una de las propiedades del objeto Response, y como podemos utilizar las más comunes.

Page 40: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

40

El objeto Response posee las siguientes propiedades:

• Buffer: indica si los datos de la página se almacenan en un búfer.

• ContentType: especifica el tipo de contenido HTTP de la respuesta.

• Expires: especifica el intervalo de tiempo que debe transcurrir para que caduque una página almacenada en la caché del navegador.

• ExpiresAbsolute: tiene el mismo sentido que la propiedad anterior, pero aquí se especificar la hora y la fecha en la que caducará la página en la caché del navegador.

• Status: valor de la línea de estado que devuelve el servidor.

• CacheControl: determinará si los servidores proxy van a almacenar o no en su caché la salida generada por una página ASP.

• CharSet: indicará el juego de caracteres que está utilizando la página ASP.

• PICS: mediante esta propiedad indicaremos el tipo de contenido que posee nuestra página ASP.

• IsClientConnected: propiedad de sólo lectura con la que podremos averiguar si el cliente se ha desconectado del servidor.

Si utilizamos la propiedad Buffer del objeto Response asignándole el valor True, conseguiremos que ASP procese todo el script en el servidor antes de enviar algo al usuario, por defecto esta propiedad tiene el valor True. El contenido del búfer no es enviado al navegador hasta que no se haya terminado de procesar la página o hasta que los métodos End o Flush del objeto Response no son invocados.

Una vez activado el almacenamiento en búfer, es decir, la propiedad Buffer posee el valor True, y una vez que ya se ha enviado contenido al navegador del cliente, no se puede modificar su valor, tampoco se puede modificar ningún valor de las propiedades del objeto Response.Así por ejemplo el Código fuente 19 generaría un error.

<%Response.Buffer=False%><HTML><HEAD><%Response.Expires=10%>

Código fuente 19

El error devuelto por el navegador sería similar a “Los encabezados HTTP ya estánescritos en el explorador cliente”.

Cualquier cambio en el encabezado HTTP se debe hacer antes de escribir el contenido de la página.

En las versiones anteriores de ASP la propiedad Buffer tenía por defecto la propiedad False, de esta forma según se iba procesando la página ASP se enviaba el resultado de la ejecución al cliente. Según Microsoft con este cambio se obtiene un mejor rendimiento en la ejecución de páginas ASP. En realidad lo que se tiene también es un mayor control sobre la salida que va a recibir el usuario.

Page 41: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 2. Modelo de objetos de ASP. Parte I

41

El uso de este búfer puede ser útil en el caso de que sea necesario procesar el contenido de una página ASP antes de enviar ningún contenido previo al navegador del cliente. De esta forma se puede redireccionar al navegador hacia otra página con el método Redirect del objeto Response, este método se comentará en su apartado correspondiente, pero se puede adelantar que una llamada a este método producirá un error en el caso de que se haya enviado anteriormente algún contenido al usuario.

La propiedad Buffer también puede ser utilizada para verificar errores antes de enviar información al navegador, de esta forma si se detecta un error se puede detener el proceso de la página y redireccionar al navegador del cliente hacia una página determinada.

Cuando la propiedad Buffer, tiene su valor por defecto, es decir, el valor True se pueden utilizar una serie de métodos del objeto Response, estos métodos, cuya función se verá en el apartado correspondiente, son: Clear, End y Flush y básicamente lo que permiten es controlar el resultado o salida que se le envía al cliente.

Métodos del objeto Response A continuación, de la misma forma que se ha hecho con las propiedades del objeto Response, se va a hacer una breve descripción de los métodos que nos ofrece este objeto.

• AddHeader: agrega un nuevo encabezado HTML a la respuesta. Este método no es muy utilizado. Permite definir nuevos encabezados. Su sintaxis es: Response.AddHeader nombreEncabezado, valorEncabezado.

• AppendToLog: agrega una cadena al final de la entrada de registro del servidor Web para la petición. IIS se puede configurar para registrar las peticiones de los clientes en una base de datos o en un fichero de log. Este método permite agregar una cadena a la información que será almacenada por el usuario acerca de una petición de un cliente.

• BinaryWrite: este método es utilizado para escribir información directamente en la salida HTTP, es decir, el navegador del cliente, sin ningún tipo de interpretación. Este método es útil cuando se necesita enviar pequeños gráficos, multimedia u otros componentes que no son texto.

• Clear: elimina el contenido del código HTML del búfer.

• End: detiene el procesamiento de la página ASP y devuelve los resultados obtenidos hasta la llamada a End.

• Flush: envía al navegador el contenido del búfer antes de finalizar el procesamiento de la página ASP.

• Redirect: se redirecciona al navegador Web del cliente a la dirección que se le pasa como parámetro.

• Write: escribe en el navegador del cliente.

Los métodos Clear, Flush y End, deben ser utilizados cuando la propiedad Buffer del objeto Response esté activada, es decir, tiene como valor True, ya sabemos que este es el valor por defecto de esta propiedad.

Cuando está activado el almacenamiento en el búfer existen varias formas de enviar la información del búfer al navegador del cliente:

Page 42: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

42

• Llamando al método Flush.

• Llamando al método End. De esta forma también se detiene la ejecución de la página ASP.

• Cuando finaliza le ejecución de la página ASP, es decir, cuando se ejecuta la última línea de las secuencias de comandos de servidor.

El método Clear se utiliza cuando se quiere eliminar todo el contenido que posee el búfer, pero esto no implica que se borre el contenido que ya se ha enviado al cliente, a ese contenido ya no se tiene acceso, así por ejemplo el Código fuente 20 produciría un error.

<HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><b>Esto es contenido</b><%Response.FlushResponse.ClearResponse.Redirect "pruebas.asp"%></BODY></HTML>

Código fuente 20

La utilización de estos métodos junto con la propiedad Buffer nos permite controlar el procesamiento de la página ASP de una forma muy sencilla y eficaz. Para mostrar el uso de estos métodos junto con el almacenamiento en búfer vamos a ver un sencillo ejemplo, en el Código fuente 21, que va mostrando poco a poco un texto en pantalla.

<%strTexto="Texto que se va mostrando poco a poco en el navegador"For i=1 to Len(strTexto)

'se realiza una pausaFor j=1 To 100000Next

Response.Write Mid(strTexto,i,1)'se envía el contenido del búferResponse.Flush

Next%>

Código fuente 21

El efecto de este código es que se va enviando el texto caracter a caracter mediante el método Flush, para que se produzca una pausa se realiza un bucle For adicional. Si situamos la sentencia Response.Flush al final del código, aparecerá todo el texto de una sola vez.

A lo largo de los distintos ejemplos que hemos visto hasta ahora en el curso, en alguno de ellos hemos utilizado la sentencia Response.Write, por lo tanto ya sabemos exactamente la función de este método del objeto Response.

Pero también para escribir se han utilizado los delimitadores <%=%>. Estos delimitadores son equivalentes a escribir Response.Write, se pueden considerar como su abreviatura. El método

Page 43: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 2. Modelo de objetos de ASP. Parte I

43

Response.Write se utilizará dentro de una bloque de script de servidor, es decir, un bloque de código encerrado por los delimitadores <%%>, y el uso de los delimitadores <%=%> será adecuado cuando se necesite intercalar una línea aislada entre código HTML:

Como ya se ha visto, el método Write se puede utilizar para escribir texto en el navegador. Las llamadas a métodos y las variables dentro del método Write serán evaluadas y sólo el resultado se escribirá en el navegador del cliente. Por ejemplo, el Código fuente 22 mostrará el valor de la variable contador en el navegador del cliente.

<%Response.Write("La variable contador contiene el valor: " & contador)%>

Código fuente 22

El uso de paréntesis en el método Write es opcional. Si tenemos en cuenta los delimitadores <%=%>, de forma equivalente podríamos haber escrito lo que se muestra en el Código fuente 23 o en el Código fuente 24.

<%="La variable contador contiene el valor: "&contador%>

Código fuente 23

La variable contador contiene el valor: <%=contador%>

Código fuente 24

Si en nuestro código tenemos diferentes líneas con los delimitadores <%=%> intercaladas dentro de código HTML, para una mayor eficiencia es recomendable sustituirlos por una única línea mediante Response.Write. Además se consigue un código más legible, se debe tender a bloques de HTML y de script de servidor bien diferenciados, siempre que sea posible.

El método Redirect recibe como parámetro una cadena de texto en forma de URL que especifica la nueva dirección a la que se va a redirigir el navegador del usuario. La URL puede ser absoluta, del tipo www.almagesto.com o del tipo /directorio/pagina.asp, o relativa del tipo pagina.asp.

Al lanzar el método Redirect en realidad lo que estamos haciendo es enviar una cabecera HTTP al navegador Web del cliente para indicarle que la página se ha movido y le indicamos la nueva localización, que es la URL que hemos indicado al método Redirect. La información que se envía al navegador es HTTP/1.1 Object Moved Location /directorio/pagina.asp.

Como se puede observar la redirección se realiza en el cliente, indicándole que la página se ha movido a una nueva dirección, que en realidad es otra página completamente distinta.

Aquí nos hemos centrado en redireccionar el navegador a otra página (HTML o ASP), pero se puede generalizar diciendo que podemos redireccionar al navegador a cualquier recurso, como puede ser una imagen, un fichero zip, un documento, etc.

Page 44: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

44

El objeto Request Este objeto integrado es utilizado para obtener información del usuario, por lo tanto realiza las funciones contrarias al objeto Response.

Cuando un navegador cliente se comunica con el servidor Web a través del protocolo HTTP, el navegador manda un gran número de información además de la página que se quiere cargar, esta información puede ser: variables de entorno, información sobre certificados, cookies, formularios, etc. Toda esta información es codificada y enviada a través de cabeceras del protocolo HTTP y en muchos casos no es sencilla de extraer. ASP realiza las funciones de extraer, decodificar y organizar toda esta información a través del objeto Request y sus diferentes colecciones.

Esta información enviada por el navegador, se puede utilizar para: validar un usuario, obtener información sobre el usuario el navegador, almacenar información para su posterior uso, enviar información al servidor a través de formularios, etc.

ASP almacena toda esta información en colecciones del objeto Request. Mediante llamadas del tipo Request.colección se puede obtener de forma sencilla la información que sea necesaria. El objeto Request presenta cinco colecciones que veremos en el siguiente apartado

Colecciones del objeto Request Las cinco colecciones que ofrece el el objeto Request del modelo de objetos de ASP contienen toda la información enviada por el navegador cliente al servidor Web. Estas colecciones se pasan a comentar de forma breve:

• ClientCertificate: contiene los valores de los campos de certificación (especificados en el estándar X.509) de la petición emitida por el navegador.

• Cookies: valores de las cookies del cliente.

• Form: valores de elementos de un formulario HTML.

• QueryString: valores de las variables de la cadena de consulta HTTP enviada.

• ServerVariables: esta colección almacena información sobre el navegador, el servidor y el usuario.

Para tener acceso a la información de las colecciones del objeto Request se puede utilizar la sintaxis general Request.NombreColeccion(variable), donde NombreColeccion es el nombre de la colección que se quiere consultar y variable es el nombre de la variable de la colección a la que se quiere tener acceso y recuperar su valor.

Las variables contenidas en las colecciones del objeto Request son únicamente de lectura.

También se puede acceder a una variable de una colección sin especificar el nombre de la colección (Request(variable)). En este caso se realizará una búsqueda por todas las colecciones del objeto Request hasta que se obtenga la variable deseada. El orden de búsqueda entre las colecciones es el siguiente: QueryString, Form, Cookies, ServerVariables y por último ClientCertificate. Se obtendrá la primera variable que coincida con el parámetro variable. Esto no es muy recomendable ya que es más lento y pueden existir variables con el mismo nombre en distintas colecciones.

Page 45: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 2. Modelo de objetos de ASP. Parte I

45

Para obtener todos los valores de las variables de una colección se puede utilizar la instrucción For Each...in..., el Código fuente 25 muestra como se obtendría el nombre y el valor de cada variable de la colección ServerVariables:

<%For each variable in Request.ServerVariablesResponse.Write("La variable: "&variable&" tiene el valor: "&_

Request.ServerVariables(variable)&"<br>")Next%>

Código fuente 25

El objeto Request mediante su colección Form permite acceder a los datos enviados a través de un formulario mediante el método POST.

Para obtener los datos de un formulario, que por ejemplo tuviera los campos Nombre y Edad, se debería escribir el Código fuente 26 dentro de la página ASP llamada PROCESAINFO.ASP.

Nombre usuario: <%=Request.Form("nombre")%><br>Edad usuario: <%=Request.Form("edad")%>

Código fuente 26

Si se quiere obtener los datos sin decodificar bastaría con escribir el Código fuente 27.

Datos: <%=Request.Form%>

Código fuente 27

En el navegador aparecería lo siguiente: Datos: nombre=Pepe&edad=30&boton=Enviar. Se puede observar que además de los campos de texto del formulario también se envía el botón de Submit si a éste se le ha asignado un nombre en la etiqueta de HTML.

En algunos casos los elementos de un formulario pueden ser un array, basta con, por ejemplo, dar a varias cajas de texto el mismo nombre, de esta forma para acceder a la información se deberá utilizar un índice. Por ejemplo si tenemos el formulario del Código fuente 28.

<form action="procesaInfo.asp" method="POST">

Nombre: <input type="Text" name="datosPersonales" value="">Apellidos: <input type="Text" name="datosPersonales" value="">Edad: <input type="Text" name="datosPersonales" value=""><input type="Submit" name="boton" value="Enviar">

</form>

Código fuente 28

Page 46: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

46

Para poder recuperar la información enviada se debería tratar como un array, y se realizaría de la forma que se indica en el Código fuente 29.

<%For i=1 To Request.QueryString("datosPersonales").CountResponse.write(Request.Form("datosPersonales")(i)&"<br>")

Next%>

Código fuente 29

Como se puede observar los índices comienzan en 1, y para saber el número de elementos del array se utiliza el método Count que devuelve el número de elementos de un array.

Las páginas ASP se pueden utilizar para recoger y procesar valores de formularios HTML de varias maneras:

• Un archivo htm o html estático puede contener un formulario que envíe sus valores a una página ASP, como ha sido el caso de los ejemplos anteriores.

• Una página ASP puede contener un formulario que envíe información a otra página ASP.

• Una página ASP puede contener un formulario que envíe información así misma, es decir, a la página ASP que contiene el formulario.

La última opción es la más potente y la más recomendable, de esta forma una página ASP se llama así misma. Para poder utilizar esta estrategia lo que se debe tener en cuenta es si la página ASP se carga por primera vez o se carga de nuevo porque ha sido llamada por sí misma. Esto se puede conseguir preguntando si existe alguno de los campos del formulario, si existe es que se ha realizado la llamada desde la misma página y por lo tanto se validarán o mostrarán los datos; y si no existe, la página se está cargando por primera vez y se mostrará el formulario. En el Código fuente 30 de ejemplo se puede observar esta técnica.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><HEAD>

<TITLE>Misma página ASP</TITLE></HEAD><BODY><%If Request.Form("botonEnviar")<>"" Then%>

<u>Datos enviados</u><br>Nombre: <%=Request.Form("nombre")%><br>Edad: <%=Request.Form("edad")%>

<%Else%><form action="mismaPagina.asp" method="POST">

Nombre: <input type="Text" name="nombre" value="">Edad: <input type="Text" name="edad" value=""><input type="Submit" name="botonEnviar" value="Enviar">

</form><%End If%></BODY></HTML>

Código fuente 30

Page 47: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 2. Modelo de objetos de ASP. Parte I

47

En este caso se pregunta por el valor del botón de envío, ya que siempre que se envíe el formularío se enviará también el botón de tipo submit. Además se supone el código mostrado pertenece a una página ASP llamada mismaPagina.asp tal como se indica en la propiedad ACTION de la etiqueta <FORM>.

Si cargamos por primera vez esta página pasaremos por la rama de la instrucción Else y veríamos el formulario en el navegador. Una vez cargada la página, si rellenamos los campos de texto y pulsamos sobre el botón etiquetado como Enviar, pasaríamos por el primer bloque del If, ya que la página ASP se volvería a cargar así misma y la variable botonEnviar de la colección Form ya contendría un valor.

Como se puede observar da la impresión que son dos páginas distintas, pero en realidad es la misma página ASP que genera diferente código HTML según la ejecución del script de servidor.

Para obtener los valores de un formulario que se ha enviado con el método GET o para recuperar los valores de una cadena de consulta de un enlace, utilizaremos esta otra colección del objeto Request: QueryString.

Todo lo visto para la colección Form es válido para la colección QueryString. La única diferencia es que los datos aparecen visibles en la barra de direcciones del navegador y existe un tamaño máximo de 1024K.

La decisión de utilizar una colección u otra depende del tamaño de los datos a enviar y del número de ellos. Cuando el tamaño es mayor de 1024K sólo tendremos la opción de usar la colección Form.

Yo personalmente sigo la siguiente regla, para los formularios de HTML siempre utilizao el método de envío POST y por lo tanto para recuperar los valores de los campos utilizo Form, y la colección QueryString la suelo utilizar para recuperar los valores de los datos facilitados desde un enlace.

Se debe tener en cuenta que el usuario puede manipular la cadena de consulta enviada mediante un enlace, por lo tanto habrá algunos datos que no podremos enviar desde una cadena de consulta, pero hay algunos casos en que no representa ningún problema que el usuario modifique la cadena de consulta.

Page 48: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 49: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Modelo de objetos de ASP. Parte II

El objeto Application Un objeto Application representa una aplicación ASP. Una aplicación basada en ASP consta de un directorio en un servidor Web y de todos los subdirectorios y archivos contenidos en él. Una aplicación puede ser una página principal sencilla, o bien puede estar formada por un conjunto completo de páginas interrelacionadas entre sí.

Se debe recordar que el protocolo HTTP es un protocolo sin estado, es decir, no se puede almacenar información entre diferentes conexiones HTTP. No se puede mantener el estado entre diferentes páginas Web a través del protocolo HTTP, sino que se deben utilizar otros mecanismos como las cookies. Pero el objeto Application junto con el objeto Session (que se comentará en su capítulo correspondiente) nos permite de forma sencilla y directa almacenar información abstrayéndonos del uso de cookies y de encabezados HTTP.

La información almacenada en los objetos Session y Application difieren en el ámbito de la misma, una información tendrá el ámbito de la sesión de un usuario concreto y la otra el ámbito de la aplicación general, respectivamente.

Las variables almacenadas dentro del objeto Application son visibles para todos los usuarios que están utilizando la misma aplicación ASP, es decir son compartidas por varios usuarios. En contraposición al objeto Session, cuyas variables son para cada uno de los usuarios conectados, es decir, no se comparten y son propias de cada sesión. Podremos acceder a una variable a nivel de aplicación en cualquiera de las páginas ASP contenidas en la aplicación ASP actual.

Page 50: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

50

En este punto se debe señalar que una variable en una aplicación ASP puede tener cuatro ámbitos diferentes, se va a ir del más global al más particular. La creación de una variable con un ámbito u otro dependerá del uso que queramos hacer de ella.

Ámbito de aplicación: esta variable la podrán manipular todos los usuarios de la aplicación ASP, es común a todos ellos. Se almacena dentro del objeto Application.

• Ámbito de sesión: las variables con este ámbito son propias de cada uno de los usuarios de la aplicación, es decir, cada usuario tendrá acceso a las variables de su sesión. Estas variables se almacenan dentro del objeto integrado Session.

• Ámbito de página: estas variables son las que se crean dentro del script de servidor de una página ASP, sólo tienen vigencia dentro de la página en la que se declararon, al abandonar la página se destruirán.

• Ámbito de procedimiento: a este ámbito pertenecen las variables declaradas dentro de un procedimiento (Sub o Function). Estas variables sólo existirán dentro del procedimiento en el que son declaradas, se dice que son variables locales al procedimiento.

Para almacenar una variable dentro de un objeto Application, es decir, crear una variable cuyo ámbito sea la aplicación se debe utilizar la sintaxis del Código fuente 31.

Application("NombreVariable")=valorVariable

Código fuente 31

También se pueden almacenar objetos dentro del objeto Application.

Hay una serie de consideraciones acerca de las variables que se pueden almacenar en el objeto Application y que pasamos a comentar a continuación.

En cuanto a tipos de variable se refiere, una variable de aplicación puede contener cualquier tipo de valor Variant, y en cuanto a objetos, puede contener cualquier tipo de objeto o componente que se encuentre preparado para tener ámbito de aplicación, a excepción de los objetos del modelo de objetos de ASP (ASPError, Request, Server, Response, Application, Session, ObjectConext) de esta forma la instrucción del Código fuente 32 generaría un error.

<%Set Application("objeto")=Request%>

Código fuente 32

Si almacenamos una variable array a nivel de aplicación, para modificar sus valores no podremos hacerlo directamente, sino que se debe hacer a través de una variable auxiliar, que será la que se modificará y luego asignará a la variable de aplicación correspondiente. En el Código fuente 33 se muestra la utilización de una variable de aplicación que es un array de cadenas.

<%Dim vector(3)vector(0)="Primer valor"vector(1)="Segundo"

Page 51: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

51

vector(2)="Tercero"vector(3)="Ultimo Valor"Application("valores")=vector'----'----'Para modificar los valores recuperamos la variablevectorAux=Application("valores")vectorAux(2)="Elemento modificado"Application("valores")=vectorAuxFor i=0 to UBound(Application("valores"))

Response.Write"Application('valores')("&i&")="&Application("valores")(i)&"<br>"Next%>

Código fuente 33

Sin embargo los valores de cada elemento de array si que se pueden recuperar directamente de la variable de aplicación.

No es recomendable almacenar objetos a nivel de aplicación, ya que esto supone que el objeto va a existir durante toda la vida de la aplicación ASP y puede ser accedido por distintos usuarios de manera concurrente. Lo ideal para almacenar en variables de aplicación son variables de tipo entero, booleano o cadenas de caracteres.

Colecciones del objeto Application En la versión 1.0 de ASP el objeto Application no poseía ninguna colección, sin embargo en ASP 2.0 se añadieron dos colecciones, y son:

• Contents: contiene las variables a nivel de aplicación a excepción de los objetos creados con la etiqueta <OBJECT>

• StaticObjects: contiene únicamente los objetos a nivel de aplicación creados con la etiqueta <OBJECT>.

Ambas colecciones nos van a permitir recuperar o acceder a las variables y objetos creados a nivel de aplicación, aunque ya hemos visto en el apartado anterior que podemos acceder directamente a ellos.

La colección Contents contiene todos los objetos y variables creados a nivel de aplicación, excluyendo aquellos objetos que han sido creados utilizando la etiqueta de HTML <OBJECT>. Esta etiqueta se utiliza para la creación de objetos, de todas formas veremos con detalle el uso de la etiqueta <OBJECT> en este mismo apartado a la hora de comentar la colección StaticObjects.

En esta colección se incluirán, por tanto, los objetos creados a nivel de aplicación con la sentencia Server.CreateObject y las variables creadas con Application("variable")=valor.

La colección Contents del objeto Application permite utilizar un par de métodos que son comunes a todas las colecciones de escritura y que son los siguientes:

• RemoveAll: elimina todas las variables de aplicación, a excepción de las creadas con la etiqueta <OBJECT>. Este método carece de parámetros.

• Remove: elimina una variable de aplicación determinada que esté contenida en la colección Contents. Este método recibe por parámetro el índice o nombre de la variable correspondiente.

Page 52: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

52

La colección StaticObjects contiene todos los objetos a nivel de aplicación que se han creado mediante la etiqueta <OBJECT>, por lo tanto la colección StaticObjects únicamente contendrá variables que son referencias a objetos.

De la misma forma que veíamos en el ejemplo anterior, podremos recorrer la colección StaticObjects para acceder a los objetos estáticos creados a nivel de aplicación.

La etiqueta <OBJECT> es una etiqueta de HTML que se suele utilizar para instanciar y crear objetos ActiveX en el navegador del cliente, sin embargo aquí su uso es muy distinto, ya que se utiliza para instanciar componentes del servidor, podemos decir que es equivalente a la sentencia Server.CreateObject. Pero esta etiqueta únicamente se puede utilizar en el fichero especial global.asa.

La colección StaticObjects no ofrece ningún método como los de la colección Contents, únicamente ofrece los métodos que son comunes a todas las colecciones de lectura, que son Count, Key e Item. Veamos un ejemplo, suponiendo que tememos creados los objetos del ejemplo anterior.

Métodos del objeto Application Las variables almacenadas en el objeto Application son compartidas por todos los usuarios de la aplicación ASP. Debido a esto se pueden dar problemas de concurrencia, es decir, cuando dos usuarios acceden a la misma información y la quieren modificar al mismo tiempo, por lo tanto se debe tener un acceso exclusivo a las variables del objeto Application cuando se quiera modificar su valor.

Aquí entendemos por usuarios a sentencias del lenguaje de secuencias de comandos, es decir, serían dos sentencias en distintas páginas que intentaran modificar la misma variable de aplicación al mismo tiempo.

Para implementar este mecanismo de exclusión mutua el objeto Application ofrece dos métodos: Lock y UnLock. Cuando se llama al método Lock, éste impide que otros usuarios modifiquen el contenido de las variables de la aplicación. Y cuando se llama al método UnLock, se permite el acceso a las variables a todos los usuarios de la aplicación. Es un método de exclusión mutua, sólo un usuario puede a la vez estar utilizando las variables del objeto Application, las variables quedarán libres para el resto de los usuarios cuando se lance sobre el objeto Application el método UnLock. El Código fuente 34 muestra un ejemplo de utilización de estos dos métodos.

<%Application.LockApplication("NumVisitas")=Application("NumVisitas")+1Application.UnLock%>

Código fuente 34

Este mecanismo puede ser ineficiente, ya que se bloquean todas las variables del objeto Application cuando, como en el ejemplo anterior, necesitamos que solamente se proteja una variable.

No se debe utilizar demasiadas sentencias entre una llamada al método Lock y la correspondiente llamada a UnLock, ya que las variables del objeto Application podrían quedar bloqueadas demasiado tiempo afectando de esta forma al correcto funcionamiento de la aplicación ASP correspondiente.

Lock y UnLock se utilizarán normalmente en el momento en el que se vaya a modificar el valor de una variable de aplicación.

Page 53: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

53

Nunca se debe olvidar el corresponder cada llamada Lock con una llamada UnLock, ya que podríamos caer en el error de dejar bloqueada las variables de la aplicación de forma indefinida.

Eventos del objeto Application. El GLOBAL.ASA El objeto Application posee dos eventos, cuando comienza la ejecución de la aplicación ASP y cuando finaliza la ejecución de la aplicación ASP, estos dos eventos se llaman, respectivamente Application_OnStart y Application_OnEnd.

Estos dos eventos se corresponden con dos procedimientos del mismo nombre definidos en el fichero global.asa. Ya empezamos a ver una de las principales funciones del ya mencionado fichero global.asa.

Dentro de estos eventos se puede situar un script que realice las tareas que consideremos necesarias. El script que se debe ejecutar en cada uno de estos eventos se deberá indicar el fichero especial llamado GLOBAL.ASA (ASA, Active Server Application).

El evento Application_OnStart se produce cuando entra el primer usuario en la aplicación, es decir antes de producirse el primer inicio de sesión (Session_OnStart), por ejemplo, cuando el primer usuario carga una página ASP perteneciente a una aplicación. Dentro de este evento se deberá indicar el código de inicialización de la aplicación ASP.

Y el evento Application_OnEnd se produce cuando se apaga el servidor Web, se descarga la aplicación ASP, finaliza la última de las sesiones de un usuario o se modifica el fichero GLOBAL.ASA, estas son las distintas formas que tiene de finalizar una sesión. Dentro de este evento se deberá escribir el script que se desee que se ejecute antes de destruir la aplicación.

En los eventos Application_OnEnd y Application_OnStart únicamente se tiene acceso a dos de los objetos integrados de ASP, se trata de los objetos Server y Application, si intentamos utilizar algún otro objeto del modelo de objetos de ASP se producirá un error.

El fichero GLOBAL.ASA (ASA, Active Server Application, aplicación activa de servidor o mejor aplicación ASP), que tanto hemos mencionado hasta ahora en este capítulo, es un fichero opcional que se encuentra en el directorio raíz de la aplicación ASP y que está relacionado de forma directa con los objetos integrados Application y Session. Este fichero, que debe ser único para cada aplicación ASP, tiene varias funciones:

• Definir como son tratados los eventos de los objetos Session y Application. Como hemos comentado en el apartado anterior.

• Permitir crear objetos con el ámbito de aplicación y sesión.

• Inicializar y crear variables en el ámbito de la sesión y aplicación.

• Información acerca del tratamiento de los eventos de los objetos Session y Application.

• Declaraciones de objetos mediante la etiqueta <OBJECT>.

Este fichero no es un fichero cuyo contenido se muestre al usuario, si un usuario intenta cargar el fichero global.asa en su navegador recibirá un mensaje de error:.

La estructura general del GLOBAL.ASA es la del Código fuente 35.

Page 54: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

54

<SCRIPT LANGUAJE=VBScript RUNAT=Server>SUB Application_OnStart......END SUB

SUB Session_OnStart......END SUB

SUB Session_OnEnd......END SUB

SUB Application_OnEnd......END SUB</SCRIPT>

Código fuente 35

Si se escribe script fuera de las etiquetas <SCRIPT></SCRIPT> o se declara un objeto que no tiene ámbito de sesión o de aplicación se producirá un error.

Tampoco se pueden incluir ficheros de ningún tipo mediante el uso de la directiva INCLUDE.

El lenguaje de secuencias de comandos a utilizar se indica en el atributo LANGUAGE de la etiqueta <SCRIPT>, y también se debe indicar en que lugar se ejecutará el script, esto se consigue a través del atributo RUNAT de la etiqueta <SCRIPT>, en realidad este atributo sólo tiene un valor posible: Server, es decir, el script se ejecutará en el servidor.

Para declarar objetos mediante la etiqueta <OBJECT>, para que tengan el ámbito de sesión o aplicación se deberá seguir la sintaxis del Código fuente 36.

<OBJECT RUNAT=Server SCOPE=Ambito ID=Identificador{PROGID="IDprog"|CLASSID="IDclase"}>........</OBJECT>

Código fuente 36

La declaración de los objetos deberá ir fuera de las etiquetas de script. Los objetos declarados de esta forma no se crearán hasta que el servidor procese una secuencia de comandos en el que se haga referencia a ellos. Así se ahorran recursos, al crearse sólo los objetos que son necesarios.

Estos objetos pasaran a formar parte de la colección StaticObjects del objeto Application.

El parámetro Ambito especifica el ámbito del objeto, podrá tener los valores Session o Application; Identificador especifica un nombre para la instancia del objeto; IDprog e IDclase para identificar la clase del objeto.

La propiedad SCOPE de la etiqueta <OBJECT> de HTML, tiene un valor de ámbito más, además de los de sesión y de aplicación, y se trata del ámbito de página SCOPE="PAGE". El ámbito de página indica que el objeto que se instancie sólo existirá en el página actual, pero este ámbito no se puede

Page 55: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

55

utilizar en el fichero global.asa sino que se puede utilizar en cualquier página ASP. Sin embargo en las páginas ASP no se puede utilizar la etiqueta <OBJECT> con el ámbito de aplicación o de sesión, únicamente se pueden instanciar objetos con ámbito de página.

El Código fuente 37 dentro del fichero global.asa crearía un objeto Connection de ADO con ámbito de sesión.

<OBJECT RUNAT=Server SCOPE=Session ID=conexion PROGID="ADODB.Connection"></OBJECT>

Código fuente 37

Para utilizar este objeto posteriormente dentro de una página ASP, por ejemplo, para ejecutar una sentencia SQL sobre la conexión con la base de datos, bastaría con escribir la línea del Código fuente 38.

<%conexion.Execute "DELETE FROM Usuarios WHERE id<10"%>

Código fuente 38

Es decir, accedemos directamente al nombre del objeto, que será el indicado en la propiedad ID de la etiqueta <OBJECT>.

El objeto Application se crea cuando el primer usuario se conecta a una aplicación ASP y pide una sesión, es decir, carga la primera página de la aplicación ASP. Cuando se crea el objeto Application, el servidor busca el fichero GLOBAL.ASA en el directorio raíz de esa aplicación ASP, si el fichero existe se ejecuta el script del evento Application_OnStart.

A continuación se crea el objeto Session. La creación del objeto Session ejecuta el script que se encuentra en el evento Session_OnStart. El script asociado al tratamiento de este evento se ejecutará antes de cargar la página indicada por la petición del navegador cliente.

Cuando el objeto Session caduca o se lanza el método Session.Abandon, se ejecutará el script que se corresponde con el evento Session_OnEnd, el código de este evento se procesará antes de destruir la sesión.

Cuando finaliza la última sesión de los usuarios, es decir, se ejecuta el código del último evento evento Session_OnEnd, se lanza el evento Application_OnEnd antes de que se destruya el objeto Application.

Si se modifica el fichero GLOBAL.ASA, el servidor lo recompilará, para ello el servidor deberá destruir el objeto Application actual y los objetos Session actuales. Primero, el servidor procesa todas las peticiones activas, el servidor no procesará más peticiones hasta que no se procese el evento Application_OnEnd. Los usuarios que se intenten conectar durante este proceso recibirán un mensaje que le indica que la petición no puede ser procesada mientras la aplicación es reiniciada. Durante este proceso se dan los siguientes pasos:

• Las sesiones activas se destruyen, dando lugar al procesamiento del evento Session_OnEnd.

• La aplicación se destruye, produciéndose el evento Application_OnEnd.

Page 56: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

56

• La primera petición reiniciará el objeto Application y creará un nuevo objeto Session, es decir, se darán los eventos Application_OnStart y Session_OnStart, respectivamente.

También se ejecutará la el evento Application_OnEnd cuando se descargue la aplicación ASP desde el Administrador de servicios de Internet o cuando se apague el servidor Web.

El objeto Session Al igual que ocurría con el objeto Application, el objeto Session nos va a permitir almacenar información entre diferentes páginas ASP incluidas en una misma aplicación ASP. La diferencia con el objeto Application se encuentra en el ámbito de las variables, cada variable del objeto Session es particular a una sesión de un usuario determinado, no a toda la aplicación. De esta forma, cada usuario tendrá sus variables y sus valores, sin dar lugar a problemas de concurrencia, tampoco se podrá acceder a distintas variables de sesión, cada usuario tiene su espacio de almacenamiento.

Las variables de aplicación son valores globales y comunes a toda la aplicación, y las variables de sesión son particulares para cada usuario de la aplicación.

El servidor Web crea automáticamente un objeto Session, cuando un usuario que aún no estableció una sesión solicita una página ASP perteneciente a la aplicación ASP actual. El servidor Web sabe si un navegador tiene ya una sesión debido a que la cookie ASPSESSIONID es enviada junto con la petición de la página ASP.

Un uso común del objeto Session es almacenar las preferencias del usuario o información personal. Se debe señalar que se podrán almacenar variables dentro del objeto Session si el navegador acepta cookies, ya que el objeto Session para almacenar información se basa en la cookie ASPSESSIONID. Aunque la utilización de esta cookie es completamente transparente para el programador.

Para una aplicación ASP tendremos tantas sesiones como usuarios conectados a la aplicación ASP.

Las recomendaciones realizadas para el objeto Application en cuanto a utilización de objetos y variables de tipo array, son también válidas para el objeto Session.

La sintaxis para manipular variables del objeto Session es la misma que en el objeto Application. El Código fuente 39 crea una variable del objeto Session con el nombre que el usuario facilita en un formulario.

<%Session("nombreUsuario")=Request.Form("nombre")%>

Código fuente 39

Colecciones del objeto Session En la versión 1.0 de ASP el objeto Session ,al igual que ocurría con el objeto Application tampoco poseía ninguna colección, apareciendo en la versión de 2.0 ASP con dos nuevas colecciones con las mismas funciones que las del objeto Application pero a nivel de sesión claro:

• Contents: contiene todas las variables a nivel de sesión menos las creadas con al etiqueta <OBJECT>.

Page 57: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

57

• StaticObjects: contiene las variables de la sesión creadas con la etiqueta <OBJECT>.

Ambas colecciones nos van a permitir recuperar o acceder a las variables y objetos creados, en este caso, a nivel de sesión. La colección Contents contiene todos los objetos y variables creados a nivel de sesión, excluyendo a los objetos que han sido creados utilizando la etiqueta <OBJECT>.

En esta colección se incluirán, por tanto, los objetos creados a nivel de sesión con Server.CreateObject y las variables creadas con las sentencias del tipo Session("variable"). La colección StaticObjects contiene todos los objetos que se han creado mediante la etiqueta <OBJECT> dentro del alcance de la sesión.

Si suponemos que tenemos el fichero GLOBAL.ASA que aparece en el Código fuente 40.

<SCRIPT LANGUAGE="VBScript" RUNAT="Server">Sub Session_OnStart

Session("variableUno")="valor"Session("variableDos")=2Session("variableTres")=True

End Sub</SCRIPT><OBJECT RUNAT="Server" SCOPE="Session" ID="conex" PROGID="ADODB.Connection"></OBJECT><OBJECT RUNAT="Server" SCOPE="Session" ID="recordset" PROGID="ADODB.RecordSet"></OBJECT>

Código fuente 40

Si ahora se ejecuta una página con el Código fuente 41.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>Número de elementos de la colección Contents:<b><%=Session.Contents.Count%></b><br><%For Each variable in Session.Contents

Response.Write variable & " = "&Session.Contents(variable)&"<br>"Next%><br>Número de elementos de la colección StaticObjects:<b><%=Session.StaticObjects.Count%></b><br><%For Each objeto in Session.StaticObjects

Response.Write objeto&"<br>"Next%><br><%'accedemos la variable de aplicación definida con <OBJECT>conex.Open "DSN=BD;UID=sa;PWD="Response.Write "Base de datos predeterminada: "&conex.DefaultDatabaseconex.Close%></BODY></HTML>

Código fuente 41

Page 58: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

58

Se producirá este resultado:

Número de elementos de la colección Contents: 3variableUno = valorvariableDos = 2variableTres = Verdadero

Número de elementos de la colección StaticObjects: 2conexrecordset

Base de datos predeterminada: Cursos

Propiedades del objeto Session El objeto Session posee cuatro propiedades:

• SessionID: contiene la identificación de la sesión para el usuario. Cada sesión tiene un identificador único que genera el servidor al crearla. No se debe utilizar esta propiedad como clave de una tabla de una base de datos, ya que, al reiniciar el servidor Web, algunos de los valores de SessionID pueden coincidir con los generados antes de que se apagase el servidor. Es únicamente de lectura.

• Timeout: la propiedad Timeout especifica el intervalo de inactividad para el objeto Session en minutos. Si el usuario no actualiza o solicita una página durante ese intervalo, la sesión termina. El valor por defecto de esta propiedad es de 20 minutos, es decir, por defecto la sesión permanecerá inactiva 20 minutos. Una sesión se dice que está inactiva mientras el navegador cliente no realice una petición. El valor de esta propiedad se puede modificar dinámicamente a lo largo de la ejecución de la aplicación ASP.

• CodePage: indica la página de códigos de caracteres que va a ser utilizado. A esta propiedad se le puede asignar un valor entero par especificar la página de códigos que se va a utilizar. Así si queremos utilizar el juego de caracteres del alfabeto turco le asignaremos a esta propiedad el valor 1254 ( <% Session.CodePage = 1254 %>). Esta propiedad es también de lectura/escritura.

• LCID (Locale Identifier): propiedad de lectura/escritura, es una abreviatura estándar e internacional que identifica de forma única la localización de los sistemas. Esta localización determina la forma en la que se le da formato a las horas y fechas, como se tratan las cadenas de caracteres y los diferentes elementos del alfabeto. Así si queremos establecer la propiedad LCID para la región de Rusia, le debemos asignar a esta propiedad el valor 1049 ( <% Session.LCID = 1049 %> ).

Las últimas dos propiedades han sido incluidas con la versión 2.0 de ASP.

Se puede configurar si queremos utilizar el estado de sesión o no, mediante el Administrador de servicios de Internet.

Pulsamos sobre la aplicación con el botón derecho del ratón y seleccionamos la opción de menú propiedades, aparecerán las hojas de propiedades del directorio como se ve en la Figura 9.

Page 59: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

59

Figura 9

En el epígrafe denominado configuración de aplicación podemos observar un botón etiquetado como Configuración, si lo pulsamos aparece una nueva ventana de la que elegiremos la pestaña etiquetada como opciones de aplicación. Ver Figura 10. Desde esta hoja de propiedades podemos configurar algunos parámetros de nuestra aplicación ASP, entre ellos el que nos interesa, es decir, la posibilidad de habilitar o deshabilitar el estado de la sesión.

Figura 10

Page 60: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

60

Además podemos configurar la propiedad Timeout de la sesión y el lenguaje del intérprete de comandos por defecto. También podemos habilitar o deshabilitar el almacenamiento en búfer. Los valores que especifiquemos en esta pantalla se pueden sobreescribir desde el código ASP indicando los valores de las propiedades o directivas de procesamiento correspondientes

Métodos del objeto Session Este objeto posee un único método: el método Abandon. Al lanzar sobre el objeto Session el método Abandon, se destruyen todas las variables de la sesión y se liberan sus recursos, finalizando la misma. Si no se llama explícitamente al método Abandon, el servidor destruirá los objetos cuando la sesión caduque, atendiendo al valor de la propiedad Timeout.

La destrucción del objeto Session no se hará efectiva hasta que el servidor no haya terminado de ejecutar la página ASP. Por lo tanto las variables del objeto Session existirán mientras no se cargue otra página.

El servidor creará un nuevo objeto Session al abrir una nueva página ASP después de abandonar la sesión.

Eventos del objeto Session Al igual que ocurría en el objeto Application, el objeto Session objeto posee dos eventos: el inicio de sesión, Session_OnStart, y el fin de sesión Session_OnEnd.

El inicio de sesión se produce cuando el usuario carga la primera página se una aplicación ASP. Dentro de este evento se deberán indicar las acciones a llevar a cabo antes de que se cargue la primera página de una aplicación ASP.

Este evento se suele utilizar para inicializar las variables para toda la sesión, así por ejemplo, si la aplicación ASP va a manipular una serie de tablas de una base de datos, se podrá crear una conexión con la base de datos en el evento de inicio de sesión y almacenarla en el objeto Session para que esté disponible para ese usuario mientras su sesión permanezca activa.

También se puede utilizar para cargar una serie de variables que definan el perfil del usuario que se acaba de conectar.

El fin de la sesión, es decir, el evento Session_OnEnd, se puede producir porque se haya caducado la sesión al permanecer inactiva el tiempo indicado por su propiedad Timeout, o bien, se puede forzar mediante a una llamada al método Abandon.

Cuando el usuario cierra el navegador no se ejecuta el evento Session_OnEnd de forma inmediata, sino que se ejecutará cuando se cumpla el Timeout correspondiente, para la aplicación ASP es igual que el usuario se encuentre con la página cargada en el navegador sin realizar ninguna petición o que el usuario haya cerrado su sesión del navegador, lo que se tiene en cuenta es el tiempo de inactividad de la sesión del usuario.

Sin embargo una llamada a Session.Abandon lanza el evento Session_OnEnd de manera inmediata.

Al igual que ocurría con el objeto Application, los procedimientos para el tratamiento de estos eventos se deben incluir en el ya conocido fichero de aplicación GLOBAL.ASA.

Page 61: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

61

En el evento Session_OnEnd sólo están disponibles los objetos Application, Server y Session, y tampoco se puede utilizar el método MapPath del objeto Server. En el evento Session_OnStart se tiene acceso a todos los objetos integrados de ASP.

El objeto Server El objeto Server nos permite ampliar las capacidades de las páginas ASP mediante la posibilidad de la creación y utilización de objetos externos y componentes en el lenguaje de secuencias de comandos.

El objeto Server está diseñado para realizar tareas específicas en el servidor. Además de la posibilidad de instanciar componentes el objeto Server ofrece una serie de métodos muy útiles como pueden se los que permiten dar formato URL o HTML a cadenas de caracteres, los que modifican la línea de ejecución de un script de una página con la posibilidad de ejecutar distintas páginas, y también existe un método utilizado para el tratamiento de errores dentro de ASP, etc. Todos estos métodos los veremos en el presente capítulo.

En algunas definiciones del objeto Server se suele indicar también que nos permite acceder a los recursos del servidor, en cierto modo esto es correcto ya que para poder instanciar un componente debe encontrarse registrado en el servidor Web.

Propiedades del objeto Server El objeto Server posee una única propiedad ScriptTimeout que es de lectura/escritura. La propiedad ScriptTimeOut expresa en segundos el periodo de tiempo durante el que puede ejecutarse una secuencia de comandos (script) antes de que termine su intervalo de espera.

El intervalo de espera de la secuencia de comandos no tendrá efecto mientras haya un componente del servidor en proceso.

Las modificaciones sobre la propiedad ScriptTimeOut del objeto Server se aplican únicamente a la página actual. Puede ser interesante aumentar el valor de esta propiedad en el caso de páginas que tarden mucho tiempo en ejecutarse debido a su complejidad, ya que si las secuencias de comandos de una página tardan en ejecutarse más tiempo que el especificado en la propiedad ScriptTomeOut se producirá un error.

La propiedad ScriptTimeOut es una forma de evitar que el servidor Web se sobrecargue son páginas ASP que presentan tiempo de ejecución excesivo.

El valor por defecto que posee esta propiedad es de 90 segundos, el valor por defecto se puede modificar a través del Administrador de servicios de Internet para que sea aplicable a todas las páginas ASP que componen una aplicación ASP determinada, es decir, se puede definir un valor por defecto de la propiedad ScriptTimeout para cada aplicación ASP.

La forma de modificar el valor por defecto de la propiedad ScriptTimeout es acudiendo a las propiedades de la carpeta que contiene la aplicación ASP dentro del Administrador de servicios de Internet. Pulsamos el botón de Configuración y accedemos a la pestaña Opciones de la aplicación. En esta ventana podemos ver un parámetro denominado Tiempo de espera de archivo de comandos ASP, este será el parámetro que defina el valor predeterminado de la propiedad ScriptTimeout.

Page 62: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

62

Métodos del objeto Server Tiene los siguientes métodos:

• CreateObject: método por excelencia del objeto Server, crea una instancia de un componente. Este componente debe estar registrado en el servidor Web.

• HTMLEncode: devuelve una cadena codificada en HTML a partir de la cadena que se le pasa como parámetro.

• MapPath: devuelve la ruta física de una ruta virtual dada a través de una cadena en formato URL.

• URLEncode: devuelve una cadena a la que se le ha aplicado la codificación URL correspondiente a las cadenas de consulta (QueryString).

• URLPathEncode: devuelve una cadena a la que se le ha aplicado la codificación URL correspondiente a las cadenas de rutas.

• Execute: para la ejecución de la página actual y transfiere la ejecución a la página indicada. Una vez que ha finalizado la ejecución de la nueva página, la ejecución continúa en la página inicial.

• Transfer: finaliza la ejecución de la página actual y transfiere la ejecución a la página indicada por parámetro. Sin volver en ningún caso a la página original.

• GetLastError: devuelve una referencia al objeto ASPError que contiene la información detallada del último error que se ha producido.

Los cuatro últimos métodos han sido añadidos en la versión 3.0 de ASP.

El método más utilizado del objeto Server es, posiblemente, el método CreateObject. Este método permite la instanciación de componentes de servidor, para que a continuación sean manipulados por las secuencias de comandos de nuestras páginas ASP. Para crear una instancia de un componente de servidor se debe utilizar la sintaxis general del Código fuente 42.

Set nombreObjeto=Server.CreateObject(ProgID)

Código fuente 42

La palabra reservada Set siempre se debe utilizar en la instanciación de un objeto y ProgID es el nombre con el que está registrado el objeto en el servidor, el formato para ProgID es: [Fabricante.]Componente[.Versión].

Así por ejemplo el ProgID de el objeto Recordset del modelo de objetos de acceso a datos ActiveX Data Objects (ADO) es ADODB.Recordset.

La variable nombreObjeto debe tener un nombre distinto de cualquiera de los objetos integrados de ASP. Se puede destruir un objeto asignándole Nothing, con el Código fuente 43.De esta forma se libera la memoria ocupada por el objeto.

Page 63: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

63

<%Set nombreObjeto=Nothing%>

Código fuente 43

Las instancias de un objeto, por defecto, se destruyen cuando la página ASP termina de ser procesada, aunque es más seguro destruirlas mediante la palabra reservada Nothing.

Para crear un objeto con ámbito de sesión o de aplicación se debe almacenar el objeto en una variable de sesión o de aplicación, o bien utilizando la etiqueta de HTML <OBJECT> en el fichero global.asa y asignando al parámetro SCOPE los valores Session o Application, como vimos en el capítulo anterior. De esta forma el objeto se destruirá cuando haya finalizado la sesión o la aplicación.

No es demasiado recomendable utilizar objetos a nivel de sesión o aplicación, y si se utilizan se deben destruir cuanto antes, ya que pueden suponer una gran carga para la memoria del servidor Web. Es preferible crear y destruir un objeto varias veces que llevar su referencia almacenada en una variable de sesión o de aplicación.

El método MapPath devuelve la ruta física que se corresponde con el la ruta virtual que se le pasa por parámetro. El objeto Server posee información sobre los directorios físicos, virtuales y relativos de la máquina servidor y sabe como debe realizar la traducción de rutas virtuales a físicas.

Se puede necesitar obtener rutas físicas cuando se quieran crear directorios o manipular ficheros en el servidor. La forma más frecuente de utilizar este método es la del Código fuente 44, que devuelve la ruta física de la carpeta en que se encuentra la páigna ASP en ejecución.

nombreVariable=Server.MapPath(rutaVirtual)

Código fuente 44

Se recomienda por eficiencia evitar el uso del método MapPath, cada llamada a este método supone una nueva conexión al servidor Web para que IIS devuelva la ruta actual del servidor. En su lugar es más rápido utilizar la ruta literal, si se conoce.

Cuando tratamos el objeto Response en su capítulo correspondiente vimos que presentaba un método llamado Redirect que nos permitía pasar a ejecutar una página distinta, pero esto suponía enviar una respuesta al cliente para indicarle la carga de una nueva página, que es la página a la que pasamos la ejecución.

La utilización del método Redirect es bastante costosa y problemática ya supone un envío de información más del servidor al cliente para indicarle mediante una cabecera HTTP de redirección que la página ha cambiado de localización, siendo la nueva localización la página que deseamos cargar. Esto es problemático ya que en algunos navegadores como Netscape Communicator aparace un mensaje del tipo El objeto requerido se ha movido y se puede encontrar aquí, esto también ocurre cuando la conexión la realiza el cliente a través de proxy.

Pero mediante los métodos Execute y Transfer podemos evitar esta redirección, que como hemos visto, tiene lugar en el cliente. Estos dos métodos permiten que la redirección tenga lugar en el servidor, quedando el cliente completamente ajeno. Ambos métodos reciben como parámetro la ruta de la página a la que queremos redirigir al cliente.

Page 64: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

64

La utilización del método Execute es muy similar a realizar una llamada a un procedimiento o función. Cuando lanzamos el método Execute se empieza a ejecutar la página que indicamos por parámetro, y cuando termina la ejecución de esta nueva página, el control pasa a la siguiente sentencia después de la llamada al método Execute en la página inicial, siguiendo a partir de aquí con la ejecución de la página, es decir, el navegador del cliente recibe una salida formada por la combinación de la ejecución de ambas páginas.

El cliente ni siquiera observa la URL correspondiente a la segunda página, ya que la redirección entre páginas se produce en el servidor. El navegador cree que sigue recibiendo todavía la página original que habia demandado, incluso en la barra de direcciones del navegador sigue apareciendo la misma URL y los botones Atrás y Adelante funcionan correctamente.

En ambos métodos se mantiene el contexto de la página inicial, es decir, en la nueva página tenemos acceso a los mismos objetos intrínsecos de ASP (Request, Session, Response...) de la página inicial o página de origen. Es decir, la colección Request.Form de la segunda página coincide con la de la primera.

El método Transfer también permite la redirección entre páginas en el servidor, pero este método se comporta de distinto modo al método Execute, al lanzar este método se pasa la ejecución a la nueva página, pero una vez que finaliza la ejecución de la misma no se vuelve a la página inicial, como ocurría con el método Execute. El método Transfer es bastante más parecido al método Redirect que lo era el método Execute, ya que con Transfer al igual que con Redirect no se regresa a la página original.

Con el método Transfer se sigue manteniendo el contexto de la página inicial entre las distintas páginas. La única diferencia es que la ejecución finaliza cuando termina la ejecución de la segunda página, y no se vuelve a la inicial.

Mediante el uso del método GetLastError podemos tener acceso a toda la información referente al último error que se ha producido en la página ASP actual. Pero es necesario aclarar que su utilización no es similar al tratamiento de errores que realizábamos con la sentencia On Error Resume Next y el objeto Err de VBScritp, que preguntábamos por la propiedad Number del objeto Err para averiguar si se había producido algún error.

El método GetLastError se puede utilizar únicamente dentro de una página de error personalizada, es decir, cuando el error ya se ha producido y lo ha detectado el servidor Web.

Mediante el servidor Web Internet Information Server 5 podemos indicar las páginas de error personalizadas y es en estas páginas dónde podemos hacer uso de este método.

El método GetLastError devuelve un nuevo objeto del modelo de objetos de ASP llamado ASPError, son las propiedades de este nuevo objeto las que nos permiten acceder de forma detallada a toda la información referente al error que se ha producido.

El objeto ObjectContext Este objeto integrado se incluyó en la versión 2.0 de las páginas ASP. Este objeto se ofrece gracias a la integración que presentaban dentro de Windows NT el servidor Web IIS4 (Internet Information Server 4) con el servidor de transacciones MTS 2.0 (Microsoft Transaction Server).

A través del objeto integrado ObjectConext podremos tratar y gestionar las transacciones que se realicen en nuestras páginas ASP, pudiendo construir, por tanto, páginas ASP transaccionales.

Page 65: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

65

Esta integración entre el servidor Web y el servidor de transacciones sigue existiendo, pero ahora el servidor Web se encuentra en su nueva versión IIS5 y el servidor de transacciones ya no se denomina MTS sino que se encuentra integrado en lo que en Windows 2000 se denomina Servicios de componentes, se puede decir que IIS y los Servicios de componentes funcionan conjuntamente para formar la arquitectura básica para la creación de aplicaciones Web y para coordinar el proceso de transacciones para las aplicaciones ASP transaccionales.

A través del objeto ObjectConext podremos deshacer o llevar a cabo las transacciones gestionadas por los Servicios de componentes.

Recordemos que una transacción es una operación que se debe realizar de forma completa, es decir, si falla una parte de la transacción se deben deshacer todos los cambios. Un ejemplo típico de una transacción es la transferencia de una cuenta bancaria a otra, las operaciones de que implican restar el capital de una cuenta y añadirlo a otra se deben ejecutar dentro de una transacción, si falla alguna de las dos se debe devolver al sistema a su estado inicial. Las transacciones ofrecen una serie de características comunes conocidas como propiedades ACID (Atomicity, Consistency, Isolation, Durability).

Para indicar la naturaleza transaccional de una página ASP debemos incluir, como primera línea de la página, la directiva de procesamiento TRANSACTION, como en el Código fuente 45.

<%@ TRANSACTION = valor %>

Código fuente 45

Donde el argumento valor define el comportamiento transaccional de la página ASP actual y puede tomar uno de los siguientes valores:

• Requires_New: se requiere una nueva transacción, por lo que siempre se iniciará una nueva transacción para las páginas ASP con este valor. Esta configuración es recomendable para páginas que debe realizar transacciones pero que siempre deben estar separadas del resto.

• Required: se requiere una transacción, si no hay una iniciada, se iniciará una nueva. La página ASP siempre se ejecutará en una transacción ya sea iniciada por ella misma o bien aprovechando una transacción ya existente.

• Supported: soporta transacciones, pero no iniciará ninguna en el caso de que no exista. En algunos casos la página ASP se ejecutará en una transacción y en otros no, ya que sólo utiliza transacciones existentes.

• Not_Supported: no soporta transacciones, es el valor por defecto. La página ASP nunca participará en ningún tipo de transacción.

• Disabled: se ignorarán los requerimientos transaccionales de la página ASP. La diferencia con el caso anterior, es que con Not_Supported la página ASP siempre se ejecutará en un nuevo contexto, y con Disabled, si existe un contexto se utilizará el mismo.

A través del objeto ObjectContext podremos construir páginas ASP transaccionales, pero evidentemente, cuando se realicen operaciones que puedan tener una naturaleza transaccional, como puede ser el acceso a bases de datos. Además, una transacción no puede abarcar varias páginas ASP, a no ser que hagamos uso de los métodos Transfer o Execute del objeto Server, ya comentamos que con

Page 66: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

66

estos métodos de ejecución entre páginas se conserva el contexto de la página inicial, en este contexto se encuentra incluido las transacciones.

Hay que tener en cuenta, además, que la mayoría de las aplicaciones ASP sólo requieren hacer uso de un contexto transaccional en determinadas operaciones. Así por ejemplo, una aplicación de una Línea de Autobuses podría hacer uso de páginas ASP transaccionales para la venta de billetes y la reserva de asientos, dejando el resto de tareas fuera del contexto transaccional.

Métodos del objeto ObjectContext Para gestionar la transacción de una página ASP y poder indicar si se debe llevar a cabo la misma (commit) o bien se deben deshacer los cambios y volver al estado anterior (rollback) debemos hacer uso de los dos métodos del objeto ObjectContext.

En algún momento debemos determinar si las operaciones que debía realizar una página ASP se han realizado con éxito, y por tanto, se puede llevar a cabo la transacción correspondiente. Igualmente debemos disponer de algún método que nos permita anular una transacción en el caso de que falle alguna de las operaciones implicadas en la misma. Para ello disponemos de dos métodos del objeto ObjectContext:

• SetComplete: indica que se puede llevar a cabo la transacción correspondiente al realizarse con éxito las operaciones que debía llevar a cabo la página ASP. Es decir, una llamada a este método equivaldría a realizar un commit dentro de SQL Server o del gestor de bases de datos correspondiente.

• SetAbort: indica que algo ha fallado en las operaciones implicadas en la transacción, una llamada a este método cancela la transacción y deshace los cambios que se hayan podido realizar. Sería equivalente a realizar una llamada a RollBack en SQL Server.

En el caso de que finalice el procesamiento de la página ASP y no se haya realizado ninguna llamada a alguno de los dos métodos anteriores, se considerará que no se ha producido ningún problema en el procesamiento de la página y, por lo tanto, se llamará automáticamente al método SetComplete.

Eventos del objeto ObjectContext El objeto ObjectContext ofrece dos eventos que indican la forma en la que ha finalizado la transacción. Esto es bastante útil para obrar en consecuencia, es decir, si se ha abortado una transacción o se ha realizado con éxito se deberán hacer unas operaciones u otras. O si lo queremos podemos no utilizar estos eventos.

Los eventos del objeto ObjectContext se describen a continuación:

• OnTransactionCommit: este evento se dispara cuando se llevó a cabo de una transacción de manera satisfactoria con la llamada al método SetComplete.

• OnTransactionAbort: este evento se disparará tras la cancelación de una transacción con el método SetAbort.

El uso de estos dos eventos, nos permitirá realizar diferentes tratamientos según se haya finalizado la transacción, es decir, si se ha producido con éxito , o por el contrario se han producido errores y se ha tenido que deshacer.

Page 67: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 3. Modelo de objetos de ASP. Parte II

67

El objeto ASPError Este objeto es le nuevo objeto integrado que aparece en ASP 3.0. La función del objeto ASPError es la de ofrecer de forma detallada toda la información relativa al último error que se ha producido dentro de una aplicación ASP, describe el error que se ha producido, la naturaleza y fuente del mismo, y si es posible el código fuente que causó el error. Para ello el objeto ASPError consta de nueve propiedades de sólo lectura, y no ofrece ningún método.

Una referencia al objeto ASPError la obtenemos a través de un nuevo método del objeto Server, el método GetLastError que ya comentamos en el capítulo correspondiente, la sintaxis de este método es la del Código fuente 46.

Set objASPError=Server.GetLastError()

Código fuente 46

Ahora bien, el método GetLastError del objeto Server no se puede utilizar de forma indiscriminada en cualquier lugar de nuestro código para consultar si se ha producido un error, únicamente se puede utilizar de forma satisfactoria dentro de una página ASP de error personalizado.

Si desactivamos el tratamiento de errores predeterminado que presenta ASP mediante la sentencia On Error Resume Next, al igual que se hacia anteriormente para consultar la propiedad Number del objeto Error, e intentamos lanzar el método GetLastError para obtener una referencia al objeto ASPError, esta llamada fallará y el método no podrá acceder a los detalles del error que se ha producido.

Propiedades del objeto ASPError El objeto ASPError no ofrece ni eventos ni métodos únicamente ofrece propiedades y todas de lectura. Estas propiedades contienen la información detallada relativa al último error de ASP que se ha producido en una aplicación.

Las propiedades del objeto ASPError las consultaremos cuando se haya producido un error, cada una de ellas tiene un significado determinado que se pasa a exponer a continuación:

• ASPCode: un entero generado por IIS (Internet Information Server) y que representa un código de error de ASP.

• ASPDescription: una cadena que es una descripción detallada del error si está relacionado con ASP.

• Category: cadena que indica si se trata de una error interno de ASP, del lenguaje de secuencia de comandos o de un objeto.

• Column: entero que indica la posición de la columna del archivo ASP que generó el error.

• Description: cadena que contiene una breve descripción del error. Tiene el mismo significado que la propiedad Description del objeto Err.

• File: cadena que contiene el nombre del archivo ASP que se estaba procesando cuando se produjo el error.

Page 68: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

68

• Line: entero que se corresponde con el número de línea del archivo ASP que generó el error.

• Number: entero que representa un código de error estándar de COM. Tiene el mismo significado que la propiedad Number del objeto Err.

• Source: cadena que contiene el código fuente real, si está disponible, de la línea que causó el error.

Como se puede observar podemos obtener una información bastante más precisa que con el objeto Err de VBScript.

Page 69: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Componentes de Servidor

Introducción Hemos visto los componentes integrados dentro de ASP y que forman parte del modelo de objetos de ASP y los componentes que ofrece el motor de secuencias de comandos de ASP contiene una serie de componentes que ofrecen una serie de funciones que liberan al programador de implementarlas, estas funciones pueden ser tareas comunes que se deban realizar dentro de un desarrollo en el entorno Web. Estos componentes están diseñados para ejecutarse en el servidor Web como parte de una aplicación basada en ASP.

Estos componentes se denominan componentes ActiveX Server o componentes de servidor, y anteriormente eran conocidos como servidores de automatización. Los componentes ActiveX Server se invocan desde páginas ASP (en nuestro caso), pero también pueden ser llamados desde otros orígenes, como por ejemplo aplicaciones ISAPI, desde otro componente de servidor o desde otros lenguajes OLE compatibles.

Los componentes de servidor son ficheros DLL que se ejecutan en el mismo espacio de direcciones de memoria que las páginas ASP y el servidor Web Internet Information Server.

Los componentes ActiveX Server que se encuentran incluidos dentro de ASP en su versión 3.0 y que se van a comentar en este tema son:

• Componente de acceso a bases de datos, ADO (ActiveX Data Objects). A través de la utilización de este componente se puede ofrecer acceso a bases de datos desde una página ASP, así por ejemplo, se puede mostrar el contenido de una tabla, permitir que los usuarios realicen consultas y otras operaciones sobre una base de datos.

Page 70: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

70

• Componente Ad Rotator. Este componente permite mostrar una serie de imágenes alternativas con un vínculo a otra dirección desde la imagen presentada. Este componente se suele utilizar para mostrar diferentes anuncios de forma alternativa dentro de una página ASP.

• Componente Funciones del explorador. A través de este componentes podemos recuperar datos acerca del tipo de navegador del cliente y que capacidades o funciones tiene.

• Componente vínculo de contenidos. Facilita el desplazamiento lógico entre las diferentes páginas ASP de una aplicación ASP.

• Componente Content Rotator (rotador de contenidos). Este componente permite hacer rotaciones de cadenas de contenido HTML en una página.

• Componente Page Counter (contador de páginas). Permite llevar una cuenta del número de veces que se ha accedido a una página determinada dentro de nuestro sitio Web.

• Componente Counters. A través de este componente podremos almacenar, crear, incrementar y consultar cualquier contador.

• Componente MyInfo. Nos permite almacenar información personal que será ofrecida por el administrador del sitio Web.

• Componente Tools. Es el denominado componente de utilidades. Ofrece una serie de funciones diversas, como la generación de números aleatorios o la comprobación de la existencia de un fichero en el servidor.

• Componente Permission Checker. A través de este componente podremos determinar si a un usuario se le ha dado permisos para acceder a un fichero determinado.

• Componente Status. Este componente, de momento, únicamente está disponible para el servidor Personal Web Server en plataformas Macintosh, resulta extraño pero es así. Nos ofrece una información variada acerca del estado del servidor Web.

• Componente de registro de IIS. Mediante este componente tenemos acceso a la información y manipulación de los ficheros de registro (log) generados por el servidor Web IIS 5.0.

Para poder utilizar un componente de servidor dentro de una página ASP debemos instanciarlo, para ello deberemos utilizar el método CreateObject del objeto Server de la misma forma que lo hacíamos con los componentes de VBScript.

También se puede crear una instancia de un componente de servidor a través de la etiqueta <OBJECT> de HTML, como ya vimos en el tema anterior

La diferencia entre los dos mecanismos es desde el punto de vista de la eficiencia. Cuando se instancia un objeto con el método Server.CreateObject se crea inmediatamente el objeto, aunque no lo lleguemos a utilizar, sin embargo, si instanciamos el objeto con la etiqueta <OBJECT> el objeto sólo se creará en el momento que lo vayamos a utilizar por primera vez.

A lo largo de los siguientes apartados del presente capítulo vamos a ir comentando los distintos componentes de servidor que se ofrecen junto con la instalación de ASP.

Page 71: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

71

Componente AdRotator Este componente de servidor se encarga de rotar una serie de anuncios (imágenes) dentro de una página ASP. Cada vez que un usuario vuelva a cargar la página el componente AdRotator mostrará una imagen con una URL asociada, atendiendo a un fichero especial denominado fichero de planificación.

Una de las características de HTML es que permite la creación de imágenes con vínculos. La etiqueta HTML que permite visualizar una imagen en una página es la etiqueta <IMG>. El componente AdRotator genera una etiqueta <IMG> a la que le asigna también una URL, al pulsar sobre la imagen se redireccionará al usuario hacia la URL asociada a esa imagen. Para llevar a cabo este proceso el componente AdRotator se sirve de dos ficheros: el fichero de redireccionamiento y el de planificación.

El fichero de redireccionamiento es una página ASP que debemos crear si queremos utilizar este componente. Este fichero suele incluir secuencias de comandos para analizar la cadena de consulta enviada por el componente AdRotator y para redirigir al usuario a al dirección URL asociada con el anuncio sobre el que se ha pulsado. En el Código fuente 47,el fichero de redirección simplemente redirige al usuario a la página del anunciante.

<%Response.Redirect(Request.QueryString("url"))%>

Código fuente 47

Dentro de la colección QueryString, en este caso, podemos encontrar dos variables: url, que indica la URL que tiene asociada la imagen e image, que indica el nombre de la imagen sobre la que se ha pulsado.

Como ya se había comentado con anterioridad, dentro del fichero de redireccionamiento también podemos realizar otras tareas además de redireccionar al navegador a una dirección determinada. Con el Código fuente 48 que se muestra a continuación se consigue saber el número de usuarios que pulsan sobre un anuncio determinado. En este código aparece un par de componentes de VBScript como son el objeto FileSystemObject y TextStream, que nos permiten leer y escribir en un fichero del servidor en el que vamos a almacenar el número de usuarios que han pulsado sobre el anuncio número dos.

<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\scrrun.dll"--><%'Cuenta el número de usuarios que han pulsado sobre un anuncio determinado'el fichero de pulsaciones está en este caso en el mismo directorio'que la página ASP de redirecciónnombreFichero=Server.MapPath("pulsaciones.txt")if Request.QueryString("image")="/cursoASP30/images/Anuncio2.gif" Then

Set objFSO= Server.CreateObject("Scripting.FileSystemObject")If objFSO.FileExists(nombreFichero) Then

'Se abre el fichero para su lecturaSet objTextStream=objFSO.OpenTextFile(nombreFichero)pulsaciones=CInt(objTextStream.ReadLine)pulsaciones=pulsaciones+1objTextStream.Close

Elsepulsaciones=1

End IfSet objTextStream=objFSO.OpenTextFile(nombreFichero,ForWriting,True)objTextStream.WriteLine pulsacionesobjTextStream.CloseSet objFSO=Nothing

Page 72: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

72

End ifResponse.Redirect(Request.QueryString("url"))%>

Código fuente 48

En la sentencia if...Then... se consulta la variable image de la colección QueryString del objeto Request, para comprobar si contiene el nombre del fichero de imagen del segundo anuncio. Si es el anuncio número dos, se lee del fichero el número actual de usuarios que lo han pulsado y se actualiza este número incrementándolo en uno.

Este es un ejemplo muy básico, por que si dos usuarios pulsan a la vez sobre el anuncio número dos uno de ellos no se contará. Para evitar este problema se debería guardar el objeto que representa al fichero dentro de una variable del objeto Application, y al ir a utilizar esta variable lanzar sobre el objeto Application los métodos Lock y UnLock.

El fichero de planificación contiene información utilizada por el componente AdRotator para administrar y mostrar las diversas imágenes de los anuncios. En él se especifican los detalles de los anuncios como puede ser tamaño, imagen a utilizar, URL asociada, frecuencia de aparición de cada imagen.

Este fichero tiene un formato determinado que se pasa a comentar a continuación. Se encuentra dividido en dos secciones mediante un asterisco (*). La primera sección establece los parámetros aplicables a todas la imágenes de los anuncios existentes, y la segunda sección especifica la información de cada imagen individual y el porcentaje de tiempo de presentación de cada anuncio.

En la primera sección hay cuatro parámetros opcionales y globales, si no se especifica ninguno de estos parámetros la primera línea del archivo debería empezar por un asterisco. El formato general del fichero de planificación es el siguiente:

REDIRECT urlWIDTH anchoHEIGHT altoBORDER borde*Fichero que contiene la imagenUrl asociadaTexto alternativoNúmero de impactos

La primera línea, REDIRECT url, indica el fichero (página ASP) que implementa el redireccionamiento, es decir, indica cual es el fichero de redireccionamiento. Las tres líneas siguientes, pertenecientes a la primera sección del fichero de planificación, hacen referencia al aspecto de la imagen: dimensiones y borde.

En la segunda sección tenemos la ubicación del fichero gráfico que representa la imagen a mostrar, a continuación está la URL a la que será enviado el navegador cuando el usuario pulse sobre la imagen, esta URL será la dirección del anunciante, por ejemplo; si el anuncio no tiene ningún vinculo asociado se deberá escribir un guión (-).

La siguiente línea contiene el texto alternativo que aparecerá cuando el navegador no esté habilitado para cargar imágenes o bien el texto que aparecerá cuando el cursor del ratón se sitúe sobre la imagen, el equivalente a la propiedad ALT de la etiqueta <IMG>. Por último se debe indicar el número relativo de apariciones del anuncio.

Page 73: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

73

En el Código fuente 49 se va a mostrar y comentar un ejemplo de un fichero de planificación para un componente Ad Rotator.

Redirect redirecciona.aspBORDER 0*

/cursoASP30/images/Anuncio1.gifhttp://www.almagesto.comCampus Virtual Almagesto40/cursoASP30/images/Anuncio2.gifhttp://www.eidos.esSitio Web del Grupo EIDOS30/cursoASP30/images/Anuncio3.gifhttp://www.eidos.es/algoritmoRevista Algoritmo30

Código fuente 49

En este ejemplo el fichero encargado de redireccionar al navegador a la dirección asociada a la imagen que se ha pulsado es la página ASP redirecciona.asp. Al no especificarse las dimensiones de la imagen, se tomarán los valores por defecto: WIDTH=440 y HEIGHT=60. Se han utilizado tres imágenes, cuya frecuencia de aparición será: para la primera un 40% de las veces que se cargue la página, para la segunda un 30% y para la tercera otro 30%.

El componente AdRotator además de estos dos ficheros especiales que ya se han comentado, posee también tres propiedades y un método. Sus propiedades son las siguientes:

• Border: indica el tamaño del borde que rodea a la imagen del anuncio, cumple la misma función que la línea BORDER del fichero de planificación.

• Clickable: indica si el anuncio es un hipervínculo o no, tendrá los valores True o False, respectivamente.

• TargetFrame: esta propiedad especifica el marco de destino en el que se debe cargar el vínculo. Esta propiedad realiza la misma función que el parámetro TARGET de una instrucción HTML de creación de vínculos.

El único método que posee este componente ActiveX de servidor es el método GetAdvertisement. A este método se le debe pasar como parámetro el nombre del fichero de planificación, y la función de este método es la de obtener las especificaciones, a partir del fichero de planificación, para el siguiente anuncio y le da formato de código HTML.

Para crear un componente AdRotator cuyo fichero de planificación se llama planificacion.txt se deberá escribir el Código fuente 50.

<%Set anuncios=Server.CreateObject("MSWC.AdRotator")%><%=anuncios.GetAdvertisement("planificacion.txt")%>

Código fuente 50

Page 74: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

74

Con el método GetAdvertisement siempre debemos utilizar los delimitadores <%=%> o bien Response.Write, para enviar al navegador el código HTML encargado de mostrar la imagen correspondiente con su vínculo asociado.

Si tenemos en cuenta el código anterior y su fichero de planificación, una posible generación de código HTML por parte del método GetAdvertisement, podría ser la que se muestra en el Código fuente 51.

<A HREF="redirecciona.asp?url=http://www.eidos.es&image=images/Anuncio2.gif"><IMG SRC="/cursoASP30/images/Anuncio2.gif" ALT="Sitio Web del Grupo EIDOS"WIDTH=440 HEIGHT=60 BORDER=0></A>

Código fuente 51

En la Figura 11 se puede observar como se relaciona el componente AdRotator con todos los ficheros que utiliza.

Figura 11

Componente Funciones del navegador El componente de funciones del navegador (Browser Capabilities) permite consultar las funciones que posee el navegador Web que ha cargado la página ASP.

Cuando un navegador se conecta a un servidor Web, le envía automáticamente un encabezado HTTP llamado User Agent. Este encabezado es una cadena que identifica el explorador y su número de versión.

El componente encargado de comprobar las funciones del navegador compara el encabezado User Agent con las entradas de un fichero especial llamado Browscap.ini. Para crear una instancia de este componente deberemos escribir lo que se muestra en el Código fuente 52.

Page 75: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

75

<%Set navegador=Server.CreateObject("MSWC.BrowserType")%>

Código fuente 52

El fichero Browscap.ini es un fichero de texto que asigna las propiedades del navegador atendiendo al encabezado HTTP User Agent, este fichero se debe encontrar en el mismo directorio que la librería que contiene al componente, es decir, el fichero BROWSCAP.DLL.

Si se encuentra coincidencia entre el encabezado User Agent y una entrada del fichero BROWSCAP.INI, el componente asumirá las propiedades del navegador de la lista que coincida con el el encabezado User Agent.

Si el componente no encuentra una coincidencia entre el encabezado User Agent y una entrada del fichero BROWSCAP.INI, toma las propiedades predeterminadas del navegador Web. Pero si dentro de BROWSCAP.INI no se han especificado estas propiedades predeterminadas se establecerá la cadena UNKNOWN para las propiedades del navegador.

Dentro del fichero BROWSCAP.INI se pueden realizar definiciones de propiedades para diferentes navegadores, también se pueden establecer valores predeterminados para utilizarlos si el navegador no pertenece a ninguna de las definiciones existentes.

Para cada definición de navegador se debe proporcionar un valor del encabezado User Agent y las propiedades y valores que se desea asociar a ese encabezado. El formato general de este fichero es el siguiente:

;comentarios[EncabezadoHTTPUserAgent]parent = DefiniciónExploradorpropiedad1 = valor1

propiedadN = valorN[Default Browser Capability Settings]PropiedadPredeterminada1 = ValorPredeterminado1

PropiedadPredeterminadaN = ValorPredeterminadoN

Dentro de este fichero los comentarios se indicarán con punto y coma. El encabezado User Agent puede contener comodines utilizando el carácter * para reemplazar cero o más caracteres. Por ejemplo si escribimos el siguiente valor para el encabezado User Agent:

[Mozilla/2.0 (compatible; MSIE 3.0;* Windows 95)]

Coincidiría con los siguientes encabezados User Agent:

[Mozilla/2.0 (compatible; MSIE 3.0; Windows 95)][Mozilla/2.0 (compatible; MSIE 3.0; AK; Windows 95)][Mozilla/2.0 (compatible; MSIE 3.0; SK; Windows 95)][Mozilla/2.0 (compatible; MSIE 3.0; AOL; Windows 95)]

Si se dan varias coincidencias, el componente devolverá las propiedades de la primera definición coincidente.

Mediante la propiedad parent, podemos utilizar dentro de una definición de un navegador todos los valores de las propiedades de otro navegador cuyo nombre se indica en DefinicionExplorador. La

Page 76: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

76

definición del navegador actual heredará todas las propiedades declaradas en la definición del navegador principal. Esto es útil para definir propiedades de una nueva versión de un navegador, ya que las nuevas versiones suelen conservar la mayoría de las propiedades de la versión anterior. Estos valores de propiedades heredados se pueden sobreescribir estableciendo un nuevo valor para esa propiedad.

El número de propiedades a definir puede ser cualquiera, las únicas restricciones es que el nombre de la propiedad debe comenzar por un carácter alfabético y no puede tener más de 255 caracteres. Normalmente para cada tipo de navegador solamente se definirán las propiedades que vayan a ser utilizadas. El valor que se le asignará a la propiedad por defecto es una cadena, si se quiere asignar un entero se deberá utilizar el signo de número (#) y para especificar un valor booleano se utilizará TRUE o FALSE.

Con el valor de User Agent [Default Browser Capability Settings] se especifican las propiedades por defecto de un navegador cuya cabecera User Agent no ha coincidido con ninguna de las especificadas en el fichero BROWSCAP.INI.

Se debe realizar un mantenimiento del fichero BROWSCAP.INI para tenerlo actualizado con las nuevas versiones de navegadores Web que van apareciendo. Existen un par de direcciones que ofrecen la última versión de este fichero: http://www.cyscape.com/browscap y http://www.asptracker.com.

En el Código fuente 53 se crea un componente defunciones del navegador y se muestran por pantalla algunas de las características del navegador del cliente. Si en el servidor Web tenemos el fichero BROWSCAP.INI como se ve en el Código fuente 54.

<%Response.Write("La Cabecera USER_AGENT enviada por el navegador es: "&_Request.ServerVariables("HTTP_USER_AGENT")&"<br>")Set navegador=Server.CreateObject("MSWC.BrowserType")if navegador.vbscript=TRUE Then Response.Write("Soporta VBScript<br>")if navegador.cookies=TRUE Then Response.Write("Soporta Cookies<br>")if navegador.beta=FALSE Then Response.Write("No es una beta<br>")if navegador.javaapplets=TRUE Then Response.Write("Soporta Java<br>")Response.Write("Plataforma: "&navegador.platform&"<br>")Response.Write("Navegador: "&navegador.browser&navegador.version&"<br>")%>

Código fuente 53

;Internet Explorer 4.0[IE 4.0]browser=IEVersion=4.0cookies=TRUEvbscript=TRUEjavascript=TRUEjavaapplets=TRUEActiveXControls=TRUEWin16=Falsebeta=False

[Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)]parent=IE 4.0Version=4.01platform=Win95

Código fuente 54

Page 77: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

77

Si el navegador que se conecta es el Internet Explorer y envía la cabecera User Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 95), el resultado de la ejecución del Código fuente 53 sería:

La Cabecera USER_AGENT enviada por el navegador es:Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)

Soporta VBScriptSoporta CookiesNo es una betaSoporta JavaPlataforma: Win95Navegador: IE4.01

Pero si el navegador que se conecta envía otra cabecera diferente, el navegador no será reconocido y por lo tanto todas las propiedades se establecerán como UNKNOWN, y la salida que devolverá la ejecución del ejemplo anterior sería:

La Cabecera USER_AGENT enviada por el navegador es: Mozilla/4.03[es] (Win95; I)

Plataforma: UnknownNavegador: UnknownUnknown

Componente Nextlink Este componente llamado también componente de vinculación de contenido, tiene como misión gestionar un conjunto de direcciones URL para poder utilizarlas dentro de páginas ASP de forma sencilla, permite tratar las páginas como las de un libro, es decir, ofrece la gestión de una navegación entre las diferentes páginas ASP de una forma sencilla.

Se debe tener en cuenta que el componente de Vinculación de Contenido trata un sitio Web como si fuera un libro que debe ser leído desde el principio al final. Sin embargo este no es el comportamiento natural de un sitio Web, ya que su distribución no es lineal, por lo tanto esta herramienta puede ser necesaria para guiar al usuario a través de un sitio Web, es decir es una herramienta lineal para un espacio no lineal.

El componente Nextlink hace referencia a un fichero especial llamado lista de vínculos, este fichero contiene una lista de las direcciones de las páginas vinculadas, este fichero se debe encontrar en el servidor Web.

El fichero de lista de vínculos contiene una línea de texto por cada dirección URL de la lista. Cada línea termina con un retorno de carro y cada elemento de una línea se separa mediante un tabulador. Los vínculos a las páginas que aparece en este fichero deben estar en el orden deseado, como si fuera un libro. El formato de este fichero es el siguiente:

URL-Página-Web descripción

No se admiten URLs absolutas, es decir, las que comienzan con "http:","//" o \\. Las URLs utilizadas deben ser relativas con el formato nombreFichero o directorio/nombreFichero.

Cuando se debe modificar el orden o el número de las páginas de contenido, sólo es necesario actualizar la lista de URLs que se encuentra dentro del fichero lista de vínculos y no se tiene que actualizar los vínculos de exploración de cada página. Una ejemplo de un fichero de lista de vínculos podría ser el siguiente:

Page 78: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

78

intro.asp Introducción a ASPcap1.asp VBScriptcap2.asp Objetos Integradoscap3.asp Componentes ActiveX Server

Para tener acceso a las URLs que aparecen especificadas dentro del fichero lista de vínculos, el objeto Nextlink ofrece una serie de métodos:

• GetListCount(fichero): devuelve el número de vínculos del fichero lista de vínculos.

• GetNextURL(fichero): obtiene la siguiente URL teniendo en cuenta la página actual. Si la página actual no está especificada en dicho fichero, GetNextURL devuelve la dirección URL de la última página de la lista.

• GetPreviousDescription(fichero): este método devuelve la descripción del elemento anterior del fichero lista de vínculos, atendiendo a la página actual. Si la página actual no está en el fichero, se devolverá la descripción del primer elemento de la lista.

• GetListIndex: devuelve el índice que corresponde a la página actual dentro del fichero lista de vínculos. La primera página tendrá el índice 1. Si la página actual no existe dentro de la lista de vínculos se devolverá 0.

• GetNthDescription(fichero, indice): devuelve la descripción correspondiente al elemento de la lista de vínculos cuyo índice coincide con el índice que se le pasa como parámetro a este método.

• GetPreviousURL(fichero): obtiene la URL anterior teniendo en cuenta ja página actual. Si la página actual no está especificada en dicho fichero, GetPreviousURL devuelve la dirección URL de la primera página de la lista de vínculos.

• GetNextDescription(fichero): este método devuelve la descripción del siguiente elemento del fichero lista de vínculos, atendiendo a la página actual. Si la página actual no está en el fichero, se devolverá la descripción del último elemento de la lista de vínculos.

• GetNthUTL(fichero, indice): devuelve la dirección URL correspondiente al elemento de la lista de vínculos cuyo índice coincide con el índice que se le pasa como parámetro a este método.

Todos estos métodos poseen un parámetro común que indica la ubicación del fichero lista de vínculos con el que debe trabajar un componente de vinculación de contenido.

En el Código fuente 55 se muestra como se utilizaría este componente para indicar en un página un enlace a la página siguiente, anterior y para volver a la primera página:

<div align="center"><hr><%Set vinculos=Server.CreateObject("MSWC.NextLink")

listaVinculos="vinculos.txt"If (vinculos.GetListIndex(listaVinculos) > 1) Then %>

<a href="<%=vinculos.GetPreviousURL(listaVinculos)%>">Páginaanterior</a>&nbsp;<%End If%><%If (vinculos.GetListIndex(listaVinculos)<vinculos.GetListCount(listaVinculos))Then%>

<a href="<%=vinculos.GetNextURL(listaVinculos)%>">Página siguiente</a>&nbsp;

Page 79: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

79

<%End If%><a href="<%=vinculos.GetNthURL(listaVinculos,1)%>">Volver Inicio</a></div>

Código fuente 55

Para comprobar si es necesario crear un enlace a la página anterior se verifica que la página actual no es la primera, esta comprobación se realiza en el primer If...Then..., y en el segundo If se comprueba si es necesario crear un enlace a la página siguiente, para ello se comprueba si la página actual es la última o no comparando el valor devuelto por el método GetListIndex con el devuelto por GetListCount.

Para realizar el enlace a la página anterior se utilizará el método GetPreviousURL, para crear el enlace a la página siguiente se utiliza GetNextURL y para el enlace de la página de inicio se utiliza el método GetNthURL pasándole como parámetro el índice con valor 1.

Este código lo podemos escribir en una página llamada pie.asp y realizar un INCLUDE en las páginas correspondientes para que muestren en la parte inferior esta sencilla barra de navegación. El aspecto sería el de la Figura 12.

Figura 12

En el capítulo de introducción de la lista de vínculos del ejemplo nos puede interesar mostrar un índice de todo el curso. En el Código fuente 56 se muestra como se crearía una tabla de contenidos a partir del fichero lista de vínculos de un componente Nextlink.

<%Set vinculos=Server.CreateObject("MSWC.NextLink")listaVinculos="vinculos.txt"num=vinculos.GetListCount(listaVinculos)i=1%>Índice:<ul><%While (i<=num)%>

<li><a href="<%=vinculos.GetNthURL(listaVinculos,i)%>"><%=vinculos.GetNthDescription(listaVinculos,i)%></a>

Page 80: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

80

</li><%i=i+1%>

<%Wend%>

Código fuente 56

Para recorrer el fichero lista de vínculos es necesario obtener el número de URLs que existen en el fichero, es decir, el número de enlaces, para ello utilizamos el método GetListCount, para acceder a cada elemento del fichero deberemos utilizar un bucle While. Dentro de este bucle se lanza el método GetNthURL, para obtener la URL cuyo índice se corresponde con el valor del contador del bucle, también se lanza el método GetNthDescription para obtener la descripción correspondiente.

El aspecto que se correspondería con el ejemplo de fichero de vínculos anterior sería el de la Figura 13.

Figura 13

Componente Content Rotator Este es uno de los componentes de servidor que se incluyó con la versión 2.0 de ASP. Su finalidad es similar al componente Ad Rotator (rotador de anuncios) que ya habíamos comentado en este capítulo.

Pero este nuevo componente no permite sólo alternar diferentes imágenes con enlaces atendiendo a una determinada frecuencia, sino que permite mostrar cualquier contenido HTML que irá apareciendo atendiendo a la frecuencia establecida en el fichero de planificación correspondiente, al igual que ocurría con la frecuencia asignada a las imágenes del componente AdRotator.

Page 81: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

81

El fichero de planificación para este componente es un fichero de texto que debe estar disponible en una ruta virtual del servidor Web y puede incluir cualquier número de entradas de cadenas de contenido HTML, por ello también se le denomina fichero de contenido.

Cada entrada se compone de dos partes: una línea que empieza por dos signos de porcentaje (%%) seguida, de manera opcional, por un número entre 0 y 65.535 que indica el peso relativo de la cadena de contenido HTML y unos comentarios acerca de la entrada.

La segunda parte de la entrada contiene la cadena de contenido HTML propiamente dicha (texto, imágenes, hipervínculos...).

La sintaxis de estas entradas sería:

%% [#Peso] [//Comentarios]CadenaContenido

En el Código fuente 57 se ofrece un ejemplo de fichero de planificación para el componente Content Rotator.

%% 2 // Esta es la primera línea del fichero de contenidos.<A HREF = "http://www.eidos.es"><img src="images/eidosportada.jpg"></A>%% 4 // Segunda Línea.<B>Cursos - Internet</B>

<UL>

<LI>Programación de aplicaciones para Internet con ASP.<LI>Lenguaje HTML.<LI>La Especificación CGI.<LI>JavaScript.

</UL>

Código fuente 57

La probabilidad de que el objeto presente una determinada cadena de contenido se expresa como el peso asociado a dicha cadena dividido por la suma de todos los pesos de las distintas entradas del fichero de contenido.

Así, para el fichero de ejemplo, el componente Content Rotator presentará la primera cadena de contenido una tercera parte del tiempo, y la segunda las dos terceras partes del tiempo.

Un peso 0 hará que se pase por alto la entrada, y si no se especifica peso para una entrada determinada se asume que su peso es 1.

El componente Content Rotator, para recuperar las cadenas de contenido del fichero de planificación, dispone de dos métodos:

• ChooseContent(fichero): recupera una cadena de contenido HTML del archivo de contenidos y la presenta en la página actual. Este método recuperará una nueva cadena de contenido cada vez que se cargue la página.

• GetAllContent(fichero): recupera todas las cadenas de contenido del archivo de contenidos y las escribe directamente en la página como una lista con una etiqueta <HR> después de cada entrada.

Page 82: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

82

En el Código fuente 58 vamos a ver un ejemplo de cómo se recuperaría el contenido del fichero CONTENIDO.TXT, haciendo uso del método ChooseContent().

<%Set objContenido = Server.CreateObject("MSWC.ContentRotator")%>

<%=objContenido.ChooseContent("contenido.txt")%>

Código fuente 58

Cada vez que el usuario ejecute la secuencia de comandos anterior, se visualizará una de las dos cadenas de contenido HTML incluidas en el fichero de planificación CONTENIDO.TXT, como se ve en la Figura 14.

Figura 14

En el Código fuente 59 podemos ver otro ejemplo haciendo uso del método GetAllContent para representar todas las cadenas de contenido incluidas en el fichero CONTENIDO.TXT.

<B>Cadenas de contenido HTML incluidas en "contenido.txt":</B>

<%Set objContenido = Server.CreateObject("MSWC.ContentRotator")%>

<%=objContenido.GetAllContent("contenido.txt")%>

Código fuente 59

El resultado de la ejecución de la secuencia de comandos anterior sería el mostrado en la Figura 15.

Page 83: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

83

Figura 15

Componente Pagecounter Este componente nos permite llevar la cuenta del número de veces que una página Web ha sido abierta. El componente guarda el número de visitas que se han realizado en una página determinada y lo almacena periódicamente en un archivo de texto.

Al guardarse la cuenta de visitas por página en un fichero de texto, si por ejemplo se resetea el servidor los datos no se perderán. Este fichero de texto se llama HITCNT.CNT y se encuentra en el directorio c:\winnt\system32\inetsrv\data, un ejemplo de contenido de este fichero es:

21 /cursoasp30/pagecounter.asp5 /cursoasp30/adrot.asp0 adrot.asp12 /cursoasp30/page/visitas.asp3 /cursoASP30/page/adrot.asp2 /cursoASP30/page/pagecounter.asp0 /cursoASP30/page/Rec.asp

El fichero HITCNT.CNT se creará o actualizará cuando se ejecute el evento Application_OnEnd del fichero GLOBAL.ASA de la aplicación ASP correspondiente.

Este componente también fue incluido con la versión 2.0 de ASP.

El componente contador de páginas se instancia de la forma que indica el Código fuente 60.

Page 84: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

84

<%Set ObjetoContador = Server.CreateObject("MSWC.PageCounter")%>

Código fuente 60

Los métodos de los que dispone el objeto Page Counter son los que se comentan a continuación:

• Hits(rutapagina): devuelve un valor LONG representado el número de veces que se ha abierto una página Web determinada. Este método puede recibir como parámetro la ruta de la página a la que se le va a llevar la cuenta. Si se omite este parámetro el método devolverá el número de visitas de la página actual.

• PageHit(): Incrementa el número de visitas a la página actual. Sintaxis.

• Reset(rutapagina): Pone a 0 el número de visitas de la página cuya ruta se le pasa como parámetro. Si no se especifica ninguna página en el parámetro, se pondrá a 0 el número de visitas de la página actual.

En el Código fuente 61 un ejemplo del uso de este componente en el que nos vamos a fabricar un contador de visitas para la página actual. Guardaremos la página como CONTADOR.ASP:

<% Set Contador = Server.CreateObject("MSWC.PageCounter")%><b>Número de visitas:<%=Contador.Hits%><%Contador.PageHit 'incrementamos el contador en uno cada vez que se cargue lapágina%>

Código fuente 61

En cualquier momento, desde otra página podremos conocer el número de visitas de la página anterior. Suponiendo que dicha página se encuentra en la ruta virtual "/CursoASP30/pagecounter.asp", visualizaríamos su número de visitas como se indica en el Código fuente 62.

<b>El número de visitas de la página Contador.asp es:<%=Contador.Hits("/CursoASP30/pagecounter.asp")%>

Código fuente 62

La ruta que se indica en los métodos Hits() y Reset() del objeto PageCounter debe iniciarse siempre con /, es decir, debe partir desde la raíz del sitio Web. Si queremos registrar las visitas realizadas a todas las páginas ASP mediante este componente, podemos construirnos la página ASP que se muestra en el Código fuente 63, que se utilizaría como un INCLUDE en todas las páginas.

<%Set Contador=Server.CreateObject("MSWC.PageCounter")Contador.PageHitSet Contador=Nothing%>

Código fuente 63

Page 85: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

85

Siguiendo este ejemplo vemos que sería muy fácil realizar una página ASP que contenga una tabla informativa de las visitas que han recibido todas las páginas del Web con contadores de un sitio Web determinado.

En este nuevo ejemplo del objeto Page Counter vamos a mostrar el número de visitas que han tenido las páginas contenidas en un directorio determinado de nuestro sitio Web. Para ello vamos hacer uso de los ya conocidos componentes de acceso al sistema de ficheros. Veamos el Código fuente 64 de este página.

<%strDirectorio="/cursoASP30/page"'creamos un objeto PageCounterSet Contador = Server.CreateObject("MSWC.PageCounter")'en esta mismo página también se registran sus visitasContador.PageHitSet objFSO=Server.CreateObject("Scripting.FileSystemObject")'obtnemos una refencia a la carpeta dónde están las páginasSet objFolder=objFSO.GetFolder(Server.MapPath(strDirectorio))'obtenemos los ficheros de la carpetaSet colFiles=objFolder.Files'se recorren los ficherosFor each objFile in colFiles

'se recupera el nombre para obtener después el nº de visitasstrNombreFichero=objFile.NameResponse.Write strNombreFichero&" --número de visitas: "&_

Contador.Hits(strdirectorio&"/"&strNombreFichero)&"<br>"Next%>

Código fuente 64

Se supone que todas las páginas mostradas deben registrar mediante el método PageHit() que un usuario a cargado la página, sino parecerá siempre cero en su número de visitas. En la Figura 16 se puede observar la ejecución del código anterior.

Figura 16

Page 86: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

86

Componente Counters Este componente nos permite crear, manipular y almacenar cualquier número de contadores individuales a través de una instancia del mismo.

Sólo necesitamos crear un único objeto Counters en el sitio Web, a través del cual podremos crear los contadores individuales que queramos. Para ello debemos crear el objeto Counters en el archivo especial de aplicación ASP llamado GLOBAL.ASA, como se ve en el Código fuente 65, y guardarlo en una variable de aplicación. Con lo cual dicho objeto persistirá durante toda la vida de la aplicación.

Sub Application_OnStartSet ObjContador = Server.CreateObject("MSWC.Counters")Set Application("Contador") = ObjContador

End Sub

Código fuente 65

También podemos crearlo con la etiqueta OBJECT, según puede verse en el Código fuente 66.

<object id="objContador" runat="server" scope="application"progid="MSWC.Counters">

Código fuente 66

Los contadores que creemos a partir de este objeto Counters no se incrementan automáticamente al cargar la página asp en la que han sido incluidos, sino que debemos hacerlo con el método correspondiente, que en este caso es Increment.

Todos los contadores se almacenan en un archivo de texto del servidor Web y se utilizan con valores enteros. Este fichero de texto se llama COUNTERS.TXT y se encuentra en el directorio c:\winnt\system32\inetsrv\Data, un ejemplo de contenido de este fichero es:

contadorUno:16contadorDos:0Contador1:31Contador2:1

Podremos manipular los contadores con los siguientes métodos que ofrece el objeto Counters:

• Get: Devuelve el valor actual del contador cuyo nombre se le pasa como parámetro. Si el contador no existe, el método lo crea y lo pone a 0.

• Increment: Incrementa en un 1 el valor actual del contador cuyo nombre se le pasa como parámetro, y devuelve el nuevo valor del contador. Si el contador no existe, el método lo crea y lo pone a 1.

• Set: Recibe dos parámetros, el nombre del contador y un entero, asignando al contador el valor entero y devolviendo el nuevo valor. Si el contador no existe, el método lo crea y le asigna el valor entero.

Page 87: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

87

• Remove: Elimina de la colección Counters y el contador cuyo nombre se le pasa como parámetro.

Veamos un ejemplo del uso de este componente en el que vamos a crear dos contadores "Contador1" y "Contador2" a partir del objeto de aplicación Counters que anteriormente hemos creado en el archivo GLOBAL.ASA mediante la etiqueta <OBJECT>. Ambos contadores se incrementarán cada vez que se actualice la página. En el momento que el segundo contador alcance el valor 10 lo volvemos a poner a 0. Todo esto puede verse en el Código fuente 67.

<b>"Contador1": <%= objCounter.Increment("Contador1") %><br><b>"Contador2":<%=objCounter.Increment("Contador2")%><%If CInt(objCounter.Get("Contador2"))=10 Then

objCounter.Set "Contador2",0End If%>

Código fuente 67

En cualquier momento, desde otra página ASP podremos conocer el valor de ambos contadores como puede verse en el Código fuente 68.

<b>Valor del "Contador1": <%=objCounter.Get("Contador1") %><br><b>Valor del "Contador2":<%=objCounter.Get("Contador2")%>

Código fuente 68

Componente MyInfo Este componente, que también fue novedad en la versión 2.0 de ASP, nos permite almacenar información personal que será ofrecida por el administrador del sitio Web.

Esta información se cargará en las propiedades correspondientes del objeto MyInfo y podrá ser recogida a través de secuencias de script de la forma: <%=MyInfo.Propiedad%>. Todas las propiedades del objeto MyInfo devuelven una cadena. Con el componente MyInfo al igual que ocurría con Counters, únicamente se suele crear una instancia a nivel de aplicación en el fichero GLOBAL.ASA, como vemos en el Código fuente 69, o también como en el Código fuente 70.

Sub Application_OnStartSet objMyInfo=Server.CreateObject("MSWC.MyInfo")Set Application("objMyInfo")=objMyInfo

End Sub

Código fuente 69

<object id="objMyInfo" runat="server" scope="application" progid="MSWC.MyInfo">

Código fuente 70

Page 88: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

88

En cualquier momento podremos crear nuevas propiedades para el objeto MyInfo y asignarles un valor. Por ejemplo, suponiendo que hemos creado el objeto con la etiqueta OBJECT, podríamos utilizar el Código fuente 71.

<%objMyInfo.Nombre = "Angel"objMyInfo.Apellidos = "Esteban Núñez"objMyInfo.Correo = "[email protected]"%>Nombre: <%=objMyInfo.Nombre%><br>Apellidos: <%=objMyInfo.Apellidos%><br>Correo: <%=objMyInfo.Correo%>

Código fuente 71

Las tres nuevas propiedades que acabamos de crear se almacenarán de forma persistente junto con las demás propiedades de MyInfo. Por lo que podemos hacer uso de las propiedades de este objeto para almacenar valores que permanezcan constantes en todo el sitio Web.

Este objeto no tiene métodos, y las propiedades son las que le indiquemos nosotros.

La información que contiene el objeto MyInfo almacena en un fichero XML llamado myinfo.xml y se encuentra en el directorio c:\winnt\system32\inetsrv\data. Un ejemplo de contenido de este fichero podría ser el Código fuente 72.

<XML><Nombre>Angel</><Apellidos>Esteban Núñez</><Correo>[email protected]</></XML>

Código fuente 72

Componente Tools Este componente, componente de herramientas, proporciona una serie de utilidades a través de sus métodos. Estos métodos son: FileExists, ProcessForm, Random, Owner y PluginExists. Hay que tener en cuenta que los dos últimos métodos (Owner y PluginExists) únicamente han sido implementados en Personal Web Server para Macintosh.

Este componente, también fue novedad en la versión 2.0 de ASP.

Vamos a describir los métodos del componente Tools:

• FileExists: Este método permite comprobar si el archivo cuya URL se le pasa como parámetro está publicado en el sitio Web. Por tanto, las URLs que recibe como parámetro son relativas y no absolutas. Si la URL existe dentro del directorio de publicación devolverá True, en caso contrario devolverá False.

• ProcessForm: Este método es el más complejo del objeto Tools y procesa el contenido de un formulario enviado por un visitante del sitio Web. Su sintaxis es:

Page 89: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

89

ObjetoTools.ProcessForm(URL_Archivo_Resultados,URL_Archivo_Plantilla, [PuntoInserción])

Donde: URL_Archivo_Resultados: es la URL del archivo de salida en el que se han escrito los datos procesados; URL_Archivo_Plantilla: es la URL del archivo que contiene las instrucciones para procesar los datos y PuntoInserción: es un parámetro opcional que indicará en qué lugar del archivo del resultados se han de insertar los datos procesados. El fichero de salida puede ser una página ASP que se ejecutará en un navegador, el fichero de plantilla puede ser también un página ASP pero no se ejecutará, sino que es copiado su código ASP al fichero de salida, pero si utilizamos la sintaxis <%% %%>, al realizar la copia al fichero se salida si se ejecutará el código ASP correspondiente.

• Random: Este método devuelve un número entero aleatorio entre -32768 y 32767.

• Owner: Este método devuelve True si el nombre y la contraseña enviados en el encabezado de la petición coinciden con los del Administrador establecidos en la interfaz de Personal Web Server. En caso contrario devuelve False. Hay que tener en cuenta que este método únicamente han sido implementado en Personal Web Server para Macintosh.

• PluginExists: Comprueba la existencia de un complemento de servidor. Devuelve True si el complemento está registrado y False en caso contrario. Igual que el método anterior, sólo ha sido implementado en Personal Web Server para Macintosh.

Los métodos Random() y FileExists() son muy sencillos y los podemos observar en el Código fuente 73.

<%Set objTools=Server.CreateObject("MSWC.Tools")%><%=objTools.FileExists("versiones.asp")%><br><%=objTools.Random()%>

Código fuente 73

El método ProcessForm es algo más complicado, si tenemos el fichero de plantilla mostrado en el Código fuente 74.

Nombre: <%%=Request.Form("nombre")%%><br>Apellidos: <%%=Request.Form("apellidos")%%><br>Edad: <%%=Request.Form("edad")%%><br>Generado en: <%%=Now%%>

Código fuente 74

Al pasarle los datos de un formulario generará este otro fichero de salida:

Nombre: Angel<br>Apellidos: Esteban Núñez<br>Edad: 25<br>Generado en: 05/06/2000 17:18:01

Veámoslo con un sencillo ejemplo. Al pulsar el botón del formulario se ejecutará el método ProcessForm y escribirá los datos en el fichero de salida atendiendo al fichero que funciona como

Page 90: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

90

plantilla. Además, en esta página a través de un objeto TextStream se muestra el contenido del fichero de salida una vez ejecutado el método ProcessForm. Ver el Código fuente 75.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><%Set objTools=Server.CreateObject("MSWC.Tools")%><form method="post" action="tools.asp">

Nombre:<input type="text" name="nombre" value="" size="20"><br>Apellidos:<input type="text" name="apellidos" value="" size="40"><br>Edad:<input type="text" name="edad" value="" size="2"><br><input type="submit" name="enviar" value="Enviar"><br>

</form><%If Request.Form("enviar")<>"" Then

objTools.ProcessForm "ficheroSalida.asp","plantilla.asp"%>Se ha generado el siguiente fichero de salida:<br><%Set objFSO=Server.CreateObject("Scripting.FileSystemObject")Set objTextStream=objFSO.OpenTextFile(Server.MapPath("ficheroSalida.asp"))Response.Write(objTextStream.ReadAll)objTextStream.Close

End if%></BODY></HTML>

Código fuente 75

Y en la Figura 17 se puede ver un ejemplo de ejecución.

Figura 17

Page 91: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 4. Componentes de Servidor

91

Si especificamos el parámetro punto de inserción se buscará la cadena especificada en el fichero de plantilla y añadirá los datos a partir de esa coincidencia.

Componente PermissionChecker Este componente nos va a permitir determinar si a un usuario se le ha dado permisos para acceder a un fichero determinado. Este componente se basa en los mecanismos de autenticación de usuario de IIS, es decir, usuario anónimo, autenticación básica y autenticación desafío/respuesta de Windows NT.

En el caso de que se encuentre activada la autenticación anónima, todos los usuarios iniciarán sus sesiones con la cuenta de usuario anónimo de IIS. En este caso, al compartir todos los usuarios la misma cuenta, El componente PermissionChecker no podrá autenticar usuarios de forma individual.

En el caso de aplicaciones en las que todos los usuarios tengan cuentas individuales, como en los sitios Web dentro de una Intranet, es recomendable la desactivación de la autenticación anónima para que PermissionChecker pueda identificar a cada usuario de forma individual.

Para denegar el acceso anónimo a una página Web, podemos usar uno de estos tres métodos:

• En la lista de control de acceso al archivo, excluir la cuenta del usuario anónimo a nivel de NTFS.

• Desde el Administrador de servicios de Internet, en la hoja de propiedades de la seguridad de directorio se desactiva el acceso anónimo. En el capítulo siguiente veremos en detenimiento la configuración y administración del servidor Web Internet Information Server.

• Mediante un script se servidor similar al del Código fuente 76.

<%If Request.ServerVariables("LOGON_USER") = "" ThenResponse.Redirect("NoAutorizado.htm")

End If%>

Código fuente 76

En este script comprobamos si la variable del servidor LOGON_USER de la colección ServerVariables está vacía, en tal caso se tratará de la cuenta de usuario anónimo y le redireccionamos a una página que le indica al usuario que no está autorizado para el acceso.

En el caso de sitios Web mixtos de Internet e Intranet, es recomendable activar la autenticación anónima y al menos uno de los dos métodos de autenticación por contraseña, autenticación básica o autenticación desafío/respuesta de Windows NT. De esta forma, si se deniega a un usuario el acceso anónimo a una página, el servidor intentará autenticar al usuario mediante alguno de dos métodos antes comentados.

A través de este componente podremos, incluso, controlar la navegación entre páginas. Es decir, para un hiperenlace determinado podríamos comprobar si el usuario tiene permisos de acceso a la página direccionada, y en caso negativo desactivar el hiperenlace.

La sintaxis de creación de este componente es:

Page 92: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

92

Set Objeto = Server.CreateObject("MSWC.PermissionChecker")

Este componente dispone de un solo método, llamado HasAccess, a través del cual vamos a poder realizar el chequeo del acceso al un archivo especificado. Su sintaxis es:

objPermissionChecker.HasAccess("rutaArchivo")

Donde rutaArchivo podrá ser una ruta física o virtual a un archivo determinado. HasAccess() devolverá un valor booleano indicando si el usuario Web tiene acceso al archivo. En el caso de que el archivo no exista, devolverá False.

Veamos en el Código fuente 77 un ejemplo de utilización del componente, en el que chequeamos el acceso del usuario a un archivo del Web y en caso afirmativo le proporcionamos un enlace para que acceda al mismo.

<%Set objPermission=Server.CreateObject("MSWC.PermissionChecker")If objPermission.HasAccess("/MiWeb/Privado.htm") Then%>

<A HREF= "/MiWeb/Privado.html"> Area Privada </A><%Else%>

Enlace no disponible.<%End If%>

Código fuente 77

Si el usuario no se ha autenticado para acceder a la página ASP del ejemplo, nunca tendrá acceso al enlace, aunque el usuario anónimo de Internet esté autorizado el método HasAccess() devolverá False.

Page 93: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Componentes de acceso a datos. ADO

Introducción Los componentes de acceso a bases de datos son en realidad un conjunto de objetos que se agrupan dentro de la denominación ActiveX Data Objects (ADO).

Mediante el conjunto de objetos ActiveX Data Objects vamos a tener acceso a bases de datos, es decir, nos va a permitir realizar conexiones a bases de datos, ejecutar sobre ellas sentencias SQL, procedimientos almacenados, obtener resultados, etc. Es decir, nos va a ofrecer desde nuestras páginas ASP todas las operaciones que se suelen realizar sobre una base de datos.

Antes en entrar en los detalles de ADO vamos a comentar el API (Application Program Interface) en el que se basa ADO. ActiveX Data Objects (ADO) nos permite desarrollar aplicaciones ASP para acceder y manipular bases de datos a través de un proveedor OLE DB (Object Linking and Embedding para bases de datos). ADO es la primera tecnología de Microsoft basada en OLE DB.

OLE DB es una especificación basada en un API construido con C++, por lo tanto se encuentra orientado a objetos. OLE DB consiste en consumidores de datos y proveedores de datos. Los consumidores toman los datos desde interfaces OLE DB, los proveedores ofrecen estos interfaces OLE DB.

En algunos casos OLE DB puede acceder a los datos de forma más rápida que DAO y RDO, esto es así debido a que DAO y RDO deben pasar a través de la capa ODBC y OLE DB se puede conectar directamente a fuentes de datos relacionales con el proveedor correspondiente.

Page 94: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

94

Figura 18

OLE DB puede ser utilizado para extender la funcionalidad de proveedores de datos sencillos. Estos objetos más especializados y sofisticados se denominan proveedores de servicio, permiten abstraer al consumidor de datos del tipo de datos al que se accede y su localización.

Los proveedores de servicio son consumidores y proveedores, es decir, un proveedor de servicio puede consumir interfaces OLE DB y construir una tabla sencilla para ese entrada, y entonces puede ofrecer interfaces OLE DB para un aplicación cliente para que construya su salida en HTML, este ejemplo sería nuestro caso, es decir una página ASP que usa ADO.

Debemos tener en cuenta que OLE DB es una especificación de bajo nivel. ADO encapsula el API de OLE DB en un API de más alto nivel que proporciona dentro de su tecnología de componentes un lenguaje neutral, que permite aprovechar todas las ventajas y características de OLE DB sin realizar una programación a bajo nivel.

Ya hemos introducido el concepto de proveedor y consumidor en el que se basa OLE DB, el consumidor es simplemente el que consume (utiliza) los datos y el proveedor el que ofrece esos datos.

Para acceder a una base de datos determinada debemos tener el proveedor OLE DB correspondiente. De esta forma el acceso a una base de datos determinada viene condicionado por la existencia del proveedor OLE DB correspondiente.

Para las bases de datos que no exista o no dispongamos de su proveedor OLE DB podemos utilizar el proveedor OLE DB para ODBC, ya que ODBC se encuentra más difundido y es posible que exista el driver ODBC correspondiente.

Es importante que no confundamos los proveedores con los drivers. En la Figura 19 se muestra un esquema dónde se pueden distinguir el lugar que ocupan los drivers y los proveedores OLE DB.

Como se puede observar los proveedores se encuentran en la capa OLE DB y los drivers en la capa ODBC. ADO 2.5 ofrece varios proveedores OLE DB por defecto. De todas formas existen más proveedores OLE DB que son ofrecidos por otras empresas.

ADO permite crear aplicaciones ASP para acceder y manipular datos en una base de datos a través de un proveedor OLE DB. Las principales ventajas de ADO son su velocidad, facilidad de uso, baja carga de memoria y requieren poco espacio en el disco duro.

Page 95: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

95

Figura 19

Una ventaja de ADO es que si ya lo hemos utilizado en Visual Basic 6, veremos que será prácticamente igual utilizarlo en ASP, aunque eso sí, teniendo siempre en cuenta el entorno tan particular en el que nos encontramos.

Las características que posee ADO para construir aplicaciones cliente/servidor y aplicaciones ASP son las siguientes:

• Sus objetos se pueden crear de forma independiente fuera de su jerarquía o modelo de objetos. No es necesario navegar a través de una jerarquía para crear un objeto, la mayoría de los objetos ADO se pueden instanciar de forma independiente. Esto nos permite crear únicamente los objetos que necesitamos.

• Ofrece soporte para realizar llamadas a procedimientos almacenados con parámetros de entrada/salida.

• Diferentes tipos de cursores.

• Soporta resultados múltiples devueltos desde procedimientos almacenados.

Se debe tener en cuenta que aunque ADO aporte todas estas características, los proveedores y drivers a los que llama ADO pueden no contemplar estas características. Por lo tanto antes debemos consultar la documentación de los proveedores OLE DB que vamos a utilizar para informarnos de las características que ofrecen.

ADO utiliza la característica pooling de conexiones de ODBC 3.0 para efectuar el acceso a las bases de datos de forma más eficiente. Esta característica consiste en mantener abiertas conexiones de bases de datos y administrar la compartición de conexiones entre diferentes solicitudes de usuarios para mantener el rendimiento y reducir el número de conexiones inactivas.

En cada solicitud de conexión se determina si del grupo de conexiones hay una conexión inactiva, si la hay, el grupo de conexiones devuelve esa conexión en lugar de efectuar una nueva conexión a la base de datos.

Por defecto el pooling de conexiones está activado en ASP. Para desactivar esta característica se debe establecer a cero la entrada de registro llamada StartConnectionPool.

Page 96: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

96

Esta característica es bastante útil para ASP debido al entorno en el que nos encontramos. Las aplicaciones tradicionales de bases de datos suelen crear una única conexión con la base de datos que se utiliza durante toda la duración de la aplicación. Sin embargo, debido a que en el entorno Web no se puede mantener la información entre diferentes peticiones de páginas, una aplicación de bases de datos en el entorno Web debe abrir y cerrar una conexión en cada página.

Además no es recomendable almacenar referencias a objetos de ADO a nivel de variables del objeto Session o Application.

Modelo de objetos de ADO Como se ha dicho anteriormente ADO es más complejo que el resto de los componentes ActiveX Server que se incluyen con ASP. ADO presenta un completo modelo de objetos que se muestra en la Figura 20.

Figura 20

Como se puede observar en la figura hay tres objetos que se diferencian del resto, es decir, los objetos: Connection, Command y Recordset. Estos objetos son los principales dentro de ADO, y se pueden crear fuera de la jerarquía de la figura, y se pueden manejar sin tener que interactuar con un intermediario. Estos tres objetos se crearán mediante el método CreateObject del objeto Server, al igual que hacíamos con el resto de los componentes de servidor, el resto de los objetos de ADO se crean a partir de estos tres.

Desde el punto de vista práctico el objeto Recordset es el más importante, ya que es le que va a permitir acceder a los registros de la base de datos, pero los objetos Connection y Command permiten la creación de un objeto Recordset.

ASP 3.0 incluye la última versión de ADO, la versión 2.5, que incluye dos nuevos objetos: el objeto Record y el objeto Stream. De todas formas ya adelantamos que desde ASP 3.0 todavía no se encuentra implementada de forma satisfactoria estos dos objetos.

Page 97: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

97

El objeto Connection Un objeto Connection representa una conexión a una base de datos. Los objetos Connection se pueden crear de forma independiente sin tener en cuenta ningún objeto definido previamente. Este objeto, al igual que los objetos Command y Recordset, es creado mediante el método CreateObject del objeto Server.

Las actividades que se pueden realizar con un objeto Connection son: creación de conexiones con bases de datos, obtención de objetos Recordset sencillos y tratamiento de errores.

A continuación se van a enumerar y comentar de forma breve las diferentes propiedades, métodos y colecciones que posee este objeto. Después se verán con más detalle las propiedades, métodos y colecciones más importantes.

Lo que se ofrece a continuación no es una descripción detallada del objeto Connection, sino que es una referencia rápida del mismo.

Las propiedades del objeto Connection son:

• Attributes: indica distintas características de la conexión por ejemplo de que forma se puede iniciar una nueva transacción.

• ConnectionTimeout: tiempo de espera máximo para la realización de una conexión antes de que se produzca un error.

• ConnectionString: cadena de conexión que identifica la base de datos a la que nos queremos conectar.

• CommandTimeout: tiempo máximo de espera en la ejecución de un comando SQL que se ejecuta de forma directa sobre la conexión.

• CursorLocation: indica la localización de los cursores que se van a crear a partir de la conexión. pueden situarse en el cliente o en el servidor.

• DefaultDatabase: indica la base de datos por defecto con la que realizar la conexión.

• IsolationLevel: propiedad de sólo lectura que indica el nivel de aislamiento de la conexión.

• Mode: modo de acceso a la conexión.

• Provider: proveedor OLE DB utilizado para establecer la conexión.

• Version: propiedad de sólo lectura, indica la versión de ADO.

• State: propiedad de sólo lectura que indica el estado de la conexión, es decir, si se encuentra abierta o cerrada.

Los métodos del objeto Connection no son tan numerosos y son los siguientes:

• BeginTrans: indica el inicio de un transacción.

• CommitTrans: almacena todos los cambios y finaliza la transacción actual, representa el commit de una transacción.

Page 98: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

98

• RollbackTrans: cancela todos los cambios realizados durante la transacción actual y finaliza la transacción, representa el rollback de una transacción.

• Close: cierra la conexión.

• Execute: ejecuta un comando SQL.

• Open: abre la conexión.

• Cancel: cancela la ejecución de una operación asíncrona de ejecución de una sentencia SQL o de una apertura de una conexión.

• OpenSchema: obtiene un objeto Recordset con el esquema de la base de datos.

El objeto Connection posee dos colecciones:

• Errors: colección de errores generados a través del uso de ADO.

• Properties: una colección de objetos Property referentes al objeto Connection.

La función principal de un objeto Connection es la de especificar el origen de los datos, aunque también se puede utilizar a veces para ejecutar sentencias SQL sencillas.

Abrir una conexión Una vez creado un objeto Connection mediante la siguiente línea, podemos utilizarlo para establecer conexiones con un proveedor de datos. Decimos proveedor de datos porque la conexión no tiene que ser necesariamente a una base de datos, como vimos en el capítulo anterior ADO forma parte de la estrategia universal de acceso a datos UDA, que permite acceder a diferentes tipos de datos.

Para realizar la conexión utilizaremos el método Open del objeto Connection, al que le podemos pasar como parámetro la cadena de conexión de la base de datos (o de forma más general, del proveedor de datos u origen de los datos). También es posible especificar la información de la conexión que se va a realizar a través de la propiedad ConnectionString.

La sintaxis general del método Open es la siguiente:

objConexion.Open [CadenaConexion], [IDusuario], [contraseña],[opciones]

Donde CadenaConexion es la cadena de conexión del origen de los datos, IDusuario es el nombre del usuario que va a realizar la conexión, contraseña es la contraseña de ese usuario y opciones permite indicar información adicional acerca de la conexión. Vamos comentar estos parámetros de forma detallada.

Como se puede observar en la sintaxis del método Open todos los parámetros del mismo son opcionales, ya que esta misma información puede ser facilitado por la propiedad ConnectionString. Esta situación la veremos en muchos casos al trabajar con ADO, es decir, los parámetros de los métodos se corresponden con propiedades del objeto sobre el que se lanzan.

El parámetro CadenaConexion puede contener los siguientes parámetros para la conexión:

• Provider: proveedor OLE DB que se va a utilizar.

Page 99: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

99

• Data Source: el nombre del servidor dónde se encuentra la base de datos o del fichero fuente de datos.

• Initial Catalog: el nombre de la base de datos.

• User id: el nombre del usuario que va a establecer la conexión.

• Password: contraseña del usuario.

• File Name: nombre del fichero que contiene la información del proveedor de la conexión.

• URL: la URL absoluta que identifica la carpeta o fichero que se va a utilizar como origen de datos.

• DSN: nombre de la fuente de datos de ODBC que se va a utilizar.

Estos parámetros son exactos a los que puede contener la propiedad ConnectionString del objeto Connection. Además se puede observar que el usuario y contraseña pueden estar contenidos en esta cadena de conexión.

En el parámetro opciones se puede indicar una constante de ADO que aporta información adicional de la conexión, esta información indica si la conexión va a ser síncrona o asíncrona, el valor de este parámetro es adASyncConnect, que indicará que la conexión es asíncrona, sino se indica nada la conexión será síncrona. En el entorno de ASP no tiene sentido declarar una conexión como asíncrona, ya que ASP no puede recibir los eventos que genera ADO, por lo tanto en nuestras páginas ASP el método Open nunca llevará el parámetro opciones.

Para utilizar las constantes de ADO se debe incluir el fichero de constantes correspondiente.

El fichero de constantes de ADO se llamada ADOVBS.INC y se encuentra en la ruta c:\Archivos de programa\archivos comunes\system\ado. Para incluir el fichero de constantes en nuestras páginas podemos copiarlo a nuestro sitio Web y realizar una referencia al mismo mediante la directiva INCLUDE, como se puede observar en el Código fuente 78.

<!--#INCLUDE FILE="ADOVBS.INC"-->

Código fuente 78

Esta sentencia la deberemos repetir en todas las páginas en las que queramos utilizar las constantes de ADO. Una alternativa más sencilla es hacer una referencia a la librería de tipos de ADO mediante la etiqueta METADATA dentro del fichero GLOBAL.ASA, como se ve en el Código fuente 79.

De esta forma las constantes se encontrarán accesibles desde cualquier página ASP de la aplicación.

<!-- METADATA TYPE="typelib" FILE="c:\Archivos de programa\archivoscomunes\system\ado\msado15.dll"-->

Código fuente 79

Page 100: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

100

Aunque el nombre de la librería de tipos termine en 15, pertenece a la versión 2.5 de ADO. A continuación se va a mostrar una serie de ejemplos que realizan conexiones de distintas formas.

En este primer ejemplo se realiza una conexión con el proveedor OLE DB de SQL Server. Además de realizar la conexión se muestra el nombre del proveedor utilizado a través de la colección Properties y la versión de ADO que se se ha utilizado para establecer la conexión. El código necesario es el que aparece en el Código fuente 80.

<%Set Conex=Server.CreateObject("ADODB.Connection")Conex.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;Userid=sa"%><b>Versión de ADO: </b> <i><%=Conex.Version%></i><br><b>Proveedor: </b><i><%=Conex.Properties("Provider Friendly Name")%>(<%=Conex.Properties("Provider Name")%>)</i><br>

Código fuente 80

Mediante esta cadena de conexión lo que se consigue es establecer una conexión con un servidor llamado aesteban2 que tiene instalado SQL Server, el usuario conectado es sa y se conecta a la base de datos pubs.

El resultado que aparece en el navegador es:

Versión de ADO: 2.5Proveedor: Proveedor de Microsoft OLE DB para SQL Server(sqloledb.dll)

Como se puede comprobar se muestra el nombre completo del proveedor (o nombre "amigable") y la librería en la que se encuentra. Si no indicamos ningún proveedor OLE DB a la hora de establecer la conexión por defecto se utiliza el proveedor de ODBC.

La conexión del ejemplo anterior la podríamos haber realizado de esta otra forma, como indica el Código fuente 81. Y otra forma más aparece en el Código fuente 82.

Set Conex=Server.CreateObject("ADODB.Connection")Conex.ConnectionString="Provider=SQLOLEDB;Data Source=aesteban2;"&_

"Initial Catalog=pubs;User id=sa"Conex.Open

Código fuente 81

Conex.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs","sa"

Código fuente 82

También podemos hacer uso de otras propiedades del objeto Connection, como se puede ver en el Código fuente 83, que no es nada más que otra versión distinta de nuestro ejemplo.

Conex.Provider="SQLOLEDB"

Page 101: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

101

Conex.ConnectionString="Data Source=aesteban2;User id=sa"Conex.OpenConex.DefaultDatabase="pubs"

Código fuente 83

La propiedad DefaultDatabase, que indica la base de datos por defecto a la que nos conectamos, se puede utilizar una vez que ya está establecida la conexión.

Como se puede comprobar, a la vista de las numerosas versiones de este ejemplo, el establecimiento de una conexión con ADO es muy flexible.

Ahora se va a realizar una conexión utilizando el proveedor OLE DB de ODBC, como ya hemos dicho este es el proveedor por defecto que se utiliza para el objeto Connection. Se va actuar de la misma forma que para la conexión anterior, es decir, se van a mostrar distintas formas de establecer una misma conexión.

Si suponemos que tenemos una fuente de datos ODBC (DSN de ODBC) de sistema definida en el servidor Web, podemos emplear el Código fuente 84 para establecer la conexión.

<%Set Conex=Server.CreateObject("ADODB.Connection")Conex.ConnectionString="DSN=FuenteCursos;User id=cursos;Password=xxx"Conex.Open%><b>Versión de ADO: </b> <i><%=Conex.Version%></i><br><b>Proveedor: </b><i><%=Conex.Properties("Provider Friendly Name")%>(<%=Conex.Properties("Provider Name")%>)</i><br>

Código fuente 84

En esta caso nos conectamos a una DSN de ODBC de sistema llamada FuenteCursos con el usuario cursos que tiene la contraseña xxx. El resultado que se obtiene ahora es el siguiente:

Versión de ADO: 2.5Proveedor: Microsoft OLE DB Provider for ODBC Drivers (MSDASQL.DLL)

También disponemos de diversas formas de establecer una misma conexión, vamos a ver unas cuantas en el Código fuente 85.

Set Conex=Server.CreateObject("ADODB.Connection")Conex.Open "DSN=FuenteCursos;User id=cursos;Password=xxx"Conex.Open "DSN=FuenteCursos;UID=cursos;PWD=xxx"Conex.Open "DSN=FuenteCursos","cursos","xxx"

Código fuente 85

Como se puede observar podemos utilizar indistintamente el parámetro PWD o Password para indicar la contraseña, y el parámetro User id y UID para indicar el usuario.

Incluso se puede establecer la conexión a través de el proveedor OLE DB de ODBC sin necesidad de crear la fuente de datos de ODBC en el servidor Web, es decir, se realiza la conexión con ODBC sin DSN. Veámoslo en el ejemplo del Código fuente 86.

Page 102: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

102

Set Conex=Server.CreateObject("ADODB.Connection")Conex.Open "driver=SQL Server;server=aesteban2;uid=cursos;pwd=xxx;database=Cursos"

Código fuente 86

En este caso se ha establecido una conexión a la base de datos Cursos que se encuentra en el servidor aesteban2 y se ha utilizado el driver ODBC para SQL Server, ya que nuestra base de datos se encuentra en un servidor SQL Server. Como se puede comprobar debemos utlizar un parámetro driver para indicar el driver ODBC que se va a utilizar para establecer la conexión.

Ejecutar comandos sobre una conexión Una vez establecida la conexión con un origen de datos determinados, ya podemos ejecutar consultas o sentencias sobre la conexión. Aunque ya hemos comentado en el tema anterior y en este mismo, que ADO permite manipular datos de cualquier tipo, vamos a centrarnos en el acceso a datos a un sistema gestor de bases de datos relacional, en mi caso he utilizado SQL Server 7, pero el lector puede utilizar el que estime conveniente.

Esta no es la labor principal del objeto Connection, aunque se suelen ejecutar sentencias SQL sencillas directamente sobre la conexión para una mayor simplicidad del código o por comodidad del programador.

Una vez establecida la conexión, podremos ejecutar sobre ella comandos SQL (sentencias SQL, procedimientos almacenados, nombre de una tabla...), para ello utilizaremos el método Execute, que posee la siguiente sintaxis general:

Set resultado = conexion.Execute(CommandText[, RegistrosAfectados,Opciones])connection.Execute CommandText[, RegistrosAfectados, Opciones]

Como se puede observar existen dos formas distintas de utilizar el método Execute. En la primera línea se muestra de que forma se llamaría al método Execute cuando necesitamos almacenar su resultado en un objeto Recordset y en la segunda línea cuando no es necesario almacenar su resultado.

El parámetro CommandText es una cadena que representa el comando SQL que se debe ejecutar, es decir, esta cadena contendrá: la sentencia SQL o procedimiento almacenado a ejecutar o el nombre de la tabla que se quiere recuperar.

En el parámetro opcional RegistrosAfectados se devolverá el número de registros a los que ha afectado la operación. En el parámetro opcional Opciones se puede indicar mediante una constante de ADO el tipo de comando que se encuentra en el parámetro CommandText, es recomendable utilizar este parámetro para optimizar la evaluación y ejecución del comando correspondiente. Los valores que puede tomar este parámetro aparecen en la Tabla 5.

Constante Descripción

adCmdText Evalúa el comando como una sentencia SQL.

Page 103: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

103

adCmdTable Evalúa el comando como el nombre de una tabla.

adCmdStoredProc Evalúa el comando como un procedimiento almacenado.

adCmdUnkown El tipo del comando SQL es desconocido.

adCmdTableDirect Se evalúa como el nombre de una tabla

adCmdFile Se trata como un fichero que contiene un objeto Recordset que se había almacenado.

adExecuteNoRecords Se utiliza cuando los comandos no devuelven registros

Tabla 5

Por lo tanto, a través del método Execute podremos ejecutar diferentes tipo de comandos SQL, a continuación se comentan mediante ejemplos algunos de los usos del método Execute.

En el Código fuente 87 se muestra como se almacenaría el contenido de una tabla en un objeto Recordset, indicando de forma explícita que el comando SQL es el nombre de una tabla.

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx"Set objRecordset=objConexion.Execute("provincias",,adCmdTable)%>

Código fuente 87

Un resultado equivalente lo obtendríamos mediante la ejecución de una sentencia SQL, como se muestra en el Código fuente 88.

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx"Set objRecordset=objConexion.Execute("Select * from provincias",,adCmdText)%>

Código fuente 88

Para ejecutar un procedimiento almacenado llamado borraDatos, haríamos lo del Código fuente 89.

<%Set objConexion=Server.CreateObject("ADODB.Connection")

objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx"objConexion.Execute "borraDatos",,adCmdStoredProc%>

Código fuente 89

Page 104: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

104

En el Código fuente 90 se borran todas las provincias cuyo código empiece por '8', el número de provincias borradas se recoge en el parámetro registrosBorrados:

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx"objConexion.Execute "DELETE FROM Provincias WHERE IDProvin LIKE '8%'"_

,,registrosBorrados,adCmdTextResponse.write("Provincias borradas:"&registrosBorrados) %>

Código fuente 90

Cerrar la conexión Una vez que hayamos terminado de trabajar con la conexión la deberemos cerrar mediante el método Close. La llamada a Close liberará los recursos del sistema asociados a la conexión, pero no eliminará el objeto de la memoria, para eliminarlo de la memoria se deberá asignar al objeto el valor Nothing.

Cerrar una conexión mientras que existe una transacción en progreso producirá un error. Al lanzar el método Close sobre una conexión también se cerrarán todos los objetos Recordset asociados a la conexión, y también se vaciarán las colecciones Parameters de los objetos Command asociados a la conexión y su propiedad ActiveConnection tendrá el valor Nothing.

El objeto Command Este es el segundo objeto que se podía crear de forma independiente a la jerarquía de objetos ADO, y además era la segunda forma de obtener un objeto Recordset. Un objeto Command permite realizar la ejecución de un procedimiento almacenado de una base de datos, por lo tanto para poder utilizar el objeto Command de esta forma, el proveedor de datos debe soportar procedimientos almacenados. A través de este objeto podremos pasar parámetros a los procedimientos almacenados.

Pero este objeto no sólo permite realizar la ejecución de procedimientos almacenados, también se puede utilizar para ejecutar sentencias SQL optimizadas. El objeto Command se va a comentar de la misma forma que el objeto Connection, primero se enumerarán todas su propiedades, métodos y colecciones y luego detallaremos los más importantes según vayamos avanzando en la explicación de este objeto de ADO.

Las propiedades que posee este objeto son las que se enumeran a continuación.

• ActiveConnection: conexión a la que se encuentra asociado el objeto Command.

• CommanText: comando que va a contener el objeto Command, puede ser una sentencia SQL, el nombre de una tabla o un procedimiento almacenado.

• CommandTimeout: tiempo máximo de espera para la finalización de la ejecución de un objeto Command. Indica cuanto tiempo se esperará mientras se ejecuta un objeto Command antes de terminar su ejecución y generar un error. Se expresa en segundos, su valor por defecto es de 30 segundos.

• CommandType: indica el tipo del objeto Command.

Page 105: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

105

• Prepared: indica si se va a crear un sentencia "preparada" (prepared statement), es decir, una sentencia precompilada, a partir del objeto Command antes de la ejecución del mismo.

• State: propiedad de sólo lectura que indica la situación actual del comando, si se está ejecutando, si está cerrado o abierto.

• Name: permite identificar un objeto Command para luego ejecutarlo directamente desde el objeto Connection asociado.

Los métodos del objeto Command son:

• CreateParameter: mediante este método crearemos un parámetro para el comando SQL a ejecutar.

• Execute: ejecuta el objeto Command.

• Cancel: cancela la ejecución asíncrona de un comando. No es posible utilizarlo en páginas ASP ya que no está permitida la ejecución asíncrona.

A continuación las colecciones del objeto Command:

• Parameters: esta colección contiene objetos Parameter que son cada uno de los parámetros que va a tener el objeto Command.

• Properties: colección de propiedades, objetos Property. Tiene la misma función que en el objeto Connection.

Crear un objeto Command Como se ha dicho anteriormente, un objeto Command se puede crear de forma independiente, pero debemos indicarle sobre que conexión se va a realizar la ejecución de ese comando. Para ello utilizaremos la propiedad ActiveConnection, el valor asignado a esta propiedad puede ser un objeto Connection ya creado o una cadena de conexión. En el Código fuente 91 vemos varios ejemplos con las dos posibilidades.

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx"Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection=objConexion%>

<%Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection="DSN=FuenteBD;UID=pepe;PWD=xxx"%>

Código fuente 91

Como se puede observar indicamos que el objeto Command va a utilizar una DSN de ODBC como origen de los datos, ya sea a través de un objeto Connection ya creado y abierto o bien a través de la cadena de conexión correspondiente.

En el Código fuente 92 se ofrece la creación de un objeto Command pero que se conecta a través del proveedor OLE DB de SQL Server.

Page 106: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

106

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;Userid=sa"Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection=objConexion %>

<%Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection="Provider=SQLOLEDB;Data Source=aesteban2;"&_

"Initial Catalog=pubs;User id=sa"

Código fuente 92

Lo más recomendable es utilizar en la propiedad ActiveConnection un objeto Connection, de esta forma distintos objetos Command pueden compartir una misma conexión. Si utilizamos una cadena de conexión en la propiedad ActiveConnection, cada objeto Command tendrá su propia conexión (objeto Connection), lo que supondrá una mayor carga para el servidor.

Una vez que hemos indicado al objeto Command la conexión a la base de datos, le debemos indicar el comando que deseamos que contenga a través de la propiedad CommandText, además, podemos indicar el tipo de comando que se va a ejecutar a través de la propiedad CommandType, los valores de esta propiedad son las constantes que ya vimos dentro del parámetro CommandText del método Execute del objeto Connection.

De esta forma si queremos crear un comando que ejecute una sentencia SQL INSERT deberemos escribir el Código fuente 93.

<%Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection="DSN=FuenteBD;UID=pepe;PWD=xxx"objComando.CommandType=adCmdTextobjComando.CommandText="INSERT INTO Provincias VALUES ('aa','Soria')"%>

Código fuente 93

El tiempo máximo que vamos a esperar a que un comando finalice su ejecución se indica en segundos a través de la propiedad CommandTimeout, cuando la ejecución de un comando supera este tiempo, se abortará su ejecución y se producirá un error. El valor de CommandTimeout dependerá del tráfico de la red, si es alto tendremos que aumentar el valor de esta propiedad. Esta propiedad del objeto Command permite sobreescribir el valor de la propiedad del objeto Connection para un objeto Command determinado.

Mediante la propiedad Prepared indicaremos si el objeto Command contiene una sentencia SQL precompilada. Si esta propiedad tiene el valor True, antes de ejecutar el comando se enviará a la base de datos la sentencia para que sea compilada (sentencia preparada), esto podría ralentizar la primera ejecución del objeto Command, pero una vez que el proveedor de datos a compilado el contenido del comando, el proveedor utilizará la versión compilada del comando en las sucesivas ejecuciones, por lo tanto ganaremos en eficiencia. Es recomendable asignar a Prepared el valor True cuando tengamos que ejecutar varias veces el objeto Command con una misma sentencia SQL.

Page 107: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

107

La colección Parameters Como se ha comentado al comienzo de este capítulo, las funciones del objeto Command eran permitir la ejecución de procedimientos almacenados y ejecución se sentencias SQL optimizadas (precompiladas o preparadas), por lo tanto debe permitir realizar el paso de parámetros a la sentencia o procedimiento SQL que se vaya a ejecutar.

Un objeto Command almacena los parámetros que va a necesitar para su ejecución en una colección llamada Parameters, esta colección está constituida por objetos Parameter. Por lo tanto antes de ejecutar un comando deberemos crear sus parámetros y añadírselos a la colección Parameters.

Para crear un parámetro utilizaremos el método CreateParameter del objeto Command, al lanzar este método obtenemos un objeto Parameter, la sintaxis general de este método es la siguiente:

Set parametro=objComando.CreateParameter([nombre][, tipo][,direccion][, tamaño][, valor])

Donde parametro es un objeto Parameter en el que se va a almacenar el parámetro creado como resultado de lanzar este método, objComando es el objeto Command al que se le ha asociado ese parámetro, los siguientes argumentos son todos opcionales: nombre es una cadena que va a representar el nombre del parámetro (a través de este nombre se podrá hacer referencia al parámetro dentro de la colección Parameters), tipo indica el tipo de dato del parámetro, direccion indica si el parámetro es de entrada o de salida, tamaño indica el tamaño máximo del parámetro y valor es el valor para ese objeto Parameter creado.

Como se ha podido comprobar, podremos crear un objeto Parameter con todas sus propiedades especificadas en el método CreateParameter, pero también podremos lanzar el método CreateParameter sin especificar ninguna de estas propiedades (se debe recordar que todos los argumentos del método CreateParameter eran opcionales) y luego, a partir del objeto Parameter creado podremos asignar valores a sus propiedades de forma directa.

Las propiedades que posee el objeto Parameter son las siguientes:

• Name: nombre con el que se identifica al parámetro dentro de la colección Parameters. Este nombre no tiene porque coincidir con el nombre del parámetro correspondiente en el procedimiento almacenado de la base de datos.

• Type: tipo de dato del parámetro.

• Direction: indica la naturaleza (dirección) del parámetro.

• Size: es el tamaño del parámetro.

• Value: valor que se asigna al parámetro.

• NumericScale: indica el número de decimales soportado por el parámetro.

• Precision: número máximo de dígitos del parámetro.

• Attributes: es una combinación de ciertas constantes que indican otras características del parámetro. Estas constantes son adParamNullable (el parámetro acepta valores nulos), adParamSigned (el parámetro acepta valores con signo) y adParamLong (el parámetro acepta valores de datos grandes).

Page 108: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

108

En el Código fuente 94 se muestran las dos posibilidades, es decir, se indican las características del parámetro a través del método CreateParameter y por otro lado se utilizan las propiedades del objeto Parameter para asignarles los valores correspondientes. En el ejemplo se pretende crear un parámetro de entrada llamado nombre de tipo char, de tamaño máximo 20 y cuyo valor es "Pepe".

<%Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection="DSN=FuenteBD;UID=jose;PWD=xxx"objComando.CommandType=adCmdTextobjComando.CommandText="INSERT INTO Usuarios VALUES (?)"Set parametro=objComando.CreateParameter("nombre",adChar,adParamInput,20,"Pepe")%>

<%Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection="DSN=FuenteBD;UID=jose;PWD=xxx"objComando.CommandType=adCmdTextobjComando.CommandText="INSERT INTO Usuarios VALUES (?)"Set parametro=objComando.CreateParameterparametro.Name="nombre"parametro.Type=adCharparametro.Direction=adParamInputparametro.Size=20parametro.Value="Pepe" %>

Código fuente 94

Como se puede observar la primera forma de crear un parámetro y establecer sus propiedades es mucho más cómoda. También podemos apreciar que en la sentencia SQL que contiene el objeto Command, el parámetro se corresponde con el signo de interrogación (?), este es el caracter especial que indica en que lugar se va a situar el parámetro.

Una vez creado el parámetro y establecidas sus propiedades lo deberemos añadir a la colección Parameters del objeto Command correspondiente, para ello esta colección ofrece el método Append. El orden en que se añaden los objeto Parameter a la colección Parameters es significativo, se irán sustituyendo los signos de interrogación (?) de la sentencia o los parámetros del procedimiento almacenado según se vayan añadiendo los parámetros a la colección. La sintaxis del método Append es:

objCommand.Parameters.Append objParametro

La colección Parameters, además del método Append ofrece dos métodos más: Delete y Refresh. El método Delete elimina el objeto Parameter de la colección Parameters, cuyo índice o nombre se pasa como argumento, la sintaxis de este método es:

objCommand.Parameters.Delete {índice|nombre}

El método Delete se suele utilizar para una vez ejecutado un objeto Command, eliminar sus parámetros para volver a utilizarlo con otros valores.

El método Refresh realiza una llamada al origen de los datos para obtener todos los datos correspondientes a los parámetros que necesita un objeto Command determinado. El método Refresh obtiene los nombres, tipos de datos, naturaleza y longitud de los parámetros y con esta información rellena la colección Parameters por nosotros, únicamente deberemos indicar los valores de los parámetros, no deberemos utilizar el método Append.

Sin embargo es recomendable construir la colección Parameters de forma manual, sin realizar la llamada al método Refesh, ya que esto último resulta más costoso para el origen de los datos.

Page 109: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

109

La colección Parameters posee dos propiedades:

• Count: devuelve el número de objetos Parameters presentes en la colección Parameters.

• Item: es la propiedad por defecto de la colección Parameters y devuelve el objeto Parameters cuyo nombre o índice se le pasa como argumento.

Ejecutar un comando Cuando se hayan facilitado al objeto Command todos sus parámetros ya estaremos en disposición de ejecutar el comando mediante el método Execute. Una vez ejecutado el objeto Command, si deseamos volver a utilizarlo con otros parámetros será necesario eliminar los parámetros existentes dentro de la colección Parameters, para ello se utiliza el método Delete (como ya comentamos en el apartado anterior).

Como se ha dicho con anterioridad para ejecutar un objeto Command se utiliza el método Execute, que presenta la siguiente sintaxis:

Set objRecordset=objComando.Execute(RegistrosAfectados,Parámetros, Opciones)

objComando.Execute RegistrosAfectados, Parámetros, Opciones

En el caso de que la ejecución del objeto Command devuelva un conjunto de filas y columnas (resultado de una SELECT) lo podremos almacenar dentro de un objeto Recordset que podremos recorrer para mostrar la información. Como ya se comentó anteriormente, el objeto Command ofrecía el segundo mecanismo (el primer mecanismo lo ofrecía el objeto Connection) para obtener un objeto Recordset.

Los argumentos son todos opcionales, RegistrosAfectados es un entero que se devuelve y que indicará el número de registros que se han visto afectados por la ejecución del comando, Parametros es un array de con los valores de los parámetros, se utiliza en el caso de que no hayamos añadido a la colección Parameters los parámetros correspondientes, Opciones indica que tipo de comando se quiere ejecutar, se utilizará si ya no lo hemos indicado en la propiedad CommandType del objeto Command, además este parámetro si se especifica sobreescribe al valor indicado en la propiedad CommandType.

En el Código fuente 95 se muestra como se ejecutaría una sentencia SQL que realiza una actualización sobre una tabla a partir de los parámetros que se le pasen.

<!--#INCLUDE VIRTUAL=/ADO/ADOVBS.INC--><%Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection="DSN=FuenteBD;UID=pepe;PWD=xxx"objComando.CommandType=adCmdTextobjComando.CommandText="UPDATE Provincias SET Provincia=?"&_

"WHERE IDProvin=?"Setparametro1=objComando.CreateParameter("nombre",adChar,adParamInput,20,"Cáceres")Set parametro2=objComando.CreateParameter("clave",adChar,adParamInput,2,"10")objComando.Parameters.Append parametro1objComando.Parameters.Append parametro2objComando.Execute%>

Código fuente 95

Page 110: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

110

En el Código fuente 96 se realiza una llamada a un procedimiento almacenado que realiza un alta sobre la tabla de provincias.

<!--#INCLUDE VIRTUAL=/ADO/ADOVBS.INC--><%Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection="DSN=FuenteBD;UID=pepe;PWD=xxx"objComando.CommandType=adCmdStoredProcobjComando.CommandText="altaProvincia"Set parametro1=objComando.CreateParameter("clave",adChar,adParamInput,2,"90")Setparametro2=objComando.CreateParameter("nombre",adChar,adParamInput,20,"Santander")objComando.Parameters.Append parametro1objComando.Parameters.Append parametro2objComando.Execute%>

Código fuente 96

Como se puede apreciar, en el caso de realizar la ejecución de un procedimiento almacenado, no se indican los parámetros con signos de interrogación, únicamente se debe proporcionar el nombre del procedimiento almacenado que queremos utilizar, y los parámetros se situarán según esté definido el procedimiento en la base de datos. Es responsabilidad del programador conocer la definición del procedimiento almacenado y por lo tanto proporcionar los parámetros de forma adecuada.

La forma de obtener un objeto Recordset a partir de la ejecución de un objeto Command es muy sencilla. A la hora de ejecutar el objeto Command con el método Execute podremos guardar su resultado en un objeto Recordset, de la misma forma que ocurría al ejecutar un sentencia SQL sobre un objeto Connection.

El Código fuente 97 trata de una página ASP que realiza una SELECT sobre la tabla de provincias y guarda el resultado en un objeto Recordset para su futura inspección.

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx"Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection=objConexionobjComando.CommandType=adCmdTextobjComando.CommandText="SELECT * FROM Usuarios"Set objRecordset=objComando.Execute%>

Código fuente 97

En el Código fuente 98 se crea un Recordset con la información devuelta por un procedimiento almacenado, en este caso, el procedimiento devuelveDomicilio devuelve una relación de los nombres de usuario junto con su domicilio.

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx"Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection=objConexionobjComando.CommandType=adCmdStoredProc

Page 111: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

111

objComando.CommandText="devuelveDomicilio"Set objRecordset=objComando.Execute%>

Código fuente 98

El objeto Recordset Este es el tercero de los objetos principales del modelo de objetos de ADO. Como se ha visto anteriormente, un objeto de este tipo se obtiene de forma automática a partir de la ejecución de un objeto Connection o un objeto Command. Pero el objeto Recordset que se obtiene es muy sencillo y limitado, representa un cursor de sólo lectura y que únicamente permite un desplazamiento hacia delante. Un objeto Recordset se puede crear de forma independiente, es decir, sin depender de ningún objeto Connection o Command.

Un objeto Recordset es un objeto tabular que contiene datos. Los valores se encuentran en las filas y los nombres de los campos en las columnas. Cada fila es un registro completo. Es importante destacar que un objeto Recordset es una representación de los datos, pero no son los datos almacenados. En un objeto Recordset se deben determinar tres cosas: el lugar en el que se encuentra, es decir, la fuente de los registros que contiene, las capacidades de navegación y la conexión con los datos. Un cursor determina el comportamiento de un objeto Recordset.

Por lo tanto, si queremos disponer de un cursor más potente, deberemos crear un objeto Recordset. al igual que creábamos un objeto Connection o Command, y a través de sus propiedades definir exactamente las características del Recorset. A continuación se pasa a mostrar de forma resumida todas las propiedades, métodos y colecciones que posee este objeto.

El objeto Recordset posee un gran número de propiedades:

• PageSize: número de registros del Recordset que se van a encontrar dentro de una página lógica.

• AbsolutePage: número de página del registro actual. Para movernos a una página determinada le asignaremos a esta propiedad el número de página correspondiente.

• AbsolutePosition: especifica la posición ordinal del registro actual dentro de un Recordset.

• PageCount: indica el número de páginas lógicas que posee un objeto Recordset.

• ActiveConnection: indica la conexión a la que esta asociado el objeto Recordset. Esta propiedad es sólo de lectura en el caso de que la propiedad Source tenga un valor válido.

• ActiveCommand: indica el objeto Command asociado con el objeto Recordset, si es que se ha utilizado uno para crear el Recordset. Esta propiedad es de sólo lectura.

• Source: indica la procedencia de los datos que contiene el Recordset, puede ser un objeto Command, una sentencia SQL, un nombre de una tabla , un procedimiento almacenado, una dirección de Internet, etc. Esta propiedad es de lectura/escritura si el Recordset está cerrado, y sólo de lectura si está abierto.

• DataMember: especifica el nombre de un miembro de datos del que obtener datos, este miembro de datos pertenece al origen de datos especificado en la propiedad DataSource.

Page 112: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

112

• DataSource: especifica un objeto que contiene datos que pueden ser representados como un objeto Recordset.

• Index: devuelve en una cadena el nombre del índice que se está utilizando actualmente.

• CursorLocation: indica la localización del motor del cursor, puede encontrarse en el cliente (adUseClient) o en el servidor (adUseServer).

• MarshalOptions: indica los registros que deben ser enviados al servidor.

• Sort: especifica el nombre del campo o campos por el que se encuentra ordenado el objeto Recordset, así como el orden.

• State: indica el estado del Recordset, si se encuentra abierto (adStateOpen) o cerrado (adStateClosed).

• LockType: indica el tipo de bloqueo que se aplicará al objeto Recordset.

• CursorType: indica el tipo de cursor que se utilizará en el Recordset.

• Bookmark: guarda una posición determinada dentro de un Recordset para volver a ella en otro momento.

• Status: indica el estado del registro actual.

• Filter: indica que se va a realizar un filtro sobre el Recordset.

• CacheSize: indica el número de registros que se encuentran en la memoria.

• EditMode: indica el proceso de edición del registro actual. Es de sólo lectura.

• MaxRecords: indica el número máximo de registros que debe contener un Recordset como resultado de una consulta. Se utiliza esta propiedad para limitar el número de registros devueltos por el proveedor desde una fuente de datos.

• RecordCount: devuelve el número de registros de un objeto Recordset.

• BOF: indica si la posición actual se encuentra antes del primer registro de un Recordset.

• EOF: indica si la posición actual se encuentra después del último registro de un Recordset.

Los métodos de estos objeto también son numerosos, y son los que aparecen a continuación:

• Open: este método abre un cursor que va a representar los registros resultantes de la realización de un comando SQL.

• Close: cierra el cursor, perdiendo todos los datos asociados.

• CompareBookmarks: compara dos Bookmark y devuelve el resultado de la comparación.

• Move: la posición actual se desplaza a la posición indicada.

• GetString: devuelve el Recordset completo dentro de una cadena.

Page 113: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

113

• MoveNext: el siguiente registro en un objeto Recordset pasa a ser el actual.

• MovePrevious: el registro anterior pasa a ser el registro actual.

• MoveFirst: el primer registro dentro de un objeto Recordset especificado, pasa a ser el registro actual.

• MoveLast: el último registro dentro de un objeto Recordset especificado, pasa a ser el registro actual.

• NextRecordset: elimina el Recordset actual y se desplaza al siguiente. Esto tiene sentido cuando el comando SQL que se ha ejecutado, y cuyo resultado contiene el objeto Recordset, está compuesto de varios resultados.

• AddNew: crea un nuevo registro en un objeto Recordset actualizable.

• Delete: borra el registro actual o grupo de registros.

• Find: busca en el Recordset un registro que coincida con el criterio especificado.

• Update: almacena todos los cambios realizados sobre el registro actual.

• CancelUpdate: cancela los cambios realizados sobre el registro actual o sobre un nuevo registro sobre el que todavía no se ha lanzado el método Update.

• UpdateBatch: almacena todos los cambios pendientes de diferentes registros.

• CancelBatch: cancela todos los cambios pendientes de diferentes registros.

• GetRows: devuelve los registros de un Recordset dentro de un array de dos dimensiones.

• Supports: indica si el objeto Recordset soporta una función determinada.

• Clone: crea una copia de un objeto Recordset existente.

• Requery: actualiza los datos de un Recordset volviendo a ejecutar el comando correspondiente que creó el objeto.

• Resync: refresca los datos en el Recordset actual.

• Save: almacena el Recordset en un fichero.

• Seek: localiza un valor dentro del Recordset.

• Supports: indica si un objeto Recordset soporta la funcionalidad específica que se le pasa como argumento a este método.

El objeto Recordset posee dos colecciones:

• Fields: esta colección está formada por objetos Field. Cada objeto Field representa una columna del Recordset, es decir, un campo.

• Properties: esta colección es como la que poseían los objetos Connection y Command.

Page 114: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

114

Creación y apertura de un objeto Recordset Debido a las enormes posibilidades de este objeto, sólo se comentarán aquí las operaciones básicas para abrir y cargar con datos un objeto recordset.

Vamos a comenzar este apartado comentando el Código fuente 99.

<HTML><HEAD><TITLE>Ejemplo objeto Recordset</TITLE></HEAD><BODY><%Set objRecordset=Server.CreateObject("ADODB.Recordset")objRecordset.Source="SELECT * FROM Usuarios"objRecordset.CursorType=adOpenStaticobjRecordset.ActiveConnection="DSN=FuenteBD;UID=pepe;PWD=xxx"objRecordset.Open%><center><strong>Número de registros: <%=objRecordset.RecordCount%><br><br></strong></center><table border="1" align="center"><tr><th>DNI</th><th>Nombre</th><th>Domicilio</th><th>Código Postal</th></tr><%while not objRecordset.EOF%>

<tr><td><%=objRecordset("DNI")%></td><td><%=objRecordset("Nombre")%></td><td><%=objRecordset("Domicilio")%></td><td align="right"><%=objRecordset("Codigo_Postal")%></td></tr><%objRecordset.MoveNext

WendobjRecordset.CloseSet objRecordset=Nothing%></table></body></html>

Código fuente 99

En este ejemplo se ha creado un objeto Recordset y se han manipulado tres propiedades del mismo. A la propiedad CursorType, es decir, la propiedad que indica el tipo de cursor que va a poseer el Recordset, se le ha asignado el valor adOpenStatic. De esta forma podremos utilizar una serie de características del Recordset. En este caso se ha utilizado la propiedad RecordCount que devuelve el número de registros que existen dentro un Recordset, además, este tipo de cursor permite un desplazamiento completamente libre sobre el Recordset.

La propiedad Source indica la procedencia de los datos del Recordset, el valor de esta propiedad es un comando SQL válido, como puede ser el nombre de una tabla, una sentencia SQL o el nombre de un procedimiento almacenado, también se le puede asignar un objeto Command. En este ejemplo a esta propiedad se le ha asignado una cadena que representa un sentencia SQL, en este caso una SELECT.

En la propiedad ActiveConnection se le indica al Recordset la conexión a la que se encuentra asociado. A esta propiedad se le puede pasar un objeto Connection ya creado, o bien, una cadena de

Page 115: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

115

conexión, como ocurre en este ejemplo. Lo normal es asignarle un objeto Connection, ya que de esta forma se puede reutilizar el mismo objeto Connection para distintos objetos Recordset, esto mismo ocurría con la propiedad ActiveConnection del objeto Command, que vimos anteriormente.

Una vez definidas las propiedades del Recordset, nos disponemos a obtener los datos, para ello se utiliza el método Open. Al lanzar este método el Recordset pasará a contener los datos indicados por la propiedad Source.

En este caso el método Open se ha utilizado sin parámetros, ya que las características del objeto Recordset ya las hemos definido a través de sus propiedades.

La sintaxis general del método Open es la siguiente:

ObjetoRecordset.Open OrigenDatos, Conexion, TipoCursor,TipoBloqueo, Opciones

Todos los parámetros son opcionales y se deberán especificar si no hemos dado algún valor a alguna de las propiedades del Recordset que representa cada uno de ellos. De esta forma, OrigenDatos es el valor que se le asignaría a la propiedad Source, Conexion representa el valor de la propiedad ActiveConnection, TipoCursor se corresponde con la propiedad CursorType, TipoBloqueo con la propiedad LockType y Opciones indica la naturaleza del origen de los datos.

A continuación se ofrecen varias formas que tenemos de obtener un objeto Recordset, en todos los casos se pretende que el contenido del objeto Recordset sea la tabla de autores (authors), y en todos los casos se va utilizar un cursor Forwar-only/Read-only.

Lo podemos obtener a partir de la ejecución directa sobre un objeto Connection, como se ve en el Código fuente 100.

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;Userid=sa"Set objRecordSet=objConexion.Execute("Select * from authors",,adCmdText)%>

Código fuente 100

También a partir de la ejecución directa de un objeto Command, como en el Código fuente 101.

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;Userid=sa"Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection=objConexionobjComando.CommandText="devuelveAutores"Set objRecordSet=objComando.Execute(,,adCmdStoredProc)%>

Código fuente 101

De momento no hemos utilizado el método Open, pero en el Código fuente 102 sí que lo vamos a utilizar. Se trata de obtener el Recordset a partir del objeto Command, pero especificando nosotros mismos las propiedades de nuestro Recordset.

Page 116: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

116

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;Userid=sa"Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection=objConexionobjComando.CommandText="devuelveAutores"Set objRecordSet=Server.CreateObject("ADODB.Recordset")objRecordSet.Open objComando ,,adOpenForwardOnly,adLockReadOnly,adCmdStoredProc%>

Código fuente 102

Como se puede observar en el parámetro del método Open correspondiente a la propiedad ActiveConnection del objeto Recordset no hemos indicado ninguna conexión, ya que se toma la conexión que se ha especificado para el objeto Command que utilizamos como origen de datos del objeto Recordset.

También podemos utilizar el método Open especificando la tabla, como en el Código fuente 103.

<%Set objConexion=Server.CreateObject("ADODB.Connection")objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;Userid=sa"Set objComando=Server.CreateObject("ADODB.Command")objComando.ActiveConnection=objConexionobjComando.CommandText="devuelveAutores"Set objRecordSet=Server.CreateObject("ADODB.Recordset")objRecordSet.Open"authors",objConexion,adOpenForwardOnly,adLockReadOnly,adCmdTable%>

Código fuente 103

Y por último podemos tener un objeto Recordset completamente independiente, que posea su propia conexión y recupere la información de la tabla a través de una sentencia SQL. Ver el Código fuente 104.

<%strConexion="Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;Userid=sa"strConsulta="select * from authors"Set objRecordSet=Server.CreateObject("ADODB.Recordset")objRecordSet.OpenstrConsulta,strConexion,adOpenForwardOnly,adLockReadOnly,adCmdText%>

Código fuente 104

Al igual que abrimos un Recordset, debmos cerrarlo con el método Close, de esta forma liberaremos todos los recursos del sistema asociados a este objeto, pero no lo eliminaremos de la memoria, para ello deberemos asignarle al objeto Recordset el valor Nothing.

En teoría, si cerramos el objeto Connection al que está asociado una serie de objetos Recordset, se cerrarán todos estos objetos Recordset dependientes de forma automática, pero es mejor, para liberar memoria y recursos de forma más fiable e inmediata, cerrar cada uno de los Recordset mediante estas dos sencillas líneas de código, como se muestra en el Código fuente 105.

Page 117: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 5. Componentes de acceso a datos. ADO

117

<%objRecordset.CloseSet objRecordset=Nothing%>

Código fuente 105

Page 118: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 119: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

CDONTS y ASP

Introducción En capítulos anteriores hemos visto distintos tipos de componentes y objetos que se pueden utilizar en ASP:

• Objetos pertenecientes al modelo de objetos de ASP (Request, Server, Application, etc.).

• Componentes incluidos en el intérprete de secuencias de comandos de VBScript (Dictionary, FileSystemObject, TextStream, etc.).

• Componentes incluidos con la instalación de ASP (AdRotator, MyInfo, ContentRotator, Tools, ADO, etc.).

En este capítulo vamos a ver un conjunto de componentes agrupados todos ellos bajo el nombre de CDONTS (Collaboration Data Objects for NT Server). CDONTS es una librería de Microsoft que ofrece la posibilidad de utilizar sistemas de mensajería, basándose en servidores de correo como Microsoft Exchange Server o el servicio SMTP incluido en IIS 5.0.

Como el propio nombre de estos componentes indica, son componentes para NT Server, en nuestro caso para 2000 Server.

CDONTS se instala como parte del servicio de correo SMTP. Podremos acceder de igual forma a Microsoft Exchage Server 5.5 o superior y al servicio de correo SMTP incluido en IIS 5.0.

En el presente capítulo los ejemplos realizados con CDONTS han sido probados con el servicio de correo de IIS 5.0, para averiguar si tenemos instalado este servicio de IIS 5.0 debemos utilizar el

Page 120: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

120

Administrador de servicios de Internet y comprobar si existe el nodo llamado Servidor virtual SMTP predeterminado.

Figura 21. El servicio SMTP dentro de IIS 5.0

Si no se encuentra instalado este servicio acudiremos a la opción Agregar o quitar programas del Panel de control. Dentro de esta opción seleccionaremos Agregar o quitar componentes de Windows y de los componentes seleccionaremos Servicios de Internet Information Server (IIS). Si pulsamos el botón etiquetado como Detalles veremos los subcomponentes de IIS y seleccionaremos el componente Servicio SMTP.

Figura 22. Instalando el servicio SMTP

Page 121: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

121

A lo largo de este capítulo comentaremos cuando sea necesario algunos puntos relacionados con la configuración del servicio SMTP de IIS 5.0.

Antes de seguir con los distintos apartados que exponen el modelo de objetos de CDONTS, vamos a ver el Código fuente 106 que utiliza un objeto de CDONTS llamado NewMail y que nos permite de manera muy sencilla enviar un mensaje de correo electrónico.

<%Set objMail=Server.CreateObject("CDONTS.NewMail")objMail.Send "[email protected]","[email protected]","Asunto","Hola que tal teva..."%>

Código fuente 106

Con este código ya podríamos enviar un mensaje de correo a través de nuestro servicio SMTP. En siguientes apartados comentaremos detenidamente de nuevo este código.

Modelo de objetos de CDONTS La librería CDONTS se encuentra formada por un modelo de objetos que vamos a comentar es este capítulo. Veamos gráficamente este modelo con la Figura 23.

Figura 23. Modelo de objetos de CDONTS

Como se puede observar todos los objetos se encuentran relacionados a excepción del objeto NewMail que aparece desconectado del resto. A continuación se ofrece una breve descripción de los objetos incluidos en CDONTS.

• NewMail: mediante este objeto podremos enviar nuevos mensajes de correo.

Page 122: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

122

• Session: este objeto contiene toda la información necesaria para manipular mensajes y también las carpetas de entrada (inbox) y de salida de mensajes (outbox), es decir, podremos leer los mensajes revibidos y enviar nuevos mensajes. Mediante este objeto podremos acceder a los mensajes almacenados de un usuario determinado. El resto de los objetos de CDONTS tienen como referencia el objeto Session.

• Folder: representa una carpeta o contenedor que contiene los mensajes almacenados correspondientes a la sesión actual. Vamos a poder acceder a los mensajes recibidos y a los mensajes pendientes de enviar.

• Message: se corresponde con un mensaje de un objeto Folder, el objeto Folder ofrece una propiedad llamada Messages que contiene una colección de objetos Message.

• AddressEntry: este objeto contiene información relativa al remitente de un mensaje determinado, se obtiene a partir de la propiedad Sender del objeto Message.

• Attachments: colección perteneciente al objeto Message que contiene objetos Attachment, y que representa todos los adjuntos de un mensaje de correo determinado.

• Attachment: objeto que representa un fichero adjunto de un mensaje.

• Recipients: colección perteneciente al objeto Message que contiene objetos Recipient, y que representa todos los destinatarios de un mensaje determinado.

• Recipient: objeto que representa un destinatario de un mensaje.

En los distintos apartados de este tema veremos cada uno de los objetos del modelo de objetos de CDONTS.

El objeto Newmail Como ya hemos dicho anteriormente, este objeto que se encuentra fuera de la jerarquía del objeto Session nos va a permitir enviar mensajes de correo electrónico.

Los métodos que ofrece este objeto son:

• Send(remitente, destinatario, asunto, mensaje, importancia): mediante este método enviaremos un mensaje al destinatario que indiquemos. Todos los parámetros son opcionales, pudiendo aplicar el método Send() sin parámetros, ya que el objeto NewMail ofrece una serie de propiedades que permiten configurar el mensaje antes de enviarlo. En el parámetro destinatario podemos expresar distintos destinatarios separados con comas. Tanto destinatario como remitente son direcciones de correo electrónico. En el asunto especificaremos el asunto del mensaje y en mensaje el cuerpo del mensaje, es decir, el mensaje en sí. Y mediante el parámetro importancia indicamos si es alta (cdoHigh), normal (cdoNormal) o baja (cdoLow), por defecto este parámetro tiene el valor cdoNormal. Todos estos parámetros se corresponden con propiedades del objeto NewMail que veremos a continuación.

• AttachFile(fuente, nombreFichero, codificación): permite adjuntar el fichero especificado en el parámetro fuente a un mensaje de correo, se debe indicar una ruta física completa, el resto de los parámetros son opcionales. En nombreFichero indicamos el nombre con el que aparece el fichero adjunto en el cliente de correo, y en codificación indicamos el método de

Page 123: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

123

codificación empleado para enviar el fichero adjunto, esta parámetro tiene dos posibles valores cdoEncodingUUencode y cdoEncodingBase64, por defecto presenta el primero de ellos.

En el ejemplo del Código fuente 107 se trata de enviar un correo a [email protected], que es de prioridad baja y que posee dos ficheros adjuntos.

<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\cdonts.dll"--><%Set objMail=Server.CreateObject("CDONTS.NewMail")objMail.AttachFile "c:\tmp\imagen.png","Figura"objMail.AttachFile "c:\tmp\tema30.html","Tema en HTML"objMail.Send "[email protected]","[email protected]"_

,"Asunto","Hola que tal te va...",cdoLow%>

Código fuente 107

Como se puede observar se ha realizado una referencia a la librería de CDONTS, para así poder utilizar las constantes definidas en ella. En este caso se ha utilizado la constante para establecer la prioridad el mensaje.

Si todo ha funcionado correctamente el mensaje habrá llegado a su destinatario. Si el destinatario abre el mensaje de correo con el cliente de correo Microsoft Outlook Express tendrá el aspecto que muestra la Figura 24.

Figura 24. El mensaje en Outlook Express

Page 124: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

124

Las propiedades que posee el objeto NewMail son las siguientes, y como ya hemos dicho algunas de ellas se corresponden con los parámetros del método Send():

• From: en esta propiedad indicamos el remitente del mensaje de correo. Se asigna una cadena que representa una dirección de correo, no es posible utilizar nombres.

• To: destinatario del mensaje, si existen varios destinatarios se deben separar mediante comas.

• CC: indicamos las direcciones de correo a las que deseamos enviar copia del mensaje.

• BCC: tiene la misma función que el caso anterior, pero en este caso se oculta la lista de destinatarios que reciben copia.

• Importance: es la importancia o prioridad del mensaje, se le puede asignar los valores cdoHigh(alta), cdoNormal(normal) o cdoLow(baja). Por defecto tiene el valor de prioridad normal.

• Body: representa el cuerpo del mensaje, es decir, el texto del mensaje. Puede contener texto plano o en HTML.

• BodyFormat: mediante este propiedad indicamos el formato del cuerpo del mensaje, puede aceptar los valores cdoBodyFormatHTML, para indica que el formato del cuerpo del mensaje es HTML o cdoBodyFormatText para indicar que el formato del cuerpo del mensaje es texto plano, por defecto el valor de esta propiedad es cdoBodyFormatText. Para poder utilizar el valor cdoBodyFormatHTML se debe utilizar el formato de correo MIME, indicándolo en la propiedad MailFormat.

• MailFormat: indica el formato con el que se crean los mensajes de correo, puede tener dos valores posibles, formato de texto plano (cdoMailFormatText), que es el valor por defecto, y formato MIME (cdoMailFormatMIME). Con el formato MIME podemos enviar contenidos más elaborados en nuestros mensajes de correo.

• Version: esta propiedad de sólo lectura devuelve la versión de la librería CDONTS que estamos utilizando, la versión actual es la 1.2.

• ContentLocation: permite especificar un camino relativo o absoluto para todas las URLs contenidas en el cuerpo del mensaje, esta propiedad tiene sentido cuando estamos enviando mensajes en formato HTML.

• ContentBase: propiedad relacionada con la anterior, ya que nos permite especificar la ruta base para todas URLs contendidas en el cuerpo del mensaje. Los valores de ContentLocation se consideran relativos a los valores de ContentBase. Así si la propiedad ContentBase tiene el valor "http://www.almagesto.com" y ContentLocation tiene el valor "images/", para las URLs presentes en el cuerpo del mensaje se construirá la ruta http://www.almagesto.com/images/. Esto sería equivalente a asignar a la propiedad ContentBase el valor "http://www.almagesto.com/images/".

Veamos un ejemplo que muestra la utilización de las propiedades del objeto NewMail. En este caso se definen algunas de las propiedades y luego se envía el correo mediante el método Send() sin parámetros.

<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\cdonts.dll"-->

Page 125: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

125

<%Set objMail=Server.CreateObject("CDONTS.NewMail")objMail.From="[email protected]"objMail.To="[email protected]"objMail.Importance=cdoLowobjMail.MailFormat=cdoMailFormatMIMEobjMail.Subject="Asunto"objMail.BodyFormat=cdoBodyFormatHTMLobjMail.ContentBase="http://aesteban/images/"strTexto="<html><body><b><i>Hola que tal te va...</i></b><br>"strTexto=strTexto&"<div align='center'><img src='almagesto.gif'></div>"strTexto=strTexto&"</body></html>"objMail.Body=strTextoobjMail.Send%>

Código fuente 108

En este ejemplo se ha dado el formato MIME al mensaje y al cuerpo el formato HTML, el resultado de visualizar este correo mediante el cliente de correo Outlook Express es el que muestra la Figura 25.

Figura 25. Mensaje de correo con formato

A través del objeto NewMail también podemos tener acceso y manipular las cabeceras del mensaje de correo, que normalmente en los clientes de correo permanecen ocultas. Parte de la información contenida en las cabeceras se genera a partir de las propiedades del objeto NewMail y otra parte las genera el servidor de correo de forma automática al enviar el mensaje.

Estas cabeceras las podemos ver con el cliente de correo Outlook Express si en el menú de el mensaje acudimos a la opción Archivo|Propiedades, y luego elegimos la pestaña Detalles.

Mediante la colección Value del objeto NewMail podemos añadir nuevas cabeceras a los mensajes o modificar las existentes.

En el Código fuente 109 se añade una nueva cabecera y se modifica la cabecera Subject.

Page 126: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

126

<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\cdonts.dll"--><%Set objMail=Server.CreateObject("CDONTS.NewMail")objMail.From="[email protected]"objMail.To="[email protected]"objMail.Importance=cdoLowobjMail.MailFormat=cdoMailFormatMIMEobjMail.Subject="Asunto"objMail.BodyFormat=cdoBodyFormatHTMLobjMail.ContentBase="http://aesteban/images/"strTexto="<html><body><b><i>Hola que tal te va...</i></b><br>"strTexto=strTexto&"<div align='center'><img src='imagen.gif'></div>"strTexto=strTexto&"</body></html>"objMail.Body=strTextoobjMail.Value("Subject")="Modifico el asunto"objMail.Value("NuevaCabecera")="Nuevo valor"objMail.Send%>

Código fuente 109

Los detalles del mensaje en Outlook Express tienen el aspecto que nos muestra la

Figura 26. Cabeceras del mensaje

Hemos visto lo sencillo que resulta enviar un mensaje mediante el objeto NewMail de la libreía CDONTS, ahora vamos a seguir viendo los distintos objetos que proporciona esta librería. Los siguientes objetos permiten acceder a los mensajes que se encuentran almacenados en el servidor de correo.

Page 127: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

127

El objeto Session Del objeto Session dependen el resto de los objetos de la librería CDONTS, a través del objeto Session iniciamos una sesión con el servidor de correo mediante un usuario determinado.

El servidor con el que iniciamos la sesión será el servidor de correo que se encuentre instalado en el servidor Web en el que se ejecutan las páginas ASP, como ya hemos dicho este servidor puede ser el servicio SMTP incluido en IIS 5.0 o Exchange Server 5.5 o superior.

Para realizar las pruebas con los distintos objetos de CDONTS se ha utilizado el servicio SMTP de IIS 5.0. Para indicar una dirección de correo dentro de este servidor utilizaremos la siguiente sintaxis: cuenta@nombreServidor, siendo nombreServidor el nombre del dominio por defecto del servidor SMTP. Aunque desde el Administrador de servicios de Internet podemos definir alias para el dominio por defecto. Para ello acudiremos dentro del Administrador de servicios de Internet al nodo llamado Servidor virtual SMTP predeterminado, y en la rama Dominios pulsando con el botón derecho del ratón seleccionamos la opción Nuevo|Dominio, en ese momento se lanza el asistente para la creación de nuevos dominios.

Dentro del asistente seleccionamos la opción de Alias y pulsamos el botón Siguiente. A continuación se debe indicar el nombre que vamos a dar al alias de nuestro dominio, yo en mi caso le he llamado mail.angel.es, siendo mi dominio por defecto aesteban, es decir, el nombre de mi servidor. Pulsamos el botón Finalizar. Si todo ha sido correcto veremos una pantalla similar a la de la Figura 27.

Figura 27. Creando dominios alias

Después de este pequeño comentario acerca de la creación de dominios, volvamos al tema principal que nos ocupa dentro de este apartado.

El objeto Session presenta los siguientes métodos:

• LogonSMTP(nombre, direccion): mediante este método se inicia una sesión con el servidor de correo. En el parámetro nombre se indica el nombre que se desea que se muestre al usuario, y en dirección la dirección completa del usuario que se desea conectar al servidor de correo. Este método no realiza ningún tipo de validación, si la conexión no se ha podido establecer no recibimos ningún mensaje de error. Cada usuario conectado tendrá acceso a su propio buzón, pudiendo leer el correo de su "bandeja de entrada" (inbox) y enviar correo a través de su "bandeja de salida" (outbox).

Page 128: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

128

• LogOff(): este método finalizará la sesión actual con el servidor de correo. Podremos reutilizar el objeto Session si deseamos realizar una nueva sesión llamando de nuevo al método LogonSMTP.

• GetDefaultFolder(tipoCarpeta): mediante este método se obtiene un objeto Folder que representa la bandeja o carpeta de entrada o la de salida del usuario conectado. El parámetro de este método puede tener dos valores cdoDefaultFolderInbox(1) para obtener la bandeja de entrada y poder leer los mensajes recibidos o cdoDefaultFolderOutbox(2) para obtener la bandeja de salida y poder enviar mensajes.

• SetLocaleID(codigo): este método permite establecer un código de localización que afectará al entorno del lenguaje, formatos horarios, fechas, valores monetarios, etc. El parñametro tiene los mismos valores que vimos para la propiedad LCID del objeto integrado Session de ASP. Este método si se utiliza se debe lanzar antes de establecer la sesión con el servidor de correo mediante el método LogonSMTP().

Ahora vamos a pasar a comentar las propiedades del objeto Session:

• Inbox: propiedad de sólo lectura que devuelve un objeto Folder que representa la bandeja de entrada de la sesión actual.

• Outbox: propiedad de sólo lectura que devuelve un objeto Folder que representa la bandeja de salida de la sesión actual.

• MessageFormat: propiedad de lectura y escritura que permite obtener e indicar el formato de codificación de los mensajes. Tiene dos valores posibles CDOMime, para mensajes de tipo MIME, y CDOText para mensajes de tipo texto plano.

• Name: propiedad de sólo lectura que contiene el nombre del usuario conectado y que se ha especificado en el método LogonSMTP().

• Version: propiedad de sólo lectura que indica la versión de la librería CDONTS.

El objeto Session además de estas propiedades ofrece otras tres que son comunes a todos los objetos de su jerarquía, y son las siguientes:

• Session: esta propiedad devuelve el objeto Session que representa la raíz de la jerarquía de un objeto determinado.

• Class: esta propiedad devuelve un entero que nos indica el tipo de objeto: Session(0), Folder(2), Message(3), Recipient(4), Attachment(5), AddressEntry(8), Messages(16), Recipients(17) y Attachments(18).

• Parent: devuelve un objeto que representa el padre del objeto especificado. La propiedad Parent del objeto Session devuelve Nothing y la del objeto AddressEntry devuelve un objeto Message.

Una vez comentados los métodos y propiedades del objeto Session vamos a mostrar un ejemplo que hace uso de algunos de ellos.

Este ejemplo consiste en un formulario que nos permite conectarnos al servicio SMTP de IIS 5.0. El formulario permite especificar el nombre del usuario y la cuenta de correo del usuario que se va a conectar. Una vez que se ha establecido la conexión con el servidor SMTP se muestran algunos de los valores de las propiedades de la sesión actual. También existe la posibilidad de desconectarnos para

Page 129: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

129

iniciar una nueva sesión, la sesión se debe almacenar en una variable a nivel de sesión, ya que más tarde deberemos utilizarla para realizar la desconexión. Veamos el Código fuente 110. Y en la Figura 28 se puede ver un ejemplo de la ejecución del código anterior.

<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\cdonts.dll"--><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><%If Request.Form("Desconectar")<>"" Then

'se realiza la desconexiónSet objSession=Session("oSession")objSession.LogOff

End ifIf Request.Form("Conectar")="" Then%>

<form action="<%=Request.ServerVariables("SCRIPT_NAME")%>" method="post">Nombre:<input type="text" name="nombre" size="20" value=""><br>Cuenta de correo:<input type="text" name="cuenta" size="20"

value=""><br><input type="submit" name="conectar" value="Conectar">

</form><%Else

'se realiza la conexiónSet objSession=Server.CreateObject("CDONTS.Session")objSession.LogonSMTP Request.Form("nombre"),Request.Form("cuenta")Set Session("oSession")=objSession%>Usuario conectado: <%=objSession.Name%><br><%If objSession.MessageFormat=CDOMime Then

strFormato="CDOMime"Else

strFormato="CDOText"End if%>Formato de los mensajes: <%=strFormato%><br>Versión de CDONTS: <%=objSession.Version%><br><form action="<%=Request.ServerVariables("SCRIPT_NAME")%>" method="post">

<input type="submit" name="desconectar" value="Desconectar"></form>

<%End if%></BODY></HTML>

Código fuente 110

Figura 28. Utilizando el objeto Session de CDONTS

Page 130: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

130

El objeto Folder Este objeto representa una carpeta o contenedor que se va a corresponder con las bandejas de entrada y de salida de los mensajes de correo de la sesión actual. Un objeto Folder lo obtenemos a partir de la propiedades Inbox y Outbox de un objeto Session que representa una sesión ya establecida con el servicio SMTP. También lo podemos obtener a través del método GetDefaultFolder().

El objeto Folder suele representar las siguientes carpetas estándar:

• Bandeja de entrada (inbox): es la localización que tiene el correo recibido.

• Bandeja de salida (outbox): es la localización temporal que tiene el correo antes de proceder a su envío.

Mediante el objeto Folder vamos a tener acceso a los contenidos de la carpeta indicada. Aunque tenemos acceso a los mensajes este acceso es algo restrictivo, podremos eliminar mensajes existentes, leer mensajes existentes y enviar mensajes nuevos, sin embargo no podemos cambiar las propiedades de los mensajes ya existentes.

En este punto se debe hacer una aclaración acerca del servidor SMTP de IIS y los objetos de la librería CDONTS.

El servidor de correo SMTP de IIS 5.0 a diferencia del servidor Exchange Server, no posee buzones individuales, es decir, no existe una bandeja para cada usuario sino que todos los mensajes recibidos se almacenan en una misma localización y todos los mensajes enviados en otra.

Si hemos aceptado las configuraciones por defecto al instalar el servicio SMTP de IIS, la bandeja de entrada se corresponde con el directorio c:\inetpub\mailroot\Drop y la de salida con el directorio c:\inetpub\mailroot\Pickup.

Sin embargo aunque los buzones sean globales, cuando iniciamos la sesión con el servidor SMTP, a través de los objetos de CDONTS únicamente tendremos acceso a los mensajes que se corresponden con los del cliente que se a conectado, de esta forma se intenta simular los buzones personales.

Debido a esto para utilizar el servicio SMTP no es necesario configurar buzones ni definir cuentas de correo de usuarios, de todas formas en los siguientes ejemplos todo esto se verá más claro.

Hecha esta aclaración volvemos a tratar el objeto Folder, empezando ahora a comentar las propiedades que nos ofrece.

• Name: propiedad de sólo lectura que contiene el nombre de la carpeta a la que representa el objeto Folder. Normalmente tiene los valores "Inbox" y "Outbox".

• Messages: esta propiedad devuelve una colección de objetos Message, que representará los mensajes presentes en la carpeta.

Veamos el tratamiento que tiene la colección Messages.

La colección Messages posee las siguientes propiedades:

• Count: número de objetos Message contenidos en la misma.

• Item(indice): devuelve un objeto Message de la colección cuyo índice coincide con el parámetro indicado. El primer índice es 1.

Page 131: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

131

Y los siguientes métodos:

• Add(asunto, texto, importancia): permite añadir un nuevo mensaje a la colección. Todos los parámetros son opcionales, y cuando se ejecuta este método se devuelve un objeto Message para poder manipularlo. Este método únicamente se puede aplicar a una colección Messages que pertenece a la bandeja de salida.

• Delete(): elimina todos lo mensajes de la colección. Para borrar un mensaje en concreto debemos utilizar el método Delete del objeto Message, pero eso lo veremos en el siguiente apartado.

• GetFirst(): método que devuelve el primer objeto Message de la colección Messages. Si el objeto no existe devuelve Nothing.

• GetLast(): método que devuelve el último objeto Message de la colección Messages. Si el objeto no existe devuelve Nothing.

• GetNext(): método que devuelve el siguiente objeto Message de la colección Messages. Si el objeto no existe devuelve Nothing.

• GetPrevious(): método que devuelve el anterior objeto Message de la colección Messages. Si el objeto no existe devuelve Nothing.

Vamos a ampliar y modificar el ejemplo del apartado anterior que utilizaba el objeto Session de CDONTS para establecer una conexión, para mostrar la utilización práctica del objeto Folder.

En este nuevo ejemplo vamos a establecer la sesión con el servicio SMTP con el mismo formulario y vamos a indicar el número de mensajes que posee el usuario conectado en ese momento en cada una de sus bandejas.

También aparece un nuevo botón que permite eliminar al usuario todos los mensajes de su bandeja de entrada. El Código fuente 111.

<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\cdonts.dll"--><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><%If Request.Form("Desconectar")<>"" AND Session("oSession")<>"" Then

'se realiza la desconexiónSet objSession=Session("oSession")objSession.LogOffSession("oSession")=""

Elseif Request.Form("EliminarInbox")<>"" Then'se eliminan todos los mensajes de InboxSet objSession=Session("oSession")Set objFolderInbox=objSession.InboxobjFolderInbox.Messages.Delete

End ifIf Request.Form("Conectar")="" AND Session("oSession")="" Then%>

<form action="<%=Request.ServerVariables("SCRIPT_NAME")%>" method="post">Nombre:<input type="text" name="nombre" size="20" value=""><br>Cuenta de correo:<input type="text" name="cuenta" size="20"

value=""><br><input type="submit" name="conectar" value="Conectar">

</form>

Page 132: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

132

<%Elseif Request.Form("Conectar")<>"" Then'se realiza la conexiónSet objSession=Server.CreateObject("CDONTS.Session")objSession.LogonSMTP Request.Form("nombre"),Request.Form("cuenta")'se guarda a nivel se sesión la referencia a la sesión establecida'con el servicio SMTPSet Session("oSession")=objSession

End ifIf Session("oSession")<>"" Then

'se recupera la sesión con SMTPSet objSession=Session("oSession")%>Usuario conectado: <b><%=objSession.Name%></b><br><form action="<%=Request.ServerVariables("SCRIPT_NAME")%>" method="post">

<input type="submit" name="desconectar" value="Desconectar"><input type="submit" name="EliminarInbox" value="Vaciar Inbox">

</form><%Set objFolderInbox=objSession.GetDefaultFolder(cdoDefaultFolderInbox)%>El número de mensajes en <%=objFolderInbox.Name%> es<%=objFolderInbox.Messages.Count%><br><%Set objFolderOutbox=objSession.Outbox%>El número de mensajes en <%=objFolderOutbox.Name%> es<%=objFolderOutbox.Messages.Count%>

<%End if%></BODY></HTML>

Código fuente 111

Y en la Figura 29 se muestra un ejemplo de un usuario conectado.

Figura 29. Utilizando el objeto Folder

En el siguiente apartado veremos como mostrar los datos de los mensajes contenidos en las bandejas y también como eliminar mensajes determinados y enviar nuevos.

Page 133: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

133

El objeto Message Este objeto representa un mensaje contenido en un objeto Folder, es decir, en una carpeta. Una referencia a un objeto Message la obtenemos a través de la colección Messages del objeto Folder correspondiente.

En este apartado además de comentar el objeto Message vamos a tratar las dos colecciones que contiene: Recipients y Attachments, y también veremos el objeto AddressEntry, que permite especificar los datos del remitente.

El objeto Message lo utilizaremos para manipular los mensajes de correo, y para ello este objeto ofrece las siguientes propiedades:

• Attachments: una colección de objetos Attachment que contiene los ficheros adjuntos de un mensaje.

• ContentBase: URL base para los contenidos del mensaje.

• ContentID: identificador del tipo de contenido MIME del mensaje.

• ContentLocation: URL relativa para los contenidos del mensaje.

• HTMLText: cuerpo del mensaje en formato HTML.

• Importance: prioridad del mensaje.

• MessageFormat: formato de codificación del mensaje.

• Recipients: colección de objetos Recipient que representa a cada uno de los destinatarios del mensaje.

• Sender: devuelve un objeto AddressEntry que representa al remitente del mensaje.

• Size: tamaño en bytes del mensaje.

• Subject: asunto del mensaje.

• Text: cuerpo del mensaje en formato de texto plano.

• TimeReceived: fecha y hora de recepción del mensaje.

• TimeSent: fecha y hora de envío del mensaje.

Muchas de estas propiedades son comunes a las del objeto NewMail.

El objeto Message ofrece los siguientes métodos:

• Send(): este método envía el mensaje a los destinatarios indicados.

• Delete(): elimina el mensaje de forma permanente.

Vamos a seguir utilizando el mismo ejemplo que el de los apartados anteriores para mostrar la utilización del objeto Message. En este caso se trata de mostrar el contenido de la bandeja de entrada

Page 134: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

134

del usuario que se ha conectado. La información que se va a mostrar de cada mensaje es la prioridad, remitente, asunto y fecha de recepción.

Para mostrar el contenido de la bandeja de entrada simplemente recorreremos la colección Messages de objeto Folder que se corresponde con inbox. Y utilizaremos las propiedades correspondientes de cada objeto Message para mostrar la información deseada.

El código que se debe añadir al ejemplo anterior, después de haber obtenido una referencia a la carpeta Inbox, es el Código fuente 112.

<%If objFolderInbox.Messages.Count>0 Then%><table border="0"><tr><th>Prioridad</td><th>De</th><th>Asunto</th><th>Recibido</th></tr><%For Each objMessage In objFolderInbox.Messages%>

<tr><td><%=Prioridad(objMessage.Importance)%></td><td><%=objMessage.Sender%></td><td><%=objMessage.Subject%></td><td><%=objMessage.TimeSent%></td></tr>

<%Next%></table>

<%End if%>

Código fuente 112

Se utiliza una función llamada Prioridad, cuya función es la de devolver una cadena con el texto que representa a la prioridad correspondiente, su código es el Código fuente 113.

<%Function Prioridad(prio)Select Case prio

Case cdoLow: Prioridad="Baja"Case cdoNormal: Prioridad="Normal"Case cdoHigh: Prioridad="Alta"

End SelectEnd Function%>

Código fuente 113

Y un ejemplo de la ejecución del Código fuente 113 lo tenemos en la Figura 30.

Como ya hemos comentado al principio el objeto Message ofrece dos colecciones a través de de sus propiedades Recipients y Attachments.

La colección Recipients contiene objetos Recipient que representan a cada uno de los destinatarios de un mensaje. Para añadir un nuevo destinatario utilizamos el método Add() sobre la colección Recipients, que además nos devolverá un objeto Recipient por si deseamos manipularlo. La sintaxis del método Add() es la siguiente:

Set objRecipient=colRecipients.Add(nombre, dirección, tipo)

Page 135: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

135

Figura 30. Mensajes de la bandeja de entrada

Todos los parámetros de este método son opcionales. En nombre indicamos el nombre del destinatario que se va a mostrar, en dirección se indica la dirección de correo del destinatario y en tipo una constante que indica si es un destinatario de copia o no. Los valores de tipo pueden ser CdoTO (es el destinatario sin copia), CdoCC (se le envía copia) o CdoBCC (se le envía copia pero no aparece en la lista de los demás destinatarios.

Los mensajes contenidos en la bandeja de entra no se pueden modificar, sólo son de lectura, por lo tanto si lanzamos el método Add() sobre una colección Recipients de un objeto Message que pertenezca al objeto Folder Inbox, se producirá un error.

El método Delete de la colección Recipients elimina todos los objetos Recipient de la colección.

Los parámetros que aparecían en el método Add() de la colección Recipients se corresponden con las propiedades del objeto Recipient, y son las siguientes:

• Name: nombre del destinatario. Es el nombre que se va a mostrar.

• Address: dirección de correo del destinatario.

• Type: tipo de destinatario, puede tener uno de los siguientes valores: CdoTO, CdoCC, CdoBCC.

La otra colección que podemos encontrar en el objeto Message es la colección Attachments que se encuentra formada por objetos Attachment y que representa los ficheros adjuntos de un mensaje determinado.

Mediante el método Delete() de la colección Attachments eliminamos todos los ficheros adjuntos de un mensaje, y mediante el método Add() se añade un nuevo fichero adjunto.

Page 136: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

136

Al igual que ocurría con la colección Recipients, al método Add() devuelve un objeto Attachment para poder manipularlo, la sintaxis de este método es:

Set objAttachment=colAttachments.Add(nombre, tipo, fuente, localización, base)

Todos los parámetros de este método son opcionales. El parámetro nombre indica el nombre con el que se va a mostrar el adjunto, el tipo de adjunto puede ser cdoFileData(1) para indicar un fichero y cdoEmbeddedMessage(4) para indicar que el adjunto es otro mensaje. En fuente se indica la ruta completa del fichero adjunto o bien un objeto Message en el caso de ser el adjunto de tipo cdoEmbeddedMessage. Localización y base son dos parámetros que especifican cabeceras para ficheros adjuntos de tipo MIME.

El método Add() no se puede utilizar con mensajes que se encuentren en la bandeja de entrada, ya que estos mensajes son únicamente de lectura.

El objeto Attachment ofrece una serie de propiedades que se corresponden con los parámetros del método Add() de la colección Attachments, y son las siguientes:

• ContentBase: cabecera para un adjunto MIME que especifica la dirección URL base.

• ContentID: identificador único para un adjunto MIME.

• ContentLocation: URL relativa para un adjunto MIME.

• Name: nombre con el que se va a mostrar el fichero adjunto.

• Source: ruta o localización del adjunto.

• Type: tipo de adjunto, puede presentar las siguientes constantes cdoFileData o cdoEmbedded-Message.

Además el objeto Attachment ofrece los siguientes métodos:

• Delete(): para eliminar un adjunto determinado.

• ReadFromFile(nombreFichero): carga el adjunto desde el fichero indicado por parámetro. Se debe indicar la ruta completa del fichero.

• WriteToFile(nombreFichero): escribe en el fichero indicado el contenido del adjunto.

Relacionado con el objeto Message también encontramos el objeto AddressEntry. El objeto AddressEntry se obtiene a través de la propiedad Sender del objeto Message y representa al remitente del mensaje.

Este objeto ofrece las siguientes propiedades:

• Name: nombre del remitente o alias, es el nombre que se muestra.

• Address: dirección de correo electrónico del remitente.

• Type: tipo de dirección. Para CDONTS siempre es "SMTP".

Ahora vamos a mostrar un ejemplo que utiliza todos estos nuevos objetos. Para ello vamos a retomar el ejemplo visto con el objeto NewMail, y lo que vamos a hacer es la misma operación, es decir,

Page 137: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

137

enviar un correo nuevo, pero utilizando algunos de los objetos vistos hasta ahora que dependen del objeto Session inicial de la librería CDONTS.

<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\cdonts.dll"--><%'se realiza la conexiónSet objSession=Server.CreateObject("CDONTS.Session")objSession.LogonSMTP "Angel","[email protected]"'se obtiene la bandeja de salidaSet objFolderOutbox=objSession.Outbox'se obtiene la colección de mensajesSet colMensajes=objFolderOutbox.MessagesstrTexto="Mensaje enviado con los objetos de CDONTS"'se añade un mensaje nuevo y se obtiene la referencia al mismoSet objMensaje=colMensajes.Add("Prueba de CDONTS",strTexto,cdoNormal)'añadimos un adjunto al mensajeobjMensaje.Attachments.Add "Fichero Adjunto",cdoFileData,"c:\tmp\imagen.png"'añadimos un destinatario al mensajeobjMensaje.Recipients.Add "Jose María","[email protected]",cdoTO'añadimos un destinatario al que se envía una copiaobjMensaje.Recipients.Add "Pepe","[email protected]",cdoCC'se envía el mensajeobjMensaje.Send%>

Código fuente 114

Como podemos comprobar es mucho más sencillo y recomendable utilizar el objeto NewMail a la hora de enviar correo. El mensaje se ha enviado con el remitente que corresponde a la sesión actual, en este caso [email protected]. Si abrimos el mensaje que hemos creado con el cliente de correo Outlook Express, vemos que tiene el aspecto que nos muestra la Figura 31.

Figura 31. Mensaje leído con Outlook Express

Page 138: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

138

Y si queremos podemos ver los detalles del mismo(Figura 32).

Figura 32. Detalles del mensaje

Antes de terminar este tema vamos añadir una mayor funcionalidad al ejemplo en el que mostrábamos el contenido de la bandeja de entrada de un usuario conectado a una sesión de nuestro servidor SMTP.

La nueva funcionalidad consiste en poder visualizar el contenido de cada uno de los mensajes que se encuentran en la bandeja de entrada del usuario conectado actualmente. Para ello vamos a situar en un enlace los asuntos de cada uno de los mensajes y para identificar cada uno de ellos utilizar una variable del QueryString que va a contener un entero para cada mensaje.

En la página de lectura del mensaje además vamos a permitir la opción de borrar el mensaje que estamos leyendo.

Veamos el Código fuente 115 que debemos modificar en la página que muestra el contenido de la bandeja de entrada. Se debe añadir la creación de los enlaces para cada asunto en el bucle For Each que recorre todos los mensajes.

<%i=0For Each objMessage In objFolderInbox.Messages

i=i+1%><tr><td><%=Prioridad(objMessage.Importance)%></td><td><%=objMessage.Sender%></td>

Page 139: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

139

<td><ahref="LeerMensaje.asp?idmensaje=<%=i%>"><%=objMessage.Subject%></a></td>

<td><%=objMessage.TimeSent%></td></tr>

<%Next%>

Código fuente 115

Como se puede comprobar en los enlaces se hace referencia a una página llamada LeerMensaje.asp, es en esta página dónde se encuentra el código necesario para mostrar el contenido del mensaje solicidado.

La página de lectura de mensajes va a tener un área de texto para mostrar el contenido del mensaje, y también dos botones: uno para volver a la página anterior, y otro para eliminar el mensaje que estamos leyendo. La página encargada de borrar el mensaje no es la de lectura de los mimos, sino que el mensaje será borrado en la página que muestra el contenido de al bandeja de entrada.

Antes de nada veamos el Código fuente 116 de la página de lectura de mensajes.

<%'recuperamos la sesión con el servidor SMTPSet objSession=Session("oSession")Set colMensajes=objSession.Inbox.Messages'recuperamos el identificador del mensajeidmensaje=Request.QueryString("idmensaje")'se recupera el mensaje correspondiente de la colecciónSet objMensaje=colMensajes.Item(idmensaje)%><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><%'se obtiene el objeto que representa al remitenteSet objAddressEntry=objMensaje.Sender%><b>De:</b> <%=objAddressEntry.Name%> (<%=objAddressEntry.Address%>)<br><b>Asunto:</b> <%=objMensaje.Subject%><br><form action="ListadoMensajes.asp" method="post"><textarea rows="10" cols="50"><%=objMensaje.Text%></textarea><br><input type="submit" name="Volver" value="Volver"><input type="hidden" name="idmensaje" value="<%=idmensaje%>"><input type="submit" name="Eliminar" value="Eliminar"></form><%'si existen adjuntos en el mensaje se muestran enlaces a los mismosIf objMensaje.Attachments.Count>0 then%>

<b>Adjuntos:</b><br><ul><%For Each objAdjunto in objMensaje.Attachments

'se almacena el adjunto en un directorio del servidor Web

objAdjunto.WriteToFile(Server.MapPath("/cursoasp30")&"\"&objAdjunto.Name)'se construye el enlace al adjunto%><li><a href="<%=objAdjunto.Name%>"><%=objAdjunto.Name%></a><br></li>

<%Next%></ul>

<%End if%></BODY></HTML>

Código fuente 116

Page 140: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

140

Como se puede ver también se crean enlaces para los adjuntos del mensaje si los tiene. Los ficheros adjuntos se graban en el servidor Web con el método WrietToFile() del objeto Attachment, para que los pueda recupera el destinatario del mensaje. La forma de grabar el adjunto en una misma carpeta y aprovechando el valor de su propiedad Name, no demasiado adecuado, ya que si existe un fichero adjunto con ese mismo nombre se sobreescribirá.

Veamos, en la Figura 33, el aspecto que ofrece esta nueva página.

Figura 33. Página de lectura del mensaje

La página LISTADOMENSAJES.ASP le pasa a LEERMENSAJE.ASP a través del QueryString un parámetro para identificar el mensaje que deseamos leer. Igualmente la página LEERMENSAJE.ASP le devuelve a la página LISTADOMENSAJES.ASP este mismo identificador de mensaje para que cuando sea demandando la página LISTADOMENSAJES.ASP pueda eliminar el mensaje deseado. Para que la página LISTADOMENSAJES.ASP pueda eliminar el mensaje solicitado, deberemos añadir el Código fuente 117 justo antes de empezar a recorrer la colección de mensajes presentes en la bandeja de entrada..

<%If Request.Form("Eliminar")<>"" Then'se obtiene el mensaje que se desea borrarResponse.Write "paso: "& Request.Form("idmensaje")

Page 141: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 6. CDONTS y ASP

141

Set objMensaje=objFolderInbox.Messages.Item(Request.Form("idmensaje"))'se borraobjMensaje.Delete

End if%>

Código fuente 117

Simplemente se obtiene el objeto Message correspondiente de la colección Messages y se le lanza el método Delete().

En el siguiente enlace se encuentra el código completo de este ejemplo.

Page 142: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 143: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

El modelo COM

Introducción a los componentes Los componentes de software son unidades de código ejecutable que proporcionan una funcionalidad específica para una aplicación. A la aplicación que utiliza código de un componente, creando objetos y llamando a sus propiedades y métodos, se denomina cliente o contenedora.

Las ventajas derivadas de la utilización de los componentes en el desarrollo de software pueden compararse a las de la producción industrial en cadena: en vez de ser un único fabricante el que se encargue, por ejemplo, de la construcción de todas y cada una de las piezas de un coche, existen varios fabricantes, cada uno de ellos especializado en una parte concreta (motor, amortiguadores, motores eléctricos, chapa, caja de cambios, ...), que tienen funcionalidades diferentes. Cada uno de estos fabricantes trabaja de forma independiente a los demás, pero siguiendo unos estándares industriales para que luego las piezas encajen entre sí para formar una única unidad funcional: el coche.

Del mismo modo, la utilización de los componentes en una aplicación informática permite que varias personas distintas, de la misma o distinta empresa, trabajando con distintos lenguajes de programación, puedan crear pequeños bloques de código con una funcionalidad específica. Cada uno de estos componentes deben ajustarse a unos estándares o protocolos, para que luego puedan encajar entre sí y formar una aplicación con funcionalidad completa.

Uno de estos protocolos para que los componentes puedan interaccionar entre sí es el modelo COM que propone Microsoft. El modelo DCOM permite que componentes que se ejecutan en máquinas distintas puedan comunicarse a través de la red.

Otro de estos protocolos es el modelo CORBA. Cada uno de estos modelos tiene sus ventajas y sus inconvenientes. El modelo CORBA está respaldado por una coalición de varios cientos de empresas,

Page 144: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

144

el OMG (Object Management Group), y lleva varios años de ventaja respecto al modelo COM/DCOM de Microsoft.

Los pasos para el diseño de componentes son los siguientes:

• Establecer qué servicios debe proporcionar el componente.

• Determinar qué objetos son necesarios para dividir la funcionalidad del componente de una manera lógica.

• Decidir cómo se ejecutarán mejor esos componentes en el mismo proceso o en un proceso aparte.

Conceptos • Objeto: Es la instancia de una clase.

• Clase: Plantilla que implementa los métodos y propiedades para un objeto. Un solo componente COM puede contener varias clases. En tiempo de ejecución, se creará un objeto creando una instancia de una clase.

• Interfaz: Grupos de funciones que exponen la funcionalidad del componente; a través de este interfaz, los clientes y los componentes COM se comunican. Las interfaces proporcionan acceso estandarizado a los métodos y propiedades (funcionalidad) disponibles en los componentes. Es más, son el contrato entre el autor del componente y los desarrolladores de clientes que aseguran un acceso fiable a la funcionalidad aportada.

• Componente: Colección de clases COM empaquetadas en una unidad ejecutable, como puede ser una DLL o un EXE. Los componentes son independientes del lenguaje; es decir, no se definen sobre la base del lenguaje con que se construyeron, sino por las interfaces que soportan. El lenguaje usado para implementar un componente y sus clientes es irrelevante.

Especificación COM Las principales características del modelo COM son:

• Compatibilidad binaria: El modelo COM es una especificación binaria. Esto significa que se pueden construir componentes COM con cualquier herramienta de desarrollo que soporte COM (Visual Basic, Visual C++, Visual J++, Delphi, etc), y esos mismos componentes pueden ser después utilizados desde una aplicación, o desde otro componente, escrito en cualquier lenguaje de programación que soporte COM.

• Compatibilidad con sistemas operativos distintos: Los componentes COM deben desarrollarse para una plataforma específica, como Windows NT o UNIX ya que no pueden ejecutarse en una plataforma que no sea para la que fueron escritos; sin embargo, sí que pueden comunicarse con otros objetos COM situados en otras plataformas.

• Localización transparente: Permite usar un componente desde un cliente sin importar si ese componente pertenece al mismo proceso, a otro proceso en la misma máquina o a otro proceso en una máquina distinta.

Page 145: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 7. El modelo COM

145

• Reutilización del código: Es la mayor ventaja de COM. Los componentes COM contienen clases que exponen grupos de métodos, conocidos como interfaces, a través de los cuales los clientes se comunican con objetos. Dado que estos interfaces están bien documentados, el código que implementan puede reutilizarse con facilidad.

El Modelo de Objetos Componentes (COM) es una especificación de cómo estos objetos interactúan con sus clientes. Como tal especificación, COM define una funcionalidad estándar, pero no define cómo debe implementarse, sino qué es lo que debe tener. Entre lo que especifica COM se incluye lo siguiente:

• Cómo se crean las instancias de los objetos COM.

• Cómo acceden los clientes a las características de estos objetos

• La responsabilidad de su auto-destrucción cuando ya no quedan instancias suyas.

Además de lo que es meramente la especificación, existen "bibliotecas COM", su runtime, que contienen:

• Una reducida API para facilitar la creación de aplicaciones COM, tanto clientes como servidoras. Esta API ofrece, por un lado, las funciones para trabajar con clientes y, por otro, las que permiten a los servidores proporcionar objetos COM.

• Servicios de localización, a través de los cuales se averigua en qué servidor se encuentra el objeto y la ubicación dentro de éste. Indirectamente esto incluye un soporte entre el identificador de objeto y el paquete en el que se encuentra su código, que normalmente se obtiene a través del Registro de Windows. De esta manera, los clientes quedan totalmente independientes de los posibles cambios de ubicación de los objetos COM, ya sean cambios de paquete o -incluso- cambios de máquina servidora.

• Servicios para la transparencia en las llamadas a procedimientos remotos, es decir, cuando un objeto está ejecutándose en un proceso aparte o en una máquina distinta desde la que se usa.

Ventajas del uso de componentes Veamos las ventajas del uso de componentes, en general, y en particular para las aplicaciones ASP:

• Se divide un problema en partes más pequeñas, más fáciles de entender y resolver, y luego se unen todas las partes.

• Reduce la complejidad, que queda oculta dentro del componente, “disfrazada” bajo un interfaz más amigable.

• Reparto del trabajo entre distintos equipos de programadores, que pueden trabajar simultánea-mente en paralelo, disminuyendo el plazo de desarrollo de la aplicación.

• Más fácil mantenimiento y mejora de cada parte individualmente.

• Los componentes son reutilizables. Si queremos reutilizar el código de una página ASP, hay que copiar las líneas de script, pero si hemos usado componentes, éstos pueden reutilizarse en la nueva página.

Page 146: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

146

• Pueden ser escritos es cualquier lenguaje, y luego utilizados en una aplicación en otro lenguaje. Un componente escrito en C++ puedo ser usado en una aplicación VB o, en nuestro caso, desde el script de una página ASP. Esto permite que el componente pueda ser desarrollado en el lenguaje en el que se encuentre más cómodo el programador.

• Se pueden comprar a terceras partes, empresas especializadas en el desarrollo de componentes. Existen muchas empresas de este tipo especializadas en el desarrollo de componentes para uso en aplicaciones ASP.

• Más rapidez de ejecución: los componentes están compilados, mientras que el script de una página ASP es interpretado. Además, hay cierta funcionalidad que no podemos conseguir con un lenguaje de script, que no deja de tener sus limitaciones.

• Protección del código: el script se puede ver y modificar; un componente compilado no. Es cierto que a partir del IIS 5.0 puede utilizarse la herramienta Windows Script Encoder para codificar el script de las páginas ASP, convirtiéndolas en caracteres ASCII ilegibles, pero esto no supone una solución segura ni definitiva. Sin embargo, el código de un componente compilado en una DLL es inaccesible.

• Los depuradores de VB y sobre todo VC++ son mejores que el script debugger de páginas ASP.

Los interfaces Un interfaz representa un contrato entre un servidor y un cliente. Un objeto siempre implementará la función para un interfaz determinado y de una manera estándar. El contrato posibilita el desarrollo de objetos en cualquier lenguaje, mientras éstos expongan sus interfaces acorde con el estándar COM. En virtud del contrato puede afirmarse que:

• El interfaz tiene un Identificador Único Global (IID).

• Las funciones tendrán siempre los mismos parámetros y conservarán sus tipos.

• Las funciones devolverán siempre el mismo tipo de valor.

• Las funciones se implementarán cada una siguiendo la semántica del interfaz.

• El interfaz tendrá siempre el mismo conjunto de funciones. No se pueden añadir ni borrar funciones.

Un interfaz no puede instanciarse en un objeto. Las clases que implementen el interfaz sí pueden ser instanciadas.

Encapsular funcionalidades en los objetos a los que se accederá a través de interfaces hacen de COM un sistema abierto y extensible; cualquiera puede proporcionar una implementación de un interfaz definida y desarrollar aplicaciones que usen esos interfaces. Un desarrollador que use luego estos componentes no necesitará entender las implementaciones internas de los interfaces; tan sólo necesitará entender las especificaciones del interfaz.

El diseño y utilización de interfaces es mucho más importante en grandes aplicaciones. En aplicaciones empresariales minimiza las interdependencias. Así, el cambiar un componente no requiere rediseñar todos los demás. Un sistema bien diseñado y construido con interfaces COM

Page 147: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 7. El modelo COM

147

permite a los usuarios de los componentes trabajar independientemente de los desarrolladores de componentes y, también, hacer pruebas rápidamente.

La mayoría de las herramientas de desarrollo que soportan COM permiten la creación de clases, objetos y componentes. Sin embargo, hay diferencias en cómo permiten a los programadores acceder a los interfaces en cada lenguaje.

Para el programador de Visual Basic, los interfaces permanecen ocultos. Cada vez que se crea una nueva clase, se crea automáticamente un interfaz por defecto. Este interfaz está compuesto por todos los métodos públicos de la clase. Visual Basic 6.0 permite que una clase implemente un interfaz COM previamente definido, por ejemplo, usando MIDL en una biblioteca de tipos.

En C++ los interfaces se implementan como clases abstractas. El programador de C++ trabaja directamente con clases e interfaces. La biblioteca ATL proporciona un mecanismo simple para generar el código necesario para usar e implementar interfaces.

Por definición, un interfaz COM no puede cambiar una vez haya sido utilizado. Se dice que el interfaz es inmutable.

Aunque ni los métodos ni la firma puedan cambiar, la implementación de estos componentes sí que puede variar. La interfaz contractual, entendida por el cliente y el componente, proporciona la base de unas actualizaciones de versiones seguras. Mientras las interfaces permanezcan inmutables, los componentes podrán intercambiarse.

Los componentes con enlace temprano no pueden cambiar sus interfaces; sin embargo, los que usan enlace tardío tienen la capacidad de añadir, borrar y cambiar métodos. Cuando se actualicen estos componentes, hay que asegurarse de que no se rompe el contrato de la interfaz.

Dado que las funcionalidades están agrupadas en interfaces del modelo de programación COM, se pueden añadir nuevas funcionalidades añadiendo nuevas interfaces y manteniendo las anteriores, aunque como veremos, desde una página ASP sólo podemos acceder a un interfaz.

Identificadores Únicos Globales (GUIDs) Cuando un cliente necesita de los servicios de un componente, realiza una petición de la clase e interfaz deseada al sistema operativo. COM utiliza Identificadores Globales Únicos (GUIDs) para identificar cada interfaz y clase. Un GUID es un número entero de 128 bits único en el tiempo y espacio. A estos números se les asigna también un texto legible sólo por conveniencia y con un ámbito más local (el PROGID). Este GUID asegura que no se solicitará ningún componente COM ni interfaz ni método accidentalmente, incluso en redes de miles de objetos componentes.

Además de las clases y los interfaces, COM utiliza GUIDs para identificar entidades que requieren valores únicos. Así, los GUIDs reciben nombres distintos según la entidad a la que se aplique:

• CLSID: para clases

• IID: para interfaces

• LIBID: para librerías de tipos

• CATID: para categorías (tipos enumerados)

Page 148: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

148

Los GUIDs pueden generarse utilizando las herramientas "guidgen" o "uuidgen", o realizando llamadas a la función del API Win32 CoCreateGuid. Guidgen.exe y uuidgen.exe se instalan con Visual Studio en el directorio de Visual Studio\Common\Tools. Estos generadores utilizan un complejo algoritmo definido por la Open Software Foundation DCE estándar. El GUID generado depende del instante en que se llamó a la función y del número de su tarjeta de red (o de otra característica única en ordenadores sin tarjeta de red). Utilizar un ordenador con tarjeta de red para generar el GUID, garantiza que el número obtenido será único.

Cuando se desarrollan componentes se trabaja con muchos CLSIDs. El teclear estos GUIDs directamente en el código es engorroso y suelen cometerse errores. Para simplificar esta operación, se utiliza un texto "legible" que sustituye a esos CLSIDs.

Los PROGID, o identificadores de programas, son cadenas de caracteres que identifican una clase y que están asociadas a un CLSID en el registro de Windows. Una vez establecida la relación entre el CLSID y el PROGID se puede utilizar éste para crear componentes. Algunos lenguajes como Visual Basic, crean automáticamente PROGID y GUID para cada clase. Visual Basic usa el esquema nombreproyecto.nombredeclase como el PROGID.

El gran inconveniente que tiene el uso de los PROGID es que puede generar conflictos con otros nombres ya existentes en la red, ya que no está garantizada su unicidad, como sucede con los CLSIDs.

Enlace temprano y tardío El enlace tardío (late binding) ocurre en cualquier lenguaje en el que se use un tipo de datos neutral para llamar a un objeto. En Visual Basic, esto se hace declarando una variable del tipo Object. En Visual C++ se hace utilizando el interfaz IDispatch para invocar los métodos del objeto. El compilador o la herramienta de desarrollo no puede comprobar los métodos, propiedades, tipo y sintaxis de ninguna llamada a los métodos del objeto en tiempo de compilación, ya que no se ha definido el tipo de objeto concreto.

El Código fuente 118 es un ejemplo de enlace tardío a un objeto Connection de ADO en Visual Basic.

Dim objCnx As ObjectSet objCnx = CreateObject(“ADODB.Connection”)objCnx.metodo

Código fuente 118

Una ventaja del enlace tardío es que no es necesario identificar el objeto que se quiere crear hasta el tiempo de ejecución. Por otro lado, una desventaja es que el compilador no puede comprobar la sintaxis. Como resultado de ello, errores como el pasar un número incorrecto de parámetros o con tipos incorrectos no se detectarán hasta el tiempo de ejecución. Aparte de esto, el enlace tardío es menos eficiente que el enlace temprano, ya que requiere un mayor nivel de comunicación entre el cliente y el componente para cada operación.

Algunos entornos, tales como los motores de scripts, sólo soportan el enlace tardío para llamar a los componentes. Este es el caso de las páginas ASP.

Por el contrario, el enlace temprano (early binding) ocurre cuando se conoce el tipo del objeto en tiempo de compilación. Se establece un enlace temprano cuando se declaran variables de un tipo específico de datos. En ese caso el compilador puede contrastar todas las referencias del objeto con las

Page 149: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 7. El modelo COM

149

que define el entorno del objeto (normalmente incluidas en bibliotecas de tipos). Las bibliotecas de tipos pueden ser ficheros *.TLB independientes o estar incorporadas en los componentes.

En Visual Basic, los enlaces tempranos requieren que se haga una referencia al componente y a la clase específica usada cuando se declaran variables de ese tipo de objeto. Visual C++ utiliza la cláusula #import o cabeceras de interfaces para obtener la información de tipos de los componentes.

El Código fuente 119 es un ejemplo de enlace temprano a un objeto Connection de ADO en Visual Basic.

Dim objCnx As ADODB.ConnectionSet objCnx = New ADODB.ConnectionobjCnx.metodo

Código fuente 119

Dado que el compilador tiene acceso a la biblioteca de tipos del objeto, puede comprobar la sintaxis de todas las llamadas que usan esa variable de objeto e informarle de cualquier error sintáctico en tiempo de diseño.

Los métodos de los componentes que se llamen utilizando enlace temprano son los más eficientes en términos de rendimiento. Dado que se dispone de la información en tiempo de compilación, el compilador puede generar un código más óptimo para las llamadas.

Los entornos de programación como Visual Basic y Visual C++ soportan la creación de componentes que serán llamados con enlaces tempranos o tardíos. No así los motores de script que utilicemos desde una página ASP, que sólo permiten el enlace tardío.

Espacio de proceso de un componente Un componente que se ejecuta en el mismo proceso que la aplicación comparte el mismo espacio de memoria que la aplicación contenedora; ésta puede ser una aplicación propiamente dicha u otro componente que se ejecuta en el mismo proceso. Los componentes que se ejecutan en el mismo proceso se denominan COM DLLs.

Los componentes que se ejecutan en otro proceso aparte tienen su propio espacio de memoria separado del de la aplicación contenedora. Estos componentes se denominan COM EXEs. Este curso se centra en la construcción de componentes COM DLLs, que son los que soportan los Servicios de Componentes (antes denominados MTS).

Visual Basic 6.0 y Delphi (entre otros) utilizan el término "DLL ActiveX" para referirse a los COM DLLs y "EXE ActiveX" para los COM EXEs. Esta denominación es equivalente a la de COM DLL y COM EXE, respectivamente.

Los controles ActiveX son un tipo especial de COM DLL que proporciona un interfaz visual al usuario. Obviamente, este tipo de componentes no son de utilidad en el script de servidor de una aplicación ASP, aunque sí podrían serlo como controles ActiveX que se ejecutaran el la máquina cliente.

Cada tipo de componente tiene sus ventajas e inconvenientes:

Page 150: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

150

• Un componente DLL proporciona un acceso al objeto más rápido, pero es menos tolerante al fallo: si el componente DLL falla, lo hará el proceso servidor completo.

• En un componente EXE, los fallos no afectan a todos los procesos del sistema, sólo al proceso en el que se encuentra el componente EXE. Es más lento porque las llamadas del método han de ser reconfiguradas entre los procesos.

El interfaz IUnknown Por convención, el nombre de un interfaz siempre lleva el prefijo "I".

Para poder utilizar un objeto, un cliente necesita conocer qué interfaces soporta ese objeto. Según la especificación COM, un objeto debe poder ser consultado por un cliente para averiguar esta información. Esto se consigue gracias al interfaz denominado IUnknown, que deben soportar todos los objetos. Es más, cualquier otro interfaz en el proyecto debe incluir la funcionalidad proporcionada por el interfaz IUnknown. Aunque Visual Basic maneja muchas de estas cuestiones sin que nos demos cuenta, de forma transparente para nosotros.

Tradicionalmente, los clientes destruyen los objetos cuando ya no los necesitan. Debido a que múltiples clientes de diferentes procesos, e incluso de diferentes ordenadores, pueden conectarse y utilizar un objeto, cuando un cliente destruye un objeto podría dejar a otros clientes "colgados". Por eso es conveniente mantener un contador, de forma que si el contador es mayor que "0", significa que el objeto sigue en activo; y si indica un número igual a "0", el objeto se autodestruye.

Para llevar este recuento, el interfaz IUnknown tiene dos funciones:

• AddRef: Incrementa en uno el contador del objeto cuando éste asigna un puntero de interfaz Se llama a AddRef cuando utiliza una sentencia Set para inicializar una variable del objeto.

• Release: Disminuye en uno el contador cuando una variable que señala al objeto se sale del ámbito. Se llama esta función cuando se asigna Nothing a una variable del objeto, o cuando la variable sobrepase el ámbito de su definición.

Además, el interfaz IUnknown presenta la función QueryInterface, que permite a los clientes preguntar por otros interfaces proporcionados por el objeto. Si el objeto soporta ese interfaz, QueryInterface devolverá un puntero a ese interfaz. Luego podrá utilizar los métodos que contiene ese interfaz para comunicarse con el objeto.

Windows DNA Se agrupa bajo el nombre de Windows DNA (Windows Distributed InterNet Application Architecture) a un conjunto de tecnologías que permiten desarrollar aplicaciones distribuidas para internet/intranet usando el modelo de n capas.

Los servicios DNA ofrecen interfaces COM para que otras aplicaciones puedan utilizarlos. Puedo usar cualquier herramienta de desarrollo que soporte COM para escribir componentes para el DNA.

Windows DNA se compone de los siguientes servicios (todos ellos basados en COM):

• Componentes COM

Page 151: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 7. El modelo COM

151

• HTML dinámico (DHTML)

• Servidor IIS

• Páginas ASP

• Componentes de acceso a datos (MDAC)

• Servicios de componentes (antes MTS)

• Colas de mensajes (MSMQ)

• Active Directory (ADSI)

• Servicios de seguridad de Windows

Page 152: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 153: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Componentes en Visual Basic

Introducción En este tema vamos a empezar a construir nuestros propios componentes. El entorno de trabajo utilizado en este tema y en los posteriores será un sistema operativo Windows 2000 Server, con el servidor web IIS 5, con Visual Basic 6 y Visual InterDev 6, y el Internet Explorer 5.

Habrá ocasiones en que existan diferencias en la funcionalidad de los componentes si éstos se ejecutan en Windows 2000 o en Windows NT. En esos casos se hará mención de estas diferencias.

Componentes en Visual Basic y Visual C++ Después de haber visto en temas anteriores que desde páginas ASP podemos utilizar un gran número de componentes ya escritos (componentes ActiveX de servidor, componentes ADO, componentes CDONTS, …), vamos a avanzar un paso más. Escribiremos estos componentes nosotros mismos, y los utilizaremos después desde las páginas ASP de nuestra aplicación web.

Al ser COM una especificación binaria, podemos escribir los componentes en el lenguaje de programación que nos resulte más cómodo, y que más se adapte a los resultados que queremos obtener. Por supuesto que el lenguaje de programación elegido deberá ser capaz de generar componentes que cumplan con la especificación COM. Entre estos lenguajes están Visual Basic, Visual C++, Delphi, etc.

El lenguaje que vamos a emplear para los ejemplos va a ser el Visual Basic, y esto será así por varios motivos.

Page 154: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

154

El primero, y más importante, es que el Visual Basic es un lenguaje conocido, al menos a un nivel básico, por la mayoría de los programadores, y no habrá necesidad de dedicar tiempo y esfuerzo al aprendizaje de un lenguaje de la complejidad de Visual C++.

Además el Visual Basic, a pesar de su facilidad de uso, nos permite hacer prácticamente lo mismo que podríamos hacer con Visual C++.

Es cierto que no podremos alcanzar el nivel de control que puede lograrse programando en Visual C++, pero esto es así porque el Visual Basic simplifica muchas de las operaciones que en Visual C++ tendríamos que codificar nosotros.

Por ejemplo, todos los componentes COM implementan el interfaz IUnknown, pero esto a mí como programador me queda oculto por el Visual Basic. También el Visual Basic crea automáticamente el interfaz por defecto, agrupando en él todos los métodos públicos del componente. Será a este interfaz por defecto al único al que tengamos acceso desde el script de una página ASP.

Por supuesto que programar los componentes en Visual C++ tiene una serie de ventajas, aparte de la desventaja principal de la mayor dificultad del lenguaje. Entre estas ventajas están:

• El lenguaje Visual C++ tiene mayor potencia y flexibilidad que el Visual Basic, y puedo lograr un mayor control sobre la funcionalidad del componente.

• El rendimiento conseguido por un componente escrito en Visual C++ es mayor que el de uno escrito en Visual Basic.

• El depurador de Visual C++ es más completo que el de Visual Basic.

• Los componentes escritos en Visual C++ pueden beneficiarse de algunos servicios COM+ a los que no tienen acceso (por el momento) los componentes escritos en Visual Basic. Entre estos servicios están el pooling de objetos. Este concepto es parecido al del pooling de conexiones de una base de datos: cuando una aplicación cliente ha acabado de utilizar una conexión con la base de datos, en vez de ser destruida, esta conexión se guarda en un pool (como si dijéramos un almacén) de donde puede ser utilizada luego por otra aplicación cliente que la necesite. De igual manera, en el pooling de objetos, cuando un cliente ha terminado de utilizar un objeto, éste no se destruye sino que se guarda en el pool, de donde puede ser recuperado y reutilizado por otro cliente

Un primer ejemplo de componente Vamos a proceder a escribir nuestro primer componente. Este componente va a ser muy simple, pero de todas formas nos tomaremos un tiempo en pensar detenidamente cómo vamos a diseñarlo.

La funcionalidad de este componente será la de calcular el resultado de incrementar una cantidad en un 7 por ciento de su valor. Como se ve, no parece necesario crear un componente para esta operación tan sencilla, pero nos vendrá muy bien como primer ejemplo.

Fases en el diseño del componente Lo primero en el diseño de un componente sería definir claramente qué funcionalidad espero que tenga. Recordemos que un componente puede compararse con una caja negra que tiene una funcionalidad, a la que yo puedo acceder a través de un interfaz, sin preocuparme en absoluto de cómo

Page 155: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 8. Componentes en Visual Basic

155

se lleva a cabo internamente esa funcionalidad, ni siquiera en qué lenguaje de programación está escrito el componente.

La funcionalidad del componente será la de calcular la nueva cantidad, resultado de incrementar en un porcentaje del 7 por ciento.

El lenguaje de programación ya hemos dicho que va a ser el Visual Basic, que nos permite con relativa facilidad obtener unos resultados satisfactorios.

Para acceder a la funcionalidad del componente, diseñaremos un interfaz formado por un único método, que recibe como parámetro la cantidad sobre la que queremos efectuar el cálculo.

Más adelante construiremos componentes mucho más complicados que requieran un análisis más completo, pero para éste no necesitamos más que ponernos ya manos a la obra.

Creación del proyecto ActiveX DLL Arrancamos Visual Basic 6.0, y en la ventana de Nuevo Proyecto, elegimos la opción ActiveX DLL, pulsando a continuación el botón Abrir. Visual Basic pone por defecto el nombre de Proyecto1 para el proyecto y el nombre de Class1 para el módulo de clase. Vamos a cambiarlos por otros más descriptivos. Los nombres que elijamos serán los que luego formen el ProgId del componente, una vez compilado y registrado en el equipo.

Figura 34

Cada módulo de clase de Visual Basic define un tipo de objeto. Es la plantilla que define los métodos y propiedades para un objeto. Los objetos se crean, en tiempo de ejecución, al crear una instancia de una clase. Un componente puede contener varios módulos de clase, y servir por tanto de plantilla para la creación de varios tipos de objeto. Es lo que se llama un COM Server. En este caso, nuestro componente sólo contendrá un módulo de clase.

Page 156: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

156

Para cambiar el nombre del proyecto, seleccionarlo haciendo click sobre él en la ventana del Explorador de proyectos, y luego modificando su nombre en la ventana de Propiedades (cambiarlo a CompPorcentaje). Repetir la operación seleccionando el módulo de clase en la ventana del Explorador de proyectos y luego modificando el nombre en la ventana de Propiedades (cambiarlo a Porcentaje).

Diseño del interfaz Para diseñar el interfaz que presentará el componente, puedo hacerlo codificando directamente los métodos (en este caso sólo uno) en la ventana de edición de código, pero es más cómodo hacerlo usando el Generador de clases.

Esta utilidad aparece en el menú Complementos. De no ser así, pulsar dentro del menú Complementos la opción Administrador de complementos. En la ventana que aparece, seleccionar la utilidad Generador de clases de VB 6, y activar las casillas de verificación Cargado/Descargado y Cargar al iniciar (si queremos que siempre que iniciemos el Visual Basic esté disponible esta utilidad en el menú de Complementos).

Ahora la utilidad está disponible en el menú Complementos, y no hemos de hacer más que seleccionarla para que se inicie. Se muestra un mensaje de advertencia, debido a que el módulo de clase no fue creado desde el Generador, sino al crear el nuevo proyecto; responder que Sí.

Una vez abierta, seleccionar en el panel izquierdo el módulo de clase (en este caso lo hemos llamado Porcentaje), y pulsando sobre él con el botón derecho seleccionar Nuevo método.

Figura 35

En la ventana del Generador de métodos que aparece, similar a la de la Figura 36, asignarle un nombre al método. Le llamaremos “calcular”. En esta misma ventana, pulsar el botón que aparece etiquetado con un signo “+, para definir el argumento que va a recibir este método.

Page 157: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 8. Componentes en Visual Basic

157

Figura 36

En la nueva ventana Agregar argumento que aparece, similar a la de la Figura 37, darle un nombre al argumento (por ejemplo “cantidad”), activar la casilla de verificación de ByVal, y seleccionar Variant de la lista desplegable Tipo de dato. Más adelante veremos los problemas que se nos pueden plantear al utilizar tipos de datos distintos de Variant dentro de un componente que luego usemos desde una página ASP; recordemos que el VBScript, como JavaScript, es un lenguaje de script débilmente tipado, donde sólo existe el tipo de dato Variant.

Figura 37

Al activar la casilla de verificación de ByVal, estamos indicando que el parámetro se pasará por valor, es decir, el método recibirá internamente una copia del valor que se le pase, y trabajará con esa copia, y no con el valor original. La otra forma de pasar el valor sería ByRef, por referencia, que es la que se

Page 158: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

158

usa si usamos explícitamente la palabra ByRef o si no indicamos absolutamente nada, ya que es el valor por defecto.

Después de pulsar Aceptar, y ya de vuelta en la ventana del Generador de métodos, seleccionaremos Variant de la lista desplegable de Tipo de datos de retorno (es decir, estamos definiendo un método que será una función de Visual Basic, en vez de un procedimiento). El resultado final será el de la Figura 38. Pulsando Aceptar volvemos a la ventana del Generador de clases, donde ya podemos ver el método que acabamos de declarar.

Figura 38

Es recomendable, antes de salir de la utilidad Generador de clases, seleccionar la opción Actualizar proyecto del menú Archivo, para asegurarnos de que los cambios que acabamos de introducir en el interfaz tienen efecto, y no los perdemos al salir. Incluso antes de cerrar la utilidad podemos ver, en la ventana de edición de código que queda debajo de la del Generador de clases, que se genera el Código fuente 120, necesario para implementar el método recién creado.

Public Function calcular(ByVal cantidad As Variant) As VariantEnd Function

Código fuente 120

Cerremos ya la utilidad sin miedo. Ya en la ventana de edición de código, escribamos las líneas necesarias para que el método tenga la funcionalidad que queremos. Esto se reduce a la línea que aparece en el Código fuente 121.

Page 159: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 8. Componentes en Visual Basic

159

Public Function calcular(ByVal cantidad As Variant) As Variantcalcular = cantidad * 1.07

End Function

Código fuente 121

Guardemos el módulo de clase (PORCENTAJE.CLS) y el proyecto (COMPPORCENTAJE.VBP) en la carpeta que queramos, y ya estamos en disposición de generar la DLL.

Generación de la DLL y registro del componente Para generar la DLL, no tenemos más que seleccionar la opción “Generar CompPorcentaje.dll” dentro del menú Archivo. Esto creará el fichero DLL en la ubicación que hayamos elegido.

Pero al mismo tiempo que se ha generado la dll, Visual Basic se ha encargado de registrar el componente en nuestro equipo. Comprobémoslo.

Si en el menú Inicio seleccionamos Ejecutar y tecleamos “regedit”, se inicia el editor del registro de Windows. Recordar siempre que no debemos modificar nada del registro a no ser que estemos completamente seguros de lo que estamos haciendo. En este caso nos limitaremos a comprobar que el componente está registrado, pero no modificaremos absolutamente nada.

En el registro es posible buscar por el ProgId del componente y por el CLSID.

Si expandimos, dentro del editor del registro, la carpeta etiquetada como HKEY_CLASSES_ROOT, podremos encontrar una carpeta denominada “CompPorcentaje.Porcentaje”, como se muestra en laFigura 39, que contiene la información del registro del componente que acabamos de generar. Como podemos ver, el ProgId que genera el Visual Basic para el componente está formado por el nombre del proyecto y el nombre del módulo de clase, separados por un punto. Este ProgId será el que utilicemos al instanciar el componente desde nuestra página ASP. Si expandimos esta carpeta, podemos seleccionar con un click la subcarpeta Clsid que aparece, y en el panel de la derecha aparecerá el GUID asignado al componente.

Figura 39

Si ahora seleccionamos la opción Buscar del menú Edición, e introducimos como valor de búsqueda el valor del CLSID, encontraremos algo similar a laFigura 40.

Page 160: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

160

Figura 40

Si quisiéramos utilizar nosotros este componente en otro equipo, deberíamos copiar el fichero COMPPORCENTAJE.DLL a la ubicación del equipo destino que elijamos (normalmente se copian en la carpeta C:\WINNT\SYSTEM32, pero puede ser cualquier carpeta). A continuación abriremos una ventana MSDOS y nos moveremos hasta esa carpeta, para escribir lo que indica el Código fuente 122.

Regsvr32 CompPorcentaje.dll

Código fuente 122

Esto registrará el componente en el equipo.

Vamos a comprobar ahora que podemos usar este componente desde una página ASP. Iniciamos el InterDev y creamos una página con el Código fuente 123.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Set objPorcentaje = Server.CreateObject("CompPorcentaje.Porcentaje")Response.Write "El resultado es: " & objPorcentaje.calcular(1000)Set objPorcentaje = Nothing%>

</BODY></HTML>

Código fuente 123

Como el componente está registrado en la misma máquina en la que estamos usando el InterDev, éste es capaz de acceder al registro de Windows (concretamente a la type library) para proporcionarnos el “IntelliSense”: al escribir el nombre de la instancia del componente seguida del punto, nos aparece la lista de los métodos disponibles (en este caso sólo el método “calcular”).

Page 161: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 8. Componentes en Visual Basic

161

Al solicitar esta página desde el navegador, obtendremos el resultado correcto de 1070.

Rediseño del componente Supongamos que decidimos rediseñar el componente, de tal forma que el parámetro del método calcular no se pase por valor, sino por referencia, es decir, que el método trabaje con el mismo valor original que se le pasa por parámetro, y no con una copia de uso interno del método.

Este cambio supone rediseñar el interfaz, porque vamos a modificar el método calcular, que ahora no recibirá el parámetro por valor, sino por referencia. No podemos rediseñar este método desde la utilidad Generadora de clases. Ni siquiera eliminarlo y volverlo a crear. Tenemos que hacerlo manualmente desde la ventana de edición de código, borrando el cuerpo del método y volviéndolo a definir con la utilidad Generadora de clases. Ahora debemos dejar desactivada la casilla de verificación de ByVal.

Aprovecharemos también para hacer que el método devuelva un booleano, en este caso True, para indicar que ha finalizado con éxito.

Esto tendrá como resultado el Código fuente 124.

Public Function calcular(cantidad As Variant) As BooleanEnd Function

Código fuente 124

Vemos que ahora, dentro de los paréntesis, el nombre del parámetro no está precedido de la palabra ByVal. Con esto se sobreentiende ByRef, que es el valor por defecto para Visual Basic.

Podríamos haber conseguido lo mismo modificando nosotros manualmente todo el código, en vez de usar la utilidad Generadora de clases. Añadamos ahora el código necesario a la función. Esta vez hacemos el cálculo del porcentaje y se lo asignamos al mismo parámetro, cantidad. Devolvemos como valor de retorno de la función el valor True. Todo esto tal cual aparece en el Código fuente 125.

Public Function calcular(cantidad As Variant) As Booleancantidad = cantidad * 1.07calcular = True

End Function

Código fuente 125

El problema se nos presenta ahora en el momento de recompilar, puesto que la dll está actualmente en uso por dos clientes:

• El Visual InterDev la está usando para proporcionarnos el IntelliSense. Esto tiene fácil arreglo: cerremos la ventana de edición de la página ASP en que hemos utilizado el componente

• La aplicación web está usando también el componente, puesto que al pedir la página desde el navegador se ha ejecutado la página y se ha cargado la dll en memoria. Si hemos tenido la

Page 162: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

162

precaución de configurar, desde la consola de administración de los servicios IIS, las propiedades de nuestra aplicación web, en la pestaña Directorio, como se ve en la Figura 41, de tal forma que la Protección de la aplicación esté en el nivel Medio (agrupado) o Alto (aislado), podremos, desde esta misma ventana de configuración del IIS, pulsar el botón Descargar, que descarga de memoria esta aplicación web (y todas las que estuvieran agrupadas con ella).

Figura 41

• Si con lo anterior no consiguiéramos liberar la dll, deberemos ir a Inicio | Programas |

Herramientas administrativas | Servicios. Dentro de la lista de servicios que aparece, buscaremos el denominado “Servicio de admin. IIS”, como se ve en la Figura 42. Pulsaremos sobre él con el botón derecho del ratón y seleccionaremos la opción Detener. Esto detiene otros servicios aparte del de publicación web, como la publicación FTP y el correo SMTP. Después de detener el servicio, debemos pulsar otra vez con el botón derecho del ratón y seleccionar la opción Iniciar, para reiniciarlo. Luego tenemos que ir a la consola administrativa del IIS, en Inicio | Programas | Herramientas administrativas | Administrador de servicios Internet, y reiniciar manualmente el Sitio web predeterminado, que estará detenido como consecuencia de haber detenido el servicio de publicación web. Esta operación se ve en la Figura 43. Este proceso resulta pesado pero debe bastar para descargar definitivamente la dll.

Page 163: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 8. Componentes en Visual Basic

163

Figura 42

Figura 43

• La solución definitiva, si todo lo anterior no es suficiente, es obvia: reiniciar el equipo. Esto

no debe ser necesario en Windows 2000, mientras que en Windows NT es más frecuente tener que recurrir a esta solución extrema.

Para poder utilizar el nuevo componente, tendremos que modificar la página ASP, que quedará como en el Código fuente 126.

<%@ Language=VBScript %>

Page 164: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

164

<HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><%Set objPorcentaje = CreateObject("CompPorcentaje.Porcentaje")cantidad = 1000retorno = objPorcentaje.calcular(cantidad)Response.Write cantidadSet objPorcentaje = Nothing%></BODY></HTML>

Código fuente 126

Ahora creamos una variable de página llamada cantidad, a la que asignamos el valor 1000. Esta variable la pasamos como parámetro, y el método del componente trabaja directamente con ella, con lo que al escribir después su valor obtenemos el valor correcto de 1070.

En cualquier caso, suele ser más aconsejable pasar los parámetros a un método por valor (ByVal) mejor que por referencia (ByRef). De esta forma conseguimos más encapsulación del código del componente.

Reutilización del componente El componente que acabamos de diseñar es un componente universal. Quiere esto decir que podemos usarlo desde cualquier aplicación que permita el acceso a componentes COM. Esta es una de las principales ventajas de la componentización: la posibilidad de reutilizar el código. Antes hemos visto cómo podíamos utilizar el componente desde una página ASP. Vamos ahora a hacer un proyecto Visual Basic que también haga uso de él. Para eso seleccionaremos la opción Agregar proyecto del menú archivo, y seleccionaremos la opción Exe estándar, como en laFigura 44.

Figura 44

Page 165: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 8. Componentes en Visual Basic

165

Nombraremos al nuevo proyecto como PruebaPorcentaje. Añadimos al formulario un campo de texto y un botón, y les asignamos, mediante la ventana de Propiedades, los nombres que nos parezcan oportunos. El formulario quedará algo parecido a la Figura 45.

Figura 45

A este nuevo proyecto debemos añadirle la referencia al componente anterior CompPorcentaje, desde el menú Proyecto | Referencias, y seleccionado la casilla de verificación correspondiente al componente CompPorcentaje, como se ve en la Figura 46. De este modo Visual Basic nos facilitará el IntelliSense, y además podremos utilizar el early binding.

Figura 46

Haciendo doble click sobre el botón, podemos escribir el código necesario para el evento Click del mismo, que será el del Código fuente 127.

Page 166: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

166

Private Sub Command1_Click()Dim objPorcentaje As CompPorcentaje.PorcentajeDim retorno As BooleanDim cantidad As Variant

cantidad = 1000Set objPorcentaje = New CompPorcentaje.Porcentajeretorno = objPorcentaje.calcular(cantidad)Text1.Text = cantidad

End Sub

Código fuente 127

Las líneas Dim objPorcentaje As CompPorcentaje.Porcentaje y SetobjPorcentaje = New CompPorcentaje.Porcentaje sólo son posibles gracias a que hemos incluido en el proyecto EXE la referencia al componente CompPorcentaje. Esto permite declarar la variable objPorcentaje como una variable de referencia a un objeto que se creará como una instancia a partir del módulo de clase Porcentaje incluido en el proyecto ActiveX CompPorcentaje. Además permite usar el operador New para hacer un enlace temprano, en tiempo de compilación, con el código de ese componente.

Si no hubiéramos incluido la referencia a CompPorcentaje, no podríamos hacer nada de lo anterior, y tendríamos que dejar el código como se ve en el Código fuente 128. El uso del método CreateObject significa que no estamos haciendo enlace temprano, sino enlace tardío.

Private Sub Command1_Click()Dim objPorcentaje As ObjectDim retorno As BooleanDim cantidad As Variant

cantidad = 1000Set objPorcentaje = CreateObject("CompPorcentaje.Porcentaje")retorno = objPorcentaje.calcular(cantidad)Text1.Text = cantidad

End Sub

Código fuente 128

En el Explorador de proyectos, pulsando con el botón derecho sobre el proyecto PruebaPorcentaje, debemos seleccionar la opción “Establecer como inicial”, de tal forma que cuando pulsemos el icono de ejecución de Visual Basic, sea éste el proyecto de arranque, se muestre el formulario, y podamos pulsar el botón.

Esta pulsación desencadenará la instanciación del componente CompPorcentaje, y la invocación al método calcular, pasándole como parámetro, por referencia, la variable cantidad. A continuación se le asigna su valor, ya actualizado por el método, al campo de texto. Por supuesto que este proyecto EXE estándar podremos depurarlo desde el entorno de Visual Basic, estableciendo puntos de interrupción con la tecla de función F9 y ejecutando paso a paso con F8.

Page 167: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 8. Componentes en Visual Basic

167

Tipos de componentes Hemos visto en los apartados anteriores que este primer componente que hemos desarrollado en Visual Basic era utilizable tanto desde una página ASP como desde un proyecto estándar de Visual Basic. Por supuesto que también podríamos utilizarlo desde otra aplicación escrita en cualquier lenguaje que soporte COM, como podría ser Visual C++. Es un componente que podríamos llamar de uso universal.

Podemos, sin embargo, diseñar componentes que sean más restrictivos en cuanto a su aplicabilidad. Supongamos que desarrollamos un componente como el anterior, pero que permita la introducción del número sobre el que vamos a calcular el porcentaje desde un campo de texto, es decir, que tenga un interfaz visual.

Si creamos una página HTML desde cualquier editor de HTML, por ejemplo FrontPage, y seleccionamos la opción Avanzadas del menú Insertar, y a continuación Control ActiveX, podemos marcar de la lista que aparece el control “Control Calendar 9.0”.

El código html que generará el FrontPage por nosotros quedaría como el Código fuente 129.

<html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252"><meta name="GENERATOR" content="Microsoft FrontPage 4.0"><meta name="ProgId" content="FrontPage.Editor.Document"><title>Pagina nueva 1</title></head><body><p><object classid="clsid:8E27C92B-1264-101C-8A2F-040224009C02" id="Calendar1"width="288" height="192">

<param name="_Version" value="524288"><param name="_ExtentX" value="7620"><param name="_ExtentY" value="5080"><param name="_StockProps" value="1"><param name="BackColor" value="-2147483633"><param name="Year" value="2001"><param name="Month" value="1"><param name="Day" value="11"><param name="DayLength" value="1"><param name="MonthLength" value="2"><param name="DayFontColor" value="0"><param name="FirstDay" value="2"><param name="GridCellEffect" value="1"><param name="GridFontColor" value="10485760"><param name="GridLinesColor" value="-2147483632"><param name="ShowDateSelectors" value="-1"><param name="ShowDays" value="-1"><param name="ShowHorizontalGrid" value="-1"><param name="ShowTitle" value="-1"><param name="ShowVerticalGrid" value="-1"><param name="TitleFontColor" value="10485760"><param name="ValueIsNull" value="0">

</object></p></body></html>

Código fuente 129

Page 168: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

168

Y en el navegador veremos algo como la Figura 47.

Figura 47

¿Podríamos utilizar este componente desde una página ASP? La respuesta en no, lógicamente, puesto que las páginas ASP se ejecutan de forma desatendida en el servidor, y no podemos generar ningún interfaz visual (recordemos que dentro de una página ASP no podemos ni siquiera usar funciones estándar de Visual Basic como MsgBox).

Con un código en un página ASP como el del Código fuente 130, no lograremos nada; no llegaré a ver el control, porque en este contexto no tienen sentido los componentes con interfaz visual.

<%Set objCom = Server.CreateObject("MSCAL.Calendar")objCom.Day = 11%>

Código fuente 130

Este sería un componente que sería utilizable en una aplicación Visual Basic, o Visual C++, que tengan un interfaz visual, pero no dentro de una página ASP.

Vayamos al caso opuesto. Si yo diseño un componente que acceda al modelo de objetos de ASP para escribir directamente código HTML a través del objeto Response, o para leer el valor de una variable de aplicación (más adelante veremos que todo esto es posible), estaré haciendo uso de un modelo de objetos que no tendría ningún sentido si utilizase este componente desde una aplicación Visual Basic o Visual C++. Este componente no sería utilizable en estas aplicaciones, pero sí en páginas ASP.

Page 169: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 8. Componentes en Visual Basic

169

Un componente ActiveX Server, como el adRotator, genera una cadena HTML, que tendría sentido sólo si se estuviera ejecutando dentro de un servidor web, para enviar este resultado HTML a un navegador.

Estos tres ejemplos de componentes mencionados son dependientes del entorno en el que se ejecutan, y no podrían considerarse de aplicabilidad universal.

Podríamos diseñar componentes que fueran capaces de reconocer por sí mismos el tipo de entorno en el que se ejecutan, es decir, si están instanciados desde una página ASP o desde una aplicación Visual Basic. Serían componentes que se adaptarían en cada caso al entorno, usando el modelo de objetos de ASP sólo si reconocieran que lo tienen disponible. Esta capacidad de adaptación los convertiría en reutilizables dentro de una aplicación Visual Basic.

Hay componentes que hacen uso de otros componentes. Un caso muy frecuente es el de los componentes que acceden a una base de datos, haciendo uso de los componentes de ADO: Connection, Command y Recordset.

Otro tipo de componente, que veremos con detalle más adelante, es aquél que está involucrado en una transacción sobre una base de datos. Estos componentes transaccionales tienen unas características especiales.

Page 170: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 171: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Modelos de aplicaciones cliente/servidor

Introducción Antes de continuar con el diseño de componentes para ASP, vamos a ver de forma resumida cómo ha ido evolucionando el concepto de aplicación cliente/servidor, desde la idea tradicional hasta el modelo cliente/servidor que podemos conseguir en una aplicación web y, en el caso que a nosotros nos interesa, en una aplicación ASP.

Arquitectura cliente/servidor en dos capas En las aplicaciones cliente/servidor tradicionales, como podría ser una aplicación escrita en Visual Basic, sólo hablamos de dos capas:

• Una sería la capa del servidor de base de datos, lo que se llama el “backend”. Es la capa encargada de servir los datos, garantizando su consistencia por medio de procedimientos almacenados y triggers. Esto es lo que se llama la lógica de datos.

• Otra sería la capa del cliente con el interfaz de usuario (el GUI), lo que se llama el “frontend”. Es la capa encargada de gestionar el interfaz de la aplicación con el usuario, para mostrarle información, y también para recibirla a través de formularios. Esto es lo que se llama la lógica de presentación. También es la capa encargada de asegurar que se cumplen las reglas conforme a la funcionalidad que queremos para nuestra aplicación. Esto es lo que se llama la lógica de negocio.

Page 172: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

172

Conviene aclarar que habría que distinguir entre capas lógicas y capas físicas. Cuando hablamos de capas normalmente nos referimos a capas lógicas. Por capas lógicas entendemos software, y por capas físicas hardware. Lo usual es que la capa de datos esté en una capa física separada, es decir, en un equipo separado donde sólo se está ejecutando el software del gestor de base de datos, por ejemplo SQL Server u Oracle, y que la capa con la lógica de presentación y la de datos esté en otra capa física separada, es decir, el equipo del usuario, donde se ejecute la aplicación cliente escrita en un lenguaje como Visual Basic.

Pero es también muy normal que durante el tiempo de desarrollo estas dos capas lógicas estén en la misma capa física, es decir, que en nuestro equipo de desarrollo esté ejecutándose el software del gestor de base de datos y el software de la aplicación cliente.

En estas aplicaciones cliente/servidor tradicionales hay una conexión permanente entre las dos capas, lo que las hace distintas de las aplicaciones web, como veremos a continuación.

Los equipos cliente en esta arquitectura tienden a ser lo que se llama “fat clients”. Necesitan bastante capacidad de proceso en su CPU para poder ejecutar la lógica de presentación y la de negocio.

Arquitectura cliente/servidor en tres capas El paso siguiente sería la de separar la capa cliente en dos capas, una para la lógica de presentación y otra para la lógica de negocio. Podríamos hablar entonces de tres capas: capa de presentación, capa de negocio o intermedia, y capa de datos.

De esta forma descargamos al cliente, para el que ya no es necesaria tanta capacidad de proceso en su CPU, y llevamos esta lógica de negocio a un servidor, que normalmente estará separado del servidor de base de datos.

Podemos considerar que las aplicaciones web entran dentro de esta arquitectura, aunque con algunos matices.

Una aplicación web (y a nosotros nos interesan las aplicaciones ASP, que serían un caso particular) son aplicaciones especiales. Están formadas por un conjunto de páginas HTML, ASP, y otros recursos, que se ejecutan dentro de un servidor.

La capa de presentación estaría en el PC del cliente, donde se ejecuta el software del navegador (como puede ser el Internet Explorer o el Netscape Navigator), con la capacidad que éste tiene de interpretar el código HTML para generar el interfaz de usuario, junto con la capacidad de ejecutar scripts escritos en lenguajes como JavaScript o VBScript, para dotar de un cierto dinamismo e interactividad a este interfaz. Otras posibilidades serían el uso de controles ActiveX, applets de Java, etc.

La capa de negocio o intermedia estaría en el servidor web, donde se ejecuta el software de servidor web (como puede ser el IIS o un servidor Netscape), con la capacidad de atender peticiones vía HTTP de múltiples clientes. Esta lógica de negocio se codifica por medio de páginas web y componentes de servidor.

La capa de datos está en el servidor de datos, donde se ejecuta el software del gestor de base de datos (como puede ser el SQL Server o el Oracle), con la capacidad de gestionar el acceso de clientes a los datos almacenados, asegurando su consistencia, administrando bloqueos, transacciones, haciendo uso de procedimientos almacenados, triggers, etc.

Si la aplicación va a tener que soportar accesos a la base de datos de muchos usuarios simultáneamente, conviene que las capas de negocio y de datos estén en equipos físicos indepen-

Page 173: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 9. Modelos de apliciones cliente / servidor

173

dientes, para que el gestor de base de datos pueda ejecutarse de una forma mucho más eficiente, ya que consume bastante memoria, CPU y accesos al disco.

En tiempo de desarrollo es muy frecuente que las tres capas estén en el mismo equipo físico, y que se estén ejecutando en la misma máquina el gestor de base de datos, el servidor web y el navegador.

En las aplicaciones web no hay una conexión permanente entre cliente y servidor. Recordemos que el protocolo HTTP es un protocolo sin estado. Cuando un navegador cliente hace una petición de un recurso a un servidor, se crea una conexión temporal entre los dos, el servidor atiende la petición y manda la respuesta e inmediatamente se cierra la conexión. El servidor pierde completamente el rastro de este cliente, y destruye toda la información de estado que hubiera utilizado durante el tiempo en que estaba procesando la petición, de forma que si este mismo cliente vuelve a hacer otra petición al servidor, sería como empezar otra vez de cero.

Varias soluciones se han desarrollado para conseguir mantener el estado, y convertir así el HTTP en un protocolo capaz de “recordar al cliente” entre distintas peticiones. Unas soluciones pasan por almacenar esta información de estado en el propio cliente, por medio de cookies, y otras pasan por almacenar esta información en el servidor, en bases de datos, en ficheros, o en el caso de páginas ASP conservando variables dentro del objeto Session. También se usa con frecuencia el paso de información de una página a otra, por medio de parámetros ocultos (del tipo “hidden”) dentro de formularios. En cada caso será más adecuada una u otra solución.

El hecho de que la conexión entre cliente y servidor no sea permanente supone una desventaja de las aplicaciones web respecto a las aplicaciones cliente/servidor tradicionales. Resulta más difícil conseguir que la lógica de la aplicación funcione correctamente cuando se trata de un conjunto de páginas distintas que son enviadas al cliente una detrás de otra, sin mantenimiento de estado entre ellas.

Sin embargo las aplicaciones web también tienen una ventaja, y es el hecho de que la parte cliente se actualiza automáticamente, sin necesidad de ir a reinstalar cada vez que hay una modificación. Esto es así porque el código con la lógica de presentación se ejecuta en el cliente, es cierto, pero es en el servidor donde se genera de forma dinámica en el momento en que se hace cada petición (es decir, el script de la página ASP se encarga de generar dinámicamente el código HTML que será enviado al navegador del cliente para que éste lo interprete y construya el interfaz visual: marcos, tablas, etc). De esa manera si yo modifico las páginas HTML o ASP, cuando el cliente haga una nueva petición recibirá la versión actualizada de forma inmediata.

Precisamente este hecho hace que las aplicaciones web no encajen perfectamente bien en el concepto de aplicaciones en tres capas, porque la lógica de presentación realmente se genera en el servidor web, es decir, en la capa de negocio, aunque luego se ejecute en la capa de presentación.

Los procedimientos almacenados también se salen un poco del modelo de tres capas, porque suponen una lógica de negocio pero que está almacenada no en la capa intermedia sino en la capa de datos, es decir, en el gestor de la base de datos.

En cualquier caso, esta división de una aplicación en capas lógicas no debe entenderse como una clasificación estricta.

Normalmente el cliente en las aplicaciones web es lo que se llama un “thin client”, porque necesita muy poca capacidad de CPU. Realmente sólo la necesaria para ejecutar un navegador, capaz de generar el interfaz de usuario con HTML y JavaScript. Si quiero conseguir un interfaz más rico, tengo que cargar más el cliente, con controles ActiveX y applets, pudiendo entonces descargar de trabajo al servidor.

Page 174: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

174

Ejemplo de una aplicación ASP en tres capas Para aclarar los conceptos expuestos, apliquemos en un ejemplo todo lo dicho sobre las capas de una aplicación.

La aplicación estará formada por tres capas:

• La capa de datos estará formada por el gestor SQL Server. Usaremos la base de datos pubs que viene incorporada como ejemplo al instalar el gestor. Servirá los datos a la aplicación cliente, en este caso una página ASP.

• La capa intermedia estará formada por una página ASP, que genere dinámicamente una tabla HTML con los registros de la tabla stores de la base de datos pubs, y que será servida por un servidor web, en este caso el IIS.

• La capa de presentación será un navegador, en este caso el Internet Explorer, que se encargará de pedir la página ASP al servidor y de recibir la respuesta en forma de código HTML que mostrará por pantalla.

El código de la página ASP podría ser como el Código fuente 131.

<HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Set objCnx = Server.CreateObject("ADODB.Connection")objCnx.Open "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;DataSource=varrondo"Set objRst = objCnx.Execute("stores",,adCmdTable)%>

<div align="center"><table border="1"><tr><%for each elem in objRst.Fields%>

<th><%=elem.Name%></th><%next%></tr><%while not objRst.EOF%>

<tr><%for each elem in objRst.Fields%>

<td><%=elem.Value%></td><%next%></tr><%objRst.MoveNext%>

<%wend%></table></div>

<%objRst.CloseobjCnx.CloseSet objRst = NothingSet objCnx = Nothing%>

Page 175: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 9. Modelos de apliciones cliente / servidor

175

</BODY></HTML>

Código fuente 131

y conseguiríamos el resultado que se muestra en la Tabla 6.

stor_id stor_name stor_address city state zip

6380 Eric the Read Books 788 Catamaugus Ave. Seattle WA 98056

7066 Barnum's 567 Pasadena Ave. Tustin CA 92789

7067 News & Brews 577 First St. Los Gatos CA 96745

7131 Doc-U-Mat: Quality Laundry and Books 24-A Avogadro Way Remulade WA 98014

7896 Fricative Bookshop 89 Madison St. Fremont CA 90019

8042 Bookbeat 679 Carson St. Portland OR 89076

Tabla 6

Componentización de la capa intermedia

Diseño de la capa intermedia con un componente Vamos a rescribir la capa intermedia de nuestra aplicación, para poder usar las ventajas que ofrece la componentización. En realidad, escribiremos un componente orientado a los datos, a medio camino entre la capa intermedia y la capa de datos, puesto que su función será la de recuperar los datos del gestor de base de datos y entregárselos a la capa intermedia.

El código de acceso a la base de datos vamos a incluirlo en un componente que devuelva un recordset con los registros de la tabla stores. La página ASP simplemente se encarga de crear el objeto e invocar al método correspondiente, recuperando el recordset y formateando sus datos en una tabla HTML. De esta forma conseguiremos al menos tres ventajas:

• Este mismo componente que creemos podríamos reutilizarlo en otras páginas ASP de esta misma aplicación que necesiten obtener un recordset con los registros de la tabla stores. También podríamos utilizarlo en páginas ASP de otras aplicaciones web. Incluso en aplicaciones tradicionales escritas en Visual Basic o Visual C++.

• Si por cualquier motivo cambia la forma de acceder a los datos, porque cambiamos el gestor de base de datos de SQL Server a Access, o porque ahora decidimos acceder a través de un procedimiento almacenado, sólo tendremos que cambiar este componente y no hará falta que modifiquemos el código de la página ASP.

Page 176: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

176

• El acceso a los datos será más rápido, porque el código estará compilado dentro del componente, y además podremos utilizar el operador New de Visual Basic, lo que supone un enlace temprano al componente. Desde el script de una página ASP sólo podemos utilizar el enlace tardío que proporciona el método CreateObject.

Para crear el componente, abrimos un nuevo proyecto ActiveX DLL de Visual Basic y cambiamos el nombre del proyecto a “CompStores” y el del módulo de clase a “Stores”.

Como el componente va a acceder a la base de datos a través de ADO, necesitamos añadir al proyecto la referencia a ADO. Esto lo hacemos seleccionando la opción Referencias del menú Proyecto, como puede verse en la Figura 48, y en la lista que aparece seleccionando “Microsoft ActiveX Data Objects 2.5 Library”.

Figura 48

Al incluir esta referencia conseguimos dos cosas:

• Por una parte se carga la type library de ADO, y Visual Basic nos ayudará con el IntelliSense a medida que vamos escribiendo el código.

• Podré utilizar el early binding, lo que supone un mayor rendimiento a la hora de ejecutar el componente

El código del componente quedaría como en el Código fuente 132.

Option Explicit

Public Function listaStores() As ADODB.RecordsetDim objCnx As ADODB.ConnectionDim objRst As ADODB.RecordsetDim strCnx As String

Page 177: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 9. Modelos de apliciones cliente / servidor

177

strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;DataSource=varrondo"

Set objCnx = New ADODB.ConnectionobjCnx.Open strCnxSet objRst = New ADODB.RecordsetobjRst.Open "Stores", objCnx, , , adCmdTableSet listaStores = objRst

End Function

Código fuente 132

Como se ve, el interfaz está formado por un único método que no recibe parámetros, y que devuelve un objeto recordset. Todo el acceso a la base de datos queda dentro del componente, y descargo de esa tarea al script de la página ASP, que ahora tendría el Código fuente 133.

Los objetos objCnx y objRst son locales al método del componente, y se liberan automáticamente al salir del mismo, sin necesidad de que yo lo haga explícitamente.

<%@ Language=VBScript %><!--#include file="ADOVBS.inc"--><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Set objCom = Server.CreateObject("CompStores.Stores")Set objRst = objCom.listaStores%>

<div align="center"><table border="1"><tr><%for each elem in objRst.Fields%>

<th><%=elem.Name%></th><%next%></tr><%while not objRst.EOF%>

<tr><%for each elem in objRst.Fields%>

<td><%=elem.Value%></td><%next%></tr><%objRst.MoveNext%>

<%wend%></table></div>

<%Set objCom = Nothing%>

</BODY></HTML>

Código fuente 133

Page 178: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

178

Sólo tengo que crear una instancia del componente e invocar al método listaStores, recuperando el recordset que me devuelve en el objeto objRst. Luego sólo hay que formatear los datos que contiene en una tabla HTML, igual que en el caso anterior.

Rediseño del componente de la capa intermedia Si ahora decidimos cambiar el componente, para que acceda a través de un procedimiento almacenado, no tengo que tocar el código de la página ASP.

El procedimiento almacenado es el del Código fuente 134.

CREATE PROCEDURE RecuperaStoresASSELECT * FROM Stores

Código fuente 134

Y el Código fuente 135 es el que tendría ahora el componente (recordar los pasos que hay que seguir para descargar la dll de la memoria y poder así recompilar).

Option Explicit

Public Function listaStores() As ADODB.RecordsetDim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objRst As ADODB.RecordsetDim strCnx As String

strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;DataSource=varrondo"

Set objCnx = New ADODB.ConnectionobjCnx.Open strCnxSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "RecuperaStores"Set objRst = New ADODB.RecordsetobjRst.Open objCmd, , , , adCmdStoredProcSet listaStores = objRst

End Function

Código fuente 135

Un segundo rediseño del componente de la capa intermedia Incluso puedo rediseñar esta capa intermedia, llegando a una solución que seguramente resulta más óptima: en vez de que el método del componente devuelva un objeto Recordset, que siempre consume más recursos, haremos que devuelva una cadena, ya con el código HTML necesario para construir la tabla.

Nos serviremos para ello del método GetString del Recordset de ADO, que devuelve los datos del recordset en forma de cadena.

Page 179: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 9. Modelos de apliciones cliente / servidor

179

Este método recibe cinco parámetros:

• El primero puede tomar únicamente el valor por defecto adClipString.

• El segundo es el número de registros que van a ser convertidos a la cadena. Si no especifico este parámetro, se convierten todos los registros.

• El tercero es el delimitador que se usará en la cadena para separar los distintos campos de un registro. El valor por defecto es un tabulador. Para conseguir formatear esta cadena en forma de tabla de HTML, nos interesa que este separador sea “</td><td>”, con lo cual cerramos la etiqueta de la celda anterior y abrimos la de la celda siguiente.

• El cuarto es el delimitador que usará en la cadena para separar los distintos registros. El valor por defecto es un retorno de carro. Nos interesa que este separador sea “</td></tr><tr><td>”, para cerrar la celda y fila anteriores, y abrir la fila y celda siguientes.

• El quinto y último parámetro es el carácter que se usará para los campos que tengan valor NULL. Por defecto es la cadena vacía.

El Código fuente 136 es el de la nueva versión del componente.

Option Explicit

Public Function listaStores() As StringDim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objRst As ADODB.RecordsetDim strCnx As StringDim strRst As String

strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;DataSource=varrondo"

Set objCnx = New ADODB.ConnectionobjCnx.Open strCnxSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "RecuperaStores"Set objRst = New ADODB.RecordsetobjRst.Open objCmd, , , , adCmdStoredProcstrRst = objRst.GetString(, , "</td><td>", "</td></tr><tr><td>")strRst = Mid(strRst, 1, Len(strRst) - 8)strRst = "<table border=1><tr><td>" & strRst & "</table>"listaStores = strRst

End Function

Código fuente 136

La línea strRst = Mid(strRst, 1, Len(strRst) - 8) es necesaria para quitar el “<tr><td>”del final de la cadena, que sobra puesto que ya no hay más filas.

El Código fuente 137,de la página ASP, queda ahora mucho más reducido.

<%@ Language=VBScript %><!--#include file="ADOVBS.inc"--><HTML>

Page 180: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

180

<HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Set objCom = Server.CreateObject("CompStores.Stores")Response.Write objCom.listaStoresSet objCom = Nothing%>

</BODY></HTML>

Código fuente 137

Arquitectura cliente/servidor en n capas Cuando se divide la capa de negocio o intermedia de la aplicación ASP en varias capas, empieza a hablarse de arquitectura en n capas.

Generalmente se trata de cuatro capas, al dividir la capa intermedia en dos:

• Una capa está formada por componentes orientados al cliente, es decir, más cercanos a la capa de presentación, que hacen uso del modelo de objetos de ASP para escribir directamente código HTML a través del objeto Response.

• Otra capa está formada por componentes orientados a los datos, es decir, más cercanos a la capa de datos, a los que accede a través de ADO.

Más adelante retomaremos este ejemplo, y veremos cómo se pueden crear estos componentes orientados al cliente, accediendo al modelo de objetos de ASP.

Incluso la capa intermedia puede dividirse no sólo en estas dos capas lógicas, sino en dos capas físicas en dos servidores distintos: uno tiene el “servidor web” junto con los componentes orientados al cliente, y otro tiene el “servidor de aplicación” junto con los componentes de lógica de negocio y los orientados a datos.

Page 181: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Diseño de componentes para ASP

Introducción En este tema nos vamos a centrar en las particularidades que tienen los componentes que diseñemos para ASP.

Ya hemos visto en temas anteriores que, si bien todos los componentes cumplen la especificación COM, unos serán utilizables en un contexto y otros no. A nosotros nos interesan los componentes que sean utilizables desde páginas ASP, así como los condicionantes que esto nos impone a la hora de desarrollar el código de los mismos.

Tipos Variant Los que programamos en ASP sabemos que los lenguajes de script, como el VBScript, son lenguajes débilmente tipados, donde sólo existe el tipo Variant.

Este hecho tiene su importancia a la hora de diseñar un componente pensado para ser utilizado desde una página ASP. Dentro del componente estoy programando en Visual Basic, que es un lenguaje que sí me permite declarar las variables con distintos tipos.

Volvamos al componente que ya hemos empleado en temas anteriores, que presentaba un método que calculaba el incremento en un porcentaje del 7 por ciento sobre una cantidad pasada como argumento. En una de las versiones de este componente, diseñamos el método de tal forma que recibía este parámetro por referencia, es decir, va a trabajar con la variable original y no con una copia de la misma.

Page 182: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

182

Ya hemos probado este componente y hemos visto que funcionaba correctamente al instanciarlo desde una página ASP. Pero esto era así mientras en el método teníamos el parámetro definido como Variant. De esta forma, desde la página ASP pasamos al componente una variable Variant, el componente trabaja con ella, tomándola como Variant, y puede modificar su valor.

Si ahora abrimos el proyecto ActiveX DLL correspondiente a este componente, y modificamos el código del módulo de clase hasta dejarlo como queda en el Código fuente 138, podemos volver a pedir la página ASP que lo utilizaba para ver lo que ocurre.

Public Function calcular(cantidad As Integer) As Booleancantidad = cantidad * 1.07calcular = True

End Function

Código fuente 138

Lo único que hemos cambiado es el tipo de datos del parámetro: ya no es Variant, sino Integer. Recordemos que el código de la página ASP era como el Código fuente 139.

<%Set objPorcentaje = CreateObject("CompPorcentaje.Porcentaje")cantidad = 1000retorno = objPorcentaje.calcular(cantidad)Response.Write cantidadSet objPorcentaje = Nothing%>

Código fuente 139

El resultado que obtenemos es un error No coinciden los tipos: 'calcular'.

¿Por qué ahora no funciona y antes sí? Muy sencillo. Al pasar la variable por referencia, lo que le estamos pasando al método es precisamente eso: una referencia a una variable, con lo cual el código del método va a acceder a la variable original. Como esta variable original estaba definida como Variant en el script de ASP, no es posible que el método intente considerarla como Integer, y se produce el error.

Escrito de esta forma, el componente no sería utilizable desde una página ASP.

Veamos qué ocurre si el parámetro se pasa por valor, y no por referencia. Para ello volvemos a modificar el componente, hasta conseguir el Código fuente 140.

Public Function calcular(ByVal cantidad As Integer) As Currencycalcular = cantidad * 1.07

End Function

Código fuente 140

Page 183: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 10. Diseño de componentes para ASP

183

Para probar esta nueva versión del componente, preparemos una página ASP con un formulario, que nos permita probar con distintos valores del parámetro. El Código fuente 141 es el que escribimos para la página.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%if Request.Form("boton")="" then%><form method="post"><input name="cantidad")><input type="submit" name="boton"></form>

<%else%><%Set objPorcentaje = Server.CreateObject("CompPorcentaje.Porcentaje")cantidad = Request.Form("cantidad")Response.Write "El resultado es: " & objPorcentaje.calcular(cantidad)Set objPorcentaje = Nothing%>

<%end if%>

</BODY></HTML>

Código fuente 141

En la rama if generamos el formulario, con un campo de texto para introducir la cantidad y un botón de submitir, que enviará el formulario a la misma página. En la rama else recibimos ese formulario y recuperamos el valor del campo de texto, cuyo valor asignamos a la variable cantidad, que es la que pasamos como parámetro al método del componente.

Si pedimos la página y metemos el valor 1000 en el campo de texto, el funcionamiento es correcto. Le estamos suministrando al método un parámetro de tipo Variant, cuando el método espera recibir un parámetro del tipo Integer. Pero entre medias está el motor del script, que es el que se encarga de hacer automáticamente la transformación, tomando la variable cantidad, del tipo Variant, y suministrándole al método del componente una copia, del tipo Integer.

Por supuesto que si el motor de script no puede hacer conversión automática, porque los tipos son incompatibles, también falla. Probémoslo metiendo en el campo de texto una cadena, en vez de un entero. Obtendremos el error No coinciden los tipos: 'objPorcentaje.calcular' .

Como último ejemplo, y para que esto quede claro, volvamos a rediseñar el componente para que reciba el parámetro por referencia, es decir otra vez como en el Código fuente 142.

Public Function calcular(cantidad As Integer) As Booleancantidad = cantidad * 1.07calcular = True

End Function

Código fuente 142

Page 184: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

184

Y rescribamos la rama else de la página ASP para que quede como en el Código fuente 143.

<%Set objPorcentaje = CreateObject("CompPorcentaje.Porcentaje")cantidad = Request.Form("cantidad")retorno = objPorcentaje.calcular(cantidad)Response.Write cantidadSet objPorcentaje = Nothing%>

Código fuente 143

De esta forma, pongamos lo que pongamos en el campo de texto, obtendremos siempre el error de Nocoinciden los tipos: 'objPorcentaje.calcular'.

Sin embargo, si cambiamos la línea en la que se invoca el método calcular del componente por la que aparece en el Código fuente 144, veremos que, al menos, no obtendremos error.

retorno = objPorcentaje.calcular(Request.Form("cantidad"))

Código fuente 144

Este es un comportamiento un tanto curioso, pero que en todo caso no nos sirve en absoluto. Parece como si al pasarle al método directamente el valor de Request.Form(“cantidad”), fuera considerada como una variable de tipo Integer, que es la que necesita el método. Pero esto no es así en absoluto. En realidad, Request.Form(“cantidad”) no es ni siquiera una variable, sino un valor constante: ninguna propiedad, ni ningún elemento de cualquier colección del objeto Request es modificable directamente.

Estamos consiguiendo lo mismo que si pusiéramos la línea del Código fuente 145.

retorno = objPorcentaje.calcular(1000)

Código fuente 145

Como pasamos un valor constante, no una variable, no podemos acceder al valor modificado que debería devolvernos el método. Luego no nos da error, pero tampoco nos es de ninguna utilidad.

En definitiva, para componentes diseñados para ser utilizados desde páginas ASP, me interesa pasar por valor los argumentos de los métodos. Y esto por dos motivos:

• Consigo una mayor encapsulación del código del componente.

• Es posible que el componente trabaje internamente con tipos Integer, String, etc. El motor de script se encargará de hacer la transformación automática, siempre que los tipos sean compatibles, del Variant al tipo necesario en el método del componente.

Page 185: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 10. Diseño de componentes para ASP

185

Dentro del componente podemos usar los tipos de datos que permite el Visual Basic, como Integer, Currency, etc, siempre tengamos la precaución de pasar los argumentos por valor.

El motor de script hará la transformación automática del tipo variant de la página ASP al tipo determinado en el argumento del método del componente.

Si activamos el control de errores en la página ASP con On Error Resume Next antes de invocar al método, podremos capturar un posible error en la conversión en el caso de haber pasado un valor incorrecto (por ejemplo una cadena como argumento de un método que espera un Integer).

Acceso al modelo de objetos de ASP desde un componente Vamos a tratar ahora de los componentes que son específicos de ASP, puesto que hacen uso de su modelo de objetos, es decir, harán uso directo de los objetos Application, Response, etc.

A partir de la versión 4 del IIS, todos los objetos instanciados bajo MTS tienen acceso al ObjectContext. En la versión 5 ya no se llama MTS, sino Servicio de Componentes, integrado en COM+, pero el ObjectContext sigue existiendo.

Más adelante veremos con más detalle este objeto, pero ahora podemos adelantar que representa el contexto en el que se está ejecutando el componente, y le permite acceder a él.

En este caso el contexto de ejecución del componente será la página ASP, ejecutándose dentro del entorno del servidor IIS, luego podrá acceder al modelo de objetos de ASP.

Acceso al objeto Application Para explicar esto, veremos el ejemplo de un componente que acceda al valor de una variable con ámbito de aplicación. Tendrá un único método, que recibirá como parámetro el nombre de la variable a la que queremos acceder, y devolverá el contenido de la misma.

El parámetro se pasará por valor, no por referencia. Llamaremos al componente CompApplication, y al módulo de clase le llamaremos Application.

Llamaremos objContext a la variable que va a contener la referencia al objeto de contexto. La instrucción mediante la que conseguimos que esta variable obtenga la referencia al contexto es GetObjectContext.

Es imprescindible añadir al proyecto la referencia a “COM+ Services Type Library”, como se muestra en la Figura 49, si estamos trabajando en Windows 2000.

De no hacerlo así, no nos fallará el componente en el momento de la compilación, pero si en ejecución, en el momento de capturar la referencia al objeto de contexto, es decir, justo en la línea Set objContext = GetObjectContext. Además de esta forma podemos declarar con Dim la variable objContext.

A partir del objeto de contexto, puedo acceder al entorno en que se ejecuta el componente. En este caso, dentro de este entorno están los objetos integrados de ASP, y entre ellos el objeto Application. Para obtener una referencia a este objeto, lo hacemos con Set objApplication =objContext("Application").

Page 186: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

186

Figura 49

El Código fuente 146 muestra el contenido completo del método leeVariable.

Public Function leeVariable(ByVal nombre As Variant) As VariantDim objContext As ObjectContextSet objContext = GetObjectContextSet objApplication = objContext("Application")leeVariable = objApplication.Contents(nombre)

End Function

Código fuente 146

Para poder probar este componente, lo haremos desde una página en la que demos valor a una variable de aplicación, cuyo nombre pasaremos luego como parámetro al método. El Código fuente 147 podría ser el de la página.

Set objCom = Server.CreateObject("CompApplication.Application")Application("variable1")="aquí iría el valor de la variable"Response.Write objCom.leeVariable("variable1")

Código fuente 147

Si ejecutamos esta página, veremos que se muestra correctamente el valor de esa variable de ámbito de aplicación.

Sin embargo, probemos a añadir un proyecto EXE estándar que haga uso de este componente, con un formulario que presente un botón y un campo de texto Text1, y escribamos como código asociado al evento Click del botón el contenido en el Código fuente 148. Agregemos a este nuevo proyecto las

Page 187: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 10. Diseño de componentes para ASP

187

referencias al componente CompApplication y a “COM+ Services Type Library”, y luego con el botón derecho sobre el nombre del proyecto en el explorador de proyectos seleccionemos la opción “Establecer como inicial”.

Private Sub Command1_Click()Dim objCom As CompApplication.ApplicationDim valor As Variant

Set objCom = New CompApplication.Applicationvalor = objCom.leeVariable("variable1")Text1.Text = valor

End Sub

Código fuente 148

Si ejecutamos este proyecto veremos que da error en la línea Set objApplication =objContext("Application") del componente. Esto se debe a que ahora el componente no se está ejecutando en el contexto de una aplicación ASP, sino en el contexto de una aplicación tradicional de Visual Basic, luego no puede acceder a través de su contexto al objeto Application, que sólo tiene sentido en una aplicación ASP.

Acceso a los objetos Request y Response Veamos ahora que tenemos acceso a otros objetos integrados de ASP, como son el Request y el Response. Haremos un componente que, en un único método, procese el formulario enviado mediante POST en la petición del navegador del cliente y genere una tabla HTML con el contenido de sus elementos.

Para mayor comodidad de programación (la que nos proporciona el IntelliSense), añadiremos al proyecto la referencia al modelo de objetos de ASP, como aparece en la Figura 50. Por cierto, que la dll correspondiente se encuentra en dos ubicaciones distintas: en Winnt\system32\inetsrv\asp.dll y en Archivos de Programa\Microsoft Visual Studio\Common\IDE.

Figura 50

Page 188: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

188

Si llamamos CompFormulario al proyecto ActiveX DLL, y Formulario al módulo de clase, el Código fuente 149 muestra las líneas que debería contener el método.

Public Sub procesaForm()Dim objContext As ObjectContextDim objRequest As RequestDim objResponse As ResponseDim strHTML As String

Set objContext = GetObjectContextSet objRequest = objContext("Request")Set objResponse = objContext("Response")

strHTML = "<table border=1><tr><th>Campo</th><th>Valor</th></tr>"For Each campo In objRequest.Form

strHTML = strHTML & "<tr><td>" & campo & "</td><td>" & _objRequest.Form(campo) & "</td></tr>"

NextstrHTML = strHTML & "</table>"

objResponse.Write strHTMLEnd Sub

Código fuente 149

El código accede al objeto Request de ASP para ir leyendo, mediante un bucle for…each, a todos los elementos de la colección Form, y va construyendo una cadena strHTML con sus valores. En la última línea, utiliza el método Write del objeto Response para escribir esta cadena en la respuesta que será enviada de vuelta al navegador del cliente.

Una página ASP para probar este componente podría ser la del Código fuente 150.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%if Request.Form("boton")="" then%><form method="post"><input name="campoTexto")><br><input type="checkbox" name="campoCheck")><br><input type="submit" name="boton"></form>

<%else%><%Set objCom = Server.CreateObject("CompFormulario.Formulario")objCom.procesaFormSet objCom = Nothing%>

<%end if%>

</BODY></HTML>

Código fuente 150

Page 189: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 10. Diseño de componentes para ASP

189

Vemos que en la rama else, cuando el formulario es submitido, sólo es necesario instanciar el componente e invocar a su único método. El resultado que obtendremos será algo parecido al de la Tabla 7.

Campo Valor

campoTexto cualquier cosa

campoCheck on

boton Enviar consulta

Tabla 7

Retomemos ahora el componente que ya hemos utilizado en temas anteriores, que accedía a la tabla Stores de la base de datos Pubs, creada durante la instalación del SQL Server. Este componente tenía un único método listaStores, que devolvía un objeto recordset, para ser formateado en la página ASP.

Lo modificaremos ligeramente, de forma que ahora tenga un método llamado recuperaTabla, que reciba como parámetro el nombre de la tabla que queremos mostrar, y devuelva un array bidimensional formado por todos los campos de todos los registros de la tabla. Este array lo conseguiremos utilizando del método GetRows del objeto Recordset de ADO.

Pues bien, ahora que ya sabemos acceder desde un componente al modelo de objetos de ASP, hagamos un segundo componente, que reciba el array que devuelve el primero, que formatee en una tabla HTML este array, y que la escriba directamente sobre el objeto Response. Llamemos CompStores1 al proyecto ActiveX del primer componente y CompStores2 al del segundo.

CompStores1 podría tener algo parecido al Código fuente 151.

Option Explicit

Public Function recuperaTabla(ByVal nombreTabla As Variant) As Variant()Dim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objRst As ADODB.RecordsetDim strCnx As String

strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;DataSource=varrondo"

Set objCnx = New ADODB.ConnectionobjCnx.Open strCnxSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "SELECT * FROM " & nombreTablaSet objRst = New ADODB.RecordsetobjRst.Open objCmd, , , , adCmdTextrecuperaTabla = objRst.GetRows

End Function

Código fuente 151

Page 190: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

190

Como este componente accede a la base de datos a través de ADO, y queremos hacer uso del early binding, tenemos que añadir al proyecto la referencia a Microsoft ActiveX Data Objects 2.5 Library. Formamos la cadena SQL dinámicamente, con el parámetro del nombre de la tabla, y devolvemos como resultado del método la ejecución de GetRows sobre el recordset.

Compilemos este componente y pasemos al siguiente.

El componente CompStores2 quedaría con el Código fuente 152.

Option Explicit

Public Sub generaTabla(ByVal nombreTabla As Variant)Dim objContext As ObjectContextDim objResponse As ResponseDim objCom As CompStores1.Stores1Dim rec()Dim strHTML As StringDim i, j As Integer

Set objContext = GetObjectContextSet objResponse = objContext("Response")Set objCom = New CompStores1.Stores1

rec = objCom.recuperaTabla(nombreTabla)

strHTML = "<table border=1>"For i = 0 To UBound(rec, 2)

strHTML = strHTML & "<tr>"For j = 0 To UBound(rec, 1)

strHTML = strHTML & "<td>" & rec(j, i) & "</td>"NextstrHTML = strHTML & "</tr>"

NextstrHTML = strHTML & "</table>"

objResponse.Write strHTMLEnd Sub

Código fuente 152

Dentro del método obtenemos la referencia al objeto de contexto, y a partir de él la referencia al objeto Response. Creamos una instancia del componente CompStores1 e invocamos a su método recuperaTabla, pasando el parámetro del nombre.

Con el array bidimensional devuelto vamos construyendo una cadena strHTML con el código necesario para formatear una tabla HTML. En la última línea, escribimos esta cadena a través del método Write del objeto Response.

Este componente no está orientado a los datos, es decir, no accede a la base de datos, luego no necesito añadir al proyecto la referencia a ADO. Si embargo, está orientado al cliente, porque tiene parte de la lógica de presentación, puesto que accede al objeto Response del modelo de ASP. Para eso necesito añadir las referencias a las librerías de COM+ y ASP.

Además, este componente va a hacer uso del otro componente que acabamos de crear, CompStores1. Tendremos que añadir al proyecto esta referencia, como se muestra en la Figura 51.

Page 191: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 10. Diseño de componentes para ASP

191

Figura 51

El Código fuente 153 es todo lo que necesita la página ASP para usar los componentes. Se reduce a instanciar el componente CompStores2, e invocar su método generaTabla, pasando como parámetro el nombre de la tabla que queramos visualizar. Probar con varias de ellas, como “stores”, “authors”, “publishers”, …

Set objCom = Server.CreateObject("CompStores2.Stores2")objCom.generaTabla "Stores"Set objCom = Nothing

Código fuente 153

De esta manera hemos creado lo que podríamos considerar una aplicación en cuatro capas:

• La capa de presentación está en la máquina del cliente, donde se ejecuta el software del navegador web, capaz de hacer la petición de la página ASP y recibir la respuesta, todo a través del protocolo HTTP. El código HTML que recibe puede interpretarlo, y mostrar en este caso una tabla. Parte de la capa de presentación se encuentra en la página ASP, que es la que realmente genera dinámicamente ese código HTML, que luego se encargará de visualizar en el formato adecuado el navegador.

• La capa intermedia orientada al cliente estaría formada por el componente CompStores2, que se encarga de hacer la petición al componente CompStores1 de la tabla, pero que además accede directamente al objeto Response para escribir el código HTML de la tabla. Este componente se ejecuta en la misma máquina que el servidor web, y es gestionado por la página ASP, cuyo código se encarga de crearlo y destruirlo cuando es oportuno.

• La capa intermedia orientada a los datos la implementa el componente CompStores1, que recibe la petición de tabla que le hace el componente CompStores2, y que accede al gestor de

Page 192: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

192

base de datos a través de los objetos de ADO. Si este componente se ejecutara en una máquina distinta de la del servidor web, podríamos denominarla “servidor de aplicación”.

• La capa de datos está formada por el gestor de base de datos, y podría ejecutarse en una máquina diferente de la del servidor web y de la del servidor de aplicación.

El hecho de separar la capa intermedia en una capa orientada al cliente y otra orientada a datos, nos permite una mayor posibilidad de reutilizar los componentes. Si por ejemplo decidimos cambiar el componente que accede a la base de datos, porque vamos a usar otro servidor, o un procedimiento almacenado en vez de una cadena SQL, sólo tendría que tocar ese componente y recompilarlo. Mientras el interfaz que le presenta al componente orientado al cliente no cambie (es decir, que siga recibiendo como parámetro un nombre de tabla y devolviendo un array bidimensional), todo funcionará igual que antes.

Además, al no depender el componente orientado a datos del modelo de objetos de ASP, puedo utilizarlo en otras aplicaciones, por ejemplo desde un EXE estándar de Visual Basic.

Recompilación de componentes con enlace temprano Cambiemos por ejemplo el código del componente orientado a los datos por el Código fuente 154.

Option Explicit

Public Function recuperaTabla(ByVal nombreTabla As Variant) As Variant()Dim objCnx As ADODB.ConnectionDim objRst As ADODB.RecordsetDim strCnx As String

strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;DataSource=varrondo"

Set objCnx = New ADODB.ConnectionobjCnx.Open strCnxSet objRst = New ADODB.RecordsetobjRst.Open nombreTabla, objCnx, , , adCmdTablerecuperaTabla = objRst.GetRows

End Function

Código fuente 154

Ahora no usamos el objeto Command, sino que pasamos como parámetro al método Open del Recordset el nombre de la tabla. La ejecución de la página ASP será igual que antes. No tenemos que modificar el código del componente orientado al cliente.

Lo que sí tenemos que hacer es recompilarlo. Como dentro de CompStores2 estamos usando enlace temprano (early binding) al CompStores1 mediante la instrucción Set objCom = NewCompStores1.Stores1, al haber recompilado el CompStores1 tenemos que recompilar el CompStores2.

De no hacerlo, al ejecutar la página ASP obtendríamos el error Esta clase no admiteAutomatización o la interfaz esperada.

Esta recompilación no sería necesaria si utilizáramos enlace tardío (late binding), es decir, si hubiéramos usado Set objCom = CreateObject(“CompStores1.Stores1”).

Page 193: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 10. Diseño de componentes para ASP

193

Implementación de interfaces en Visual Basic Los interfaces se definen en Visual Basic a través de clases abstractas. Una clase abstracta no contiene código de implementación, sólo las declaraciones de las funciones. La implementación real del interfaz ocurre en otras clases, en aquéllas que implementan el interfaz.

Vamos a crear un nuevo proyecto ActiveX DLL de Visual Basic al que llamaremos CompInterfaz, con un módulo de clase llamado IInterfaz1. Por convenio, a los nombres de interfaz se les suele anteponer la “I”. Estableceremos la propiedad de instanciación de esta clase como PublicNotCreatable, como se ve en la Figura 52. Esto significa que no se pueden instanciar objetos a partir de esta clase. Sólo será una plantilla para otras clases que implementen el interfaz.

Figura 52

Con ayuda de la utilidad Generador de clases, añadimos un método al módulo de clase, como se muestra en el Código fuente 155.

Public Function metodo1(ByVal par As Integer) As IntegerEnd Function

Código fuente 155

Vamos a utilizar esta clase abstracta en otro módulo de clase. Para ello añadimos un nuevo módulo de clase al proyecto, llamado “Implementa”, y en su sección de Declaraciones añadimos la línea Implements IInterfaz1. Esto significa que esta clase acepta el “contrato”, con lo cual está obligada a implementar todos y cada uno de los métodos que formaran parte del interfaz. En este caso el metodo1. Si no lo implementara, obtendríamos un error de compilación.

Nada más añadir esta línea, aparecerá en el combo de “Objetos”, en la esquina superior izquierda del panel de edición, el nombre del interfaz. Si lo seleccionamos de la lista, automáticamente aparecerá la estructura del método metodo1, al que se le antepone el nombre del interfaz y un guión bajo “_”, listo

Page 194: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

194

para que lo implementemos con las líneas de código que creamos oportunas. Dejémoslo con el Código fuente 156.

Implements IInterfaz1

Public Function metodo3(ByVal par As Integer) As Integermetodo3 = par + 3

End Function

Private Function IInterfaz1_metodo1(ByVal par As Integer) As IntegerIInterfaz1_metodo1 = par + 1

End Function

Código fuente 156

Como puede verse, hemos añadido además un método llamado “metodo3”, pero que no es fruto de implementar el interfaz anterior, sino un método como los que hemos escrito hasta ahora.

Vamos a repetir el proceso llevado a cabo con el módulo de clase IInterfaz1, para crear otro módulo de clase IInterfaz2, con un método llamado metodo2. Haremos que la clase Implementa “firme el contrato” también con este interfaz, lo que le obliga a implementar también el metodo2. El resultado final se muestra en el Código fuente 157.

Implements IInterfaz1Implements IInterfaz2

Public Function metodo3(ByVal par As Integer) As Integermetodo3 = par + 3

End Function

Private Function IInterfaz1_metodo1(ByVal par As Integer) As IntegerIInterfaz1_metodo1 = par + 1

End Function

Private Function IInterfaz2_metodo2(ByVal par As Integer) As IntegerIInterfaz2_metodo2 = par + 2

End Function

Código fuente 157

Si ahora compilamos el proyecto, y desde una página ASP instanciamos este objeto, veremos que sólo tenemos disponible el metodo3, pero no el metodo1 ni el metodo2. ¿Qué es lo que está ocurriendo?

Cuando se compila un proyecto ya sea con ActiveX DLL o con EXE, Visual Basic crea un interfaz por defecto para cada clase. Dicho interfaz toma el nombre de la clase, precedido por un carácter de subrayado bajo. Por ejemplo, el interfaz por defecto para la clase “Implementa” es “_Implementa”. Los métodos que no forman parte de otro interfaz (precedido por la línea de subrayado y el nombre del interfaz), como es el caso del metodo3, pasan a ser miembros del interfaz por defecto. Todo esto lo realiza Visual Basic sin que tengamos que especificárselo.

Pues bien, al ser el VBScript de una página ASP un lenguaje en que no es posible asignar tipo a las variables, sólo nos está permitido acceder a este interfaz por defecto, es decir, sólo podemos acceder al metodo3. A continuación veremos que para acceder a los otros interfaces, distintos del interfaz por defecto, es necesario declarar variables con el tipo específico de esos interfaces.

Page 195: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 10. Diseño de componentes para ASP

195

Vamos a probar este componente desde Visual Basic.

Para ello, desde el menú Archivo, seleccionemos la opción “Agregar proyecto”, que elegiremos del tipo EXE estándar. El grupo de proyectos quedará al final como se muestra en la Figura 53.

Figura 53

Al formulario que se crea automáticamente, añadimos un botón y hacemos doble clic sobre él para implementar el código asociado a su evento Click, como se ve en el Código fuente 158.

Private Sub Command1_Click()Dim objCom As ImplementaDim i1 As IInterfaz1Dim i2 As IInterfaz2Dim var As Integer

Set objCom = New Implementavar = objCom.metodo3(1)

Set i1 = objComvar = i1.metodo1(1)

Set i2 = objComvar = i2.metodo2(1)

End Sub

Código fuente 158

En él definimos las variables i1 e i2 del tipo de los dos interfaces IInterfaz1 e IInterfaz2. Luego instanciamos el componente e invocamos al metodo3. Luego asignamos sucesivamente a las variables de referencia i1 e i2 la referencia al objeto e invocamos el método correspondiente a cada interfaz.

Cuando usa Set para asignar valores a una variable de tipo interfaz, Visual Basic pregunta al objeto si éste tiene implementada dicha interfaz. El método que utiliza para ello se llama QueryInterface y pertenece a la interfaz IUnknown.

Vamos a establecer el proyecto EXE estándar recién creado como proyecto de inicio. Para ello pulsamos con el botón derecho sobre él en el Explorador de proyectos y seleccionamos la opción “Establecer como inicial”.

Page 196: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

196

Si depuramos el componente, veremos que podemos invocar todos los métodos correctamente, y la variable var toma los valores adecuados después de la ejecución de cada método. En definitiva, desde el proyecto EXE estándar de Visual Basic conseguimos lo que no podíamos hacer desde el script de ASP: acceder tanto a los métodos del interfaz por defecto como a los métodos de los interfaces IInterfaz1 e IInterfaz2.

Como desarrollador de aplicaciones ASP, tal vez nunca utilicemos otras interfaces aparte de las que Visual Basic proporciona por defecto. La elección a la hora de realizar la implementación depende de la complejidad de la aplicación y de los requisitos del diseño. Desde luego, desde un componente instanciado desde una página ASP sí podría acceder a interfaces, distintos del interfaz por defecto, que implemente un segundo componente.

Las bibliotecas de tipos se utilizan para especificar los interfaces de un objeto, es decir, para definir los métodos y parámetros de un interfaz, y no tiene nada que ver con la implementación de ésta. COM utiliza IDL para describir interfaces, ya que permite ver lo que realmente ocurre cuando se crea un componente. Las bibliotecas de tipos pueden formarse a partir de archivos IDL, los cuales, a su vez, pueden utilizarse en tiempo de compilación o de ejecución. La definición de interfaces en visual Basic se hace con clases abstractas (o simplemente utilizando la interfaz por defecto) en vez de con el IDL. Visual Basic crea bibliotecas de tipos y las incluye en los componentes. Existen herramientas, como el OLE/COM Object Viewer incluido en Microsoft Visual Studio, que le permiten convertir cualquier biblioteca de tipos en IDL, incluso aquellas que se crearon con Visual Basic. Es importante observar que actualmente no pueden aprovecharse todas las posibilidades del IDL en Visual Basic.

Page 197: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Servicios de Componentes

Introducción En este tema se va a tratar de los Servicios de Componentes que proporciona el Windows 2000.

Sin embargo, se empezará hablando del MTS (Microsoft Transaction Server), para situar al lector en el proceso de evolución de Windows NT a Windows 2000, y poder establecer comparaciones útiles para aquellos que ya conocieran este producto. Además, los conceptos del MTS son aplicables en su práctica totalidad a los Servicios de Componentes, exceptuando algunas diferencias que se comentarán adecuadamente.

Características del MTS (Microsoft Transaction Server) Aunque su nombre pueda producir confusión, el MTS no es sólo un monitor transaccional, sino que es un servidor de componentes, con soporte de Transacciones, que simplifica el desarrollo y distribución de las aplicaciones servidoras que utilizan la tecnología COM. Este servidor define un modelo de programación y proporciona un entorno de ejecución, además de unas herramientas de administración para las aplicaciones más complejas.

Pueden utilizarse herramientas como Visual Basic, Visual C++, Delphi, Visual J++, Visual FoxPro o incluso COBOL para construir aplicaciones servidoras para MTS sin necesidad de tener que codificar los complejos mecanismos de comunicación entre componentes. Por esta razón, MTS reduce significativamente el tiempo necesario para la construcción de aplicaciones de n-capas, y aumenta la extensibilidad, escalabilidad y reusabilidad de las aplicaciones.

Page 198: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

198

Forma parte del Windows DNA (Windows Distributed interNet Application Architecture) para aplicaciones internet/intranet de n-capas.

El MTS es un servicio creado para Windows NT. No es una parte integral del sistema operativo, sino que se instala como un servicio adicional, con el Windows NT Option Pack. Supone una funcionalidad añadida a la del COM, proporcionando un nuevo runtime para los objetos que se están ejecutando en la capa intermedia de una aplicación distribuida según el modelo de n-capas.

Esta funcionalidad añadida consiste sobre todo en soporte para transacciones distribuidas, seguridad integrada, pooling de hilos de ejecución, y facilidades de configuración y administración de los componentes mediante el uso de propiedades declarativas.

Para Windows 95/98 existe una versión reducida del MTS, del mismo modo que existe una versión reducida del servidor IIS denominada PWS (Personal Web Server).

Como ya se ha comentado, el MTS no sólo proporciona la funcionalidad necesaria para gestionar las transacciones distribuidas, sino que incluso componentes no-transaccionales pueden obtener ventajas en su ejecución si hacen uso de los servicios que aporta.

El MTS aúna dos funcionalidades principales:

• Object request broker (ORB). Gestiona la instanciación de objetos para los clientes. Sabe dónde están los objetos y cómo crearlos. Gestiona la comunicación entre los componentes, ahorrando al programador el trabajo de escribir el código en C++ que hiciera lo mismo). En una página ASP, intercepta los Server.CreateObject y crea él mismo los objetos, usando sus propios objetos COM para supervisar a estos objetos.

• Monitor transaccional: MS DTC (Distributed Transaction Coordinator). Tiene dos funciones:

• Comparte recursos (procesos, hilos, …) del sistema entre los clientes. Cada proceso necesita una cantidad de memoria. Si se tienen muchos clientes simultáneos, es necesaria mucha memoria, que no es un recurso especialmente caro en la actualidad, pero se requiere mucho tiempo de CPU para gestionar todos los procesos. Es mejor compartir procesos: un mismo proceso sirve a varios clientes. De esta forma hace falta menos CPU para gestionarlos, así que el rendimiento es mayor, con menos memoria RAM.

• Usa los protocolos de transacciones para coordinar las acciones de los distintos componentes. El programador no tiene que poner el código para gestionar el rollback; todo está centralizado en el MTS.

Servicios que aporta el MTS El MTS proporciona una serie de ventajas para el programador:

• Administrando los recursos del Sistema Operativo como procesos e hilos. Por esto varios usuarios pueden acceder y ejecutar la aplicación a la vez.

• Sincronizando el acceso a los datos, para que no se reduzca el rendimiento cuando muchos usuarios accedan a la misma información de la base de datos.

• Obteniendo información acerca de los usuarios: quiénes son, qué tipo de operaciones realizan, así se evita que el trabajo de un usuario interfiera en el de otro.

Page 199: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

199

• Implementando la seguridad, de tal manera que los usuarios sólo tengan acceso a los recursos para los que el administrador les ha dado permisos.

• Implementando la administración y configuración, esto reduce el coste de distribución, administración y/o modificación.

Estas ventajas las proporciona a través de un conjunto de servicios:

Transacciones para componentes Son similares a las de las bases de datos, a diferencia de que éstas últimas engloban un conjunto de sentencias SQL, mientras que las de componentes engloban el trabajo de uno o más componentes. MTS monitoriza la interacción entre los componentes y los recursos transaccionales, como pueden ser bases de datos, y coordina los cambios. Si algún componente corta la transacción, MTS facilita el rollback de todos los cambios realizados por el componente y de todos los demás componentes que se ejecutaban en el mismo contexto de transacción.

Comercio de objetos MTS actúa como un comerciante de objetos, sirviendo las peticiones de instanciación que varios clientes hacen. MTS reconoce la petición, coordina su creación y mantenimiento, y destruye las instancias de componentes COM y de los hilos que éstas hayan creado. La independencia de la ubicación de los componentes respecto de los clientes es otra de las ventajas que aporta este servicio que, además, soporta la reconfiguración dinámica y el cambio de la ubicación de un objeto sin tener que cambiar el código de la aplicación cliente, después de la fase de desarrollo.

Independencia entre procesos MTS permite agrupar varios componentes en paquetes, cada uno de los cuales trabaja en su propia área de direcciones protegida. Esto es crítico cuando, por ejemplo, se está integrando un componente comprado a terceros en una solución existente. Los errores de un componente no deberían propagarse a los componentes que están en otro paquete.

Fondo común de recursos MTS administra de forma automática y reúne en un fondo común, llamado pooling, dos de los recursos más críticos para el servidor: hilos y conexiones a bases de datos. El fondo común de conexiones a bases de datos administrado por el controlador ODBC o OLE DB evita al desarrollador el manejo complejas características de sincronización. MTS emplea un fondo común de hilos para acelerar los tiempos de respuesta a los clientes, aportando también los mecanismos necesarios para que varios componentes compartan información sin que el desarrollador tenga que preocuparse de problemas de concurrencia ni de sincronización.

Activación en el momento (Just-In-Time) Permite que el sistema desactive y reactive un objeto mientras sus clientes le siguen haciendo referencia; esta posibilidad se traducen en un uso más eficiente de los recursos del servidor. Desde el

Page 200: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

200

punto de vista del cliente, sólo existe una copia del objeto desde que lo mandó crear hasta que lo destruyó. Realmente, el objeto puede desactivarse y reactivarse varias veces. La administración de instancias de objetos y la activación en el momento benefician la escalabilidad de las aplicaciones.

Seguridad MTS proporciona un servicio de seguridad plenamente integrado con la seguridad de Windows NT, facilitando el control de uso por parte de personal no autorizado, incluso a los componentes comprados a terceros. Existen dos modelos de seguridad soportados por MTS: el modelo declarativo y el modelo programado". En el modelo declarativo la seguridad se configura con el Administrador de Usuario de Windows NT y con el Explorador de MTS. El modelo "programado" proporciona la funcionalidad necesaria para preguntar, en tiempo de ejecución, quién quiere utilizar el componente. Un componente puede alterar su comportamiento dependiendo de la respuesta.

Conceptos principales del MTS

La intercepción El modelo COM no fue modificado para albergar esta nueva funcionalidad que ofrece el MTS. La capa de runtime del COM permanece igual que antes, pero convive ahora con una capa que se le superpone, que es la capa del runtime del MTS. Debido a esto, la compenetración entre COM y MTS no es siempre todo lo eficiente que podría ser, y supone un esfuerzo adicional para el programador, que debe conocer los dos modelos. Veremos más adelante que algunas técnicas de programación que son perfectamente válidas para COM no lo son para MTS.

Al ser dos capas de runtime distintas, para que el MTS pueda aportar funcionalidad añadida a los objetos COM que instancie un cliente, debe interponerse entre el cliente y el objeto en el momento de la creación del mismo, para poder controlar así su ciclo de vida y sus características de ejecución.

Propiedades declarativas. El catálogo del MTS Para hacer uso de la funcionalidad del MTS, debemos darle la autorización para que se encargue de gestionar y supervisar las instancias de nuestros componentes.

Esto se hace añadiendo los componentes a un “paquete” del MTS. Estos paquetes deben ser entendidos como unidades de administración de componentes.

Una vez registrado el componente, es posible configurar muchas de sus características de ejecución mediante lo que se llaman propiedades declarativas.

Ya se entiende la flexibilidad que todo esto supone. El programador construye sus componentes igual que antes, sin tener que hacer apenas nada especial. Después de compilados, se registran en el MTS, y se modifican sus atributos declarativos, que describen las propiedades de ejecución de ese componente. No hay necesidad de programar nada nuevo, ni recompilar.

Las propiedades declarativas suponen un nuevo enfoque de programación. Tradicionalmente, una aplicación hacía uso de los servicios proporcionados por el sistema operativo mediante un API de bajo nivel. Si más adelante se quería variar el uso que la aplicación hacía de estos servicios, era necesario

Page 201: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

201

modificar el código y recompilar. Ahora este esfuerzo no es necesario, y basta con modificar una serie de propiedades declarativas, sin necesidad de tocar una sola línea de código.

La información de estas propiedades declarativas de cada componente registrado en algún paquete del MTS se guarda en el catálogo. Este catálogo almacena información adicional a la que se guarda en el registro de Windows.

Funcionamiento del MTS Explicaremos aquí, de forma muy breve y simplificada, el funcionamiento interno del MTS. Esto ayudará a comprender algunas cosas que se verán más adelante.

El MTS Executive, encargado de gestionar el funcionamiento del MTS, trabaja con dos objetos COM principales (el objeto Context Wrapper y el objeto de contexto), y dos interfaces (interfaz ObjectContext e interfaz ObjectControl):

El objeto Context Wrapper Es el objeto que ve realmente el cliente que pide una instancia de un objeto MTS, resultado de la intercepción que éste realiza en el momento de la creación.

El MTS inspecciona el interfaz del objeto, crea un objeto Context Wrapper con ese interfaz y le devuelve esa referencia al cliente. No activa el objeto real hasta que el cliente pide el primer método de ese objeto (JIT: Just-In-Time Activation). Así ahorra recursos. También lo destruye lo antes posible (ASAP: As-Soon-As-Possible Deactivation), sin que el cliente lo sepa: él sigue “engañado” con su referencia al Context Wrapper.

El objeto es desactivado después de cada llamada a un método. Esto es eficiente, aunque no lo parezca, porque MTS guarda la DLL en su memoria caché, y no le lleva tiempo desactivar y reactivar. Pero el estado se pierde entre llamadas a los métodos. Esto me asegura la propiedad de aislamiento de las transacciones. Si quiero guardar el estado del componente, tengo recurrir a otros mecanismos, como guardarlo en una base de datos o pasarlo como parámetro entre métodos.

En definitiva, el Context Wrapper sirve para “engañar” al cliente, que se crea que tiene la referencia al objeto mientras que realmente es el MTS el que gestiona cuándo se activa y desactiva.

El objeto de contexto Almacena información asociada con el objeto (creador del objeto, información de seguridad, transacción en curso, etc). Es usada por el entorno para saber cómo el componente interactúa. Todos los componentes registrados en MTS lo tienen. Suele decirse que el objeto de contexto es como la “sombra” del objeto.

Almacena información de seguridad, que le permite al Context Wrapper saber si el cliente tiene permiso para usar los métodos que ha pedido.

Almacena información del contexto de ejecución del componente. Esta información es la que le permite al MTS meter un componente, programado de forma aislada y como si fuera monousuario, dentro de una transacción distribuida con gestión de concurrencia, sin que yo tenga que programar

Page 202: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

202

nada especial. Gracias a este objeto es posible monitorizar las transacciones y ver estadísticas desde la consola administrativa del MTS.

IIS almacena información en el objeto de contexto, ya que IIS es parte del entorno y está construido con tecnología MTS. Entre esta información almacenada están las referencias a los objetos integrados de ASP. Luego no será necesario pasar estas referencias a un objeto COM para que pueda utilizarlas.

En resumen, el objeto de contexto puede utilizarse para:

• Informar que se ha terminado el trabajo del objeto.

• Evitar que se confirme una transacción, ya sea temporal o permanentemente.

• Instanciar otros objetos de MTS e incluir su trabajo en el ámbito de la transacción del objeto creador.

• Averiguar la función del usuario que utiliza el objeto.

• Averiguar si dispone de los permisos necesarios.

• Averiguar si el objeto se está ejecutando en una transacción.

• Recuperar objetos incorporados en Microsoft Internet Information Server.

El interfaz ObjectContext El objeto de contexto que acabamos de ver implementa este interfaz ObjectContext. Puedo acceder a este interfaz desde cualquier objeto MTS con las líneas mostradas en el Código fuente 159.

Dim objContext As ObjectContextSet objContext = GetObjectContext()

Código fuente 159

Los principales métodos de este interfaz son:

• SetComplete: indica al MTS que el trabajo realizado por el objeto ha finalizado con éxito, y puede ser confirmado cuando todos los objetos implicados en la transacción terminen su trabajo. El método SetComplete también indica al MTS que cualquier recurso retenido por el objeto, incluido el propio objeto, puede ser reciclado.

• SetAbort: indica al MTS que el trabajo realizado por el objeto no ha finalizado con éxito, con lo cual todos los cambios hechos por este objeto y los realizados por otros objetos en la misma transacción quedarán anulados. El método SetComplete también indica al MTS que cualquier recurso retenido por el objeto, incluido el propio objeto, puede ser reciclado.

• CreateInstance: crea un nuevo objeto, pero además MTS copia la información del objeto de contexto del objeto creador al objeto de contexto del objeto creado. Así formará parte de la misma transacción y tendrá las mismas características de seguridad. Para que forme parte de la misma transacción, el nuevo objeto debe tener su atributo transaccional configurado como “Requiere una transacción” o “Compatible con transacciones”.

Page 203: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

203

• EnableCommit: Declara que el trabajo de un objeto no está necesariamente terminado, pero que sus actualizaciones de la transacción son consistentes y que podrían confirmarse en su forma actual. El objeto mantiene su estado interno durante las llamadas realizadas a otros métodos hasta que le llame a SetComplete o SetAbort, o hasta que la transacción termina. EnableCommit es la establecida por defecto para un objeto, si éste no llama a otros métodos del objeto de contexto. Por ejemplo, una compañía tiene un objeto Pedido que crea pedidos que hay que suministrar a los clientes. Un cliente puede crear un pedido a través de internet y solicitar que le sea enviado a una dirección determinada. O el cliente puede ir a buscar el pedido directamente a uno de los almacenes de la compañía. Un fichero ASP crea el pedido llamando al método AñadirPedido del objeto Pedido. Éste llama a EnableCommit ya que no sabe dónde irá el cliente a buscarlo. Una vez el cliente elija, la página ASP podrá llamar a los métodos DejarEnAlmacén o EnviarADirección, para indicar qué debe hacerse con el pedido. Cada uno de estos dos último métodos llamarán a SetComplete.

• DisableCommit: Declara que el trabajo de un objeto no está terminado, que sus actualizaciones de la transacción son inconsistentes y que, por lo tanto, no pueden ser autorizadas en su forma actual.

El interfaz ObjectControl Un buen componente MTS implementa este interfaz. Tiene tres métodos:

• Activate: es invocado automáticamente por el MTS Excecutive cuando el cliente invoca un método del componente. Aquí pondría el código de inicialización que sea global para todos los métodos del componente. Por ejemplo, si todos los métodos acceden a una BD, aquí crearía la conexión.

• Deactivate: es invocado automáticamente por el MTS Executive cuando finaliza la ejecución del método, dando como resultado un SetComplete o un SetAbort. Aquí pondría el código de finalización que sea global para todos los métodos del componente. En el ejemplo utilizado, éste sería el lugar en el que liberar la conexión.

• CanBePooled: devuelve un booleano que indica si el MTS puede meter este componente en un fondo compartido, o pooling, de objetos. En MTS 2.0 devuelve siempre False.

En estos métodos Activate y Deactivate es donde se debe poner el código de inicialización y de finalización del objeto, no en los eventos Class_Initialize y Class_Terminate de Visual Basic. Por varios motivos:

• El MTS tiene que crear un objeto de prueba la primera vez que se usa un objeto MTS, para ver si es un objeto Java. Lo crea y lo destruye. En esta prueba llama a los métodos Class_Initialize y Class_Terminate, con lo que haría la inicialización y destrucción cuando no es necesaria. Si embargo en esta prueba no llama a Activate y Deactivate.

• El MTS no permite mantener el estado del componente entre llamadas, lo que significa que la inicialización y finalización debe hacerse en Activate y Deactivate, que son los métodos invocados precisamente entre estas llamadas.

• Desde los métodos Class_Initialize y Class_Terminate no está disponible el objeto de contexto, con lo que no podremos acceder desde ellos, por ejemplo, a las características de seguridad del componente.

Page 204: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

204

Instanciar un objeto a partir de un componente MTS

Instanciar un objeto desde otro objeto de Visual Basic Usando el operador New:

• Si se instancia el objeto a partir de un componente incluido en el mismo servidor COM (es decir, un mismo proyecto ActiveX DLL que contiene varios módulos de clase), el Visual Basic sabe cómo tiene que crearlo, y no necesita llamar a las rutinas de COM para hacerlo. Entonces se crea una instancia privada, de la cual el MTS no sabe que existe. Como consecuencia, no se crea un objeto de contexto, aunque el componente esté registrado en MTS, y el objeto creado no podrá intervenir en transacciones. Es un objeto COM tradicional.

• Si se instancia desde otro servidor COM, sí se llama a las rutinas de COM y el objeto creado dispondrá de un objeto de contexto, en el caso de que estuviera registrado en COM.

Usando el método CreateObject:

• Equivale a New cuando se instancia desde servidores COM distintos; sin embargo, New es más eficiente por utilizar el enlace temprano. Siempre usa las rutinas de COM para crear el objeto, con lo que se crea un objeto de contexto para él. Pero no se transmite la información sobre el contexto del componente que lo creó, sino que se crea un objeto de contexto completamente nuevo, y no podrá formar parte de su transacción.

Usando el método CreateInstance:

• Al crear el nuevo objeto, el MTS copia toda la información del objeto de contexto del objeto creador al objeto de contexto del objeto creado, con lo cual podrá compartir la transacción y las características de seguridad.

Instanciar un objeto desde una página ASP con VBScript Usando el método CreateObject:

• Esta función de VBScript hace una llamada directa a las rutinas COM, luego no pasa por IIS, y por lo tanto tampoco por MTS, luego el objeto correrá en una transacción separada en el caso de ser transaccional. No debe usarse en ASP.

Usando el método Server.CreateObject:

• Este método del objeto integrado Server transmite la petición de instanciación del objeto al IIS, que se encargará de utilizar el MTS en caso necesario. Si la página es transaccional, este componente correrá en la misma transacción. En definitiva, este método emplea internamente el método CreateInstance del interfaz ObjectContext.

Page 205: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

205

Introducción a las transacciones Para que una transacción sea fiable ha de hacer lo que los usuarios y administradores esperan que haga; esto incluye la capacidad de devolver el estado a una situación conocida, válida y consistente en caso de que se produzca un fallo. Son las transacciones las que dan esta garantía al sistema.

Una transacción es una unidad indivisible de trabajo que puede ser deshecha en cualquier momento antes de que finalice. Son muy importantes pues proporcionan a los desarrolladores el marco adecuado para trabajar con componentes no muy fiables.

Toda transacción tiene un comienzo, uno o dos finales y algunos procesos que se ejecutan en medio. Una transacción puede terminar sin más o terminar y realizar una "vuelta atrás" al estado anterior como si no se hubiese realizado operación alguna. Las transacciones pueden ser abortadas, tanto por los clientes como por el propio sistema de transacciones. Por ejemplo, un servidor de datos puede abortar una transacción si ésta mantiene bloqueos durante demasiado tiempo o si se produce un ínter bloqueo.

Para el comercio electrónico, el comportamiento transaccional es fundamental. Es inaceptable que un sistema funcione parte del tiempo sí y parte no, aunque el tiempo que sí está funcionando sea del 99%. Por ello, se ha hecho especial hincapié en los aspectos de recuperación de las transacciones, para garantizar el 100% de fiabilidad.

En una situación en la que los elementos de la transacción incluyen transferencias de una cuenta bancaria a otra, si el proceso de aumento de la cuenta se ejecuta correctamente, pero el de disminución no, la transacción debería fallar y no dar dinero que no se tiene.

Cualquier actividad que pueda ser deshecha forma parte activa de la transacción. Los accesos a bases de datos son los ejemplos clásicos que se incluyen en componentes transaccionales. Estos sistemas gestores de datos soportan las transacciones, permitiendo confirmar (Commit) o realizar una vuelta atrás (Roll Back) a sus actividades internas. El nombre genérico que se da a los sistemas que soportan este comportamiento es el de "administrador de recursos transaccionales". Microsoft Message Queue Server es un buen ejemplo de lo que es un administrador de recursos transaccionales.

Una transacción debe cumplir cuatro propiedades, que suelen denominarse propiedades ACID (tomando la primera letra de cada propiedad):

• Atomicidad: Las transacciones deben ser indivisibles, es decir, o se ejecutan todas las acciones o no se ejecuta ninguna.

• Consistencia: Toda transacción debe llevar el sistema de un estado consistente a otro.

• Independencia: Para ser consistentes debemos imaginar que somos los únicos que estamos realizando operaciones en un momento dado; las demás transacciones deben ser invisibles para nosotros. Sirva de ejemplo el siguiente caso: un viajero pide cambiar un billete de un vuelo por otro distinto. Una transacción se ocuparía de cancelar el billete del primer vuelo, al tiempo que otra transacción intentaría añadir un pasajero nuevo en el otro vuelo. Supongamos ahora que la primera transacción falla, el viajero no podría volver a su "asiento" anterior porque ahora estaría ocupado con el nuevo viajero. Este tipo de anomalías se evitan gracias a la independencia de las transacciones.

• Durabilidad: Cuando una transacción se confirma, permanece así aunque se produzcan errores del sistema, de las comunicaciones o del propio ordenador servidor.

Page 206: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

206

Duración y resultado de una transacción Una transacción empieza cuando un cliente llama a un objeto de MTS con su atributo de transacción establecido en “Requiere una transacción” o “Requiere una nueva transacción”. Este objeto es, entonces, considerado la raíz de la transacción porque fue el primer objeto que la creó. Cuando ésta termina, MTS determina el resultado de la transacción, ya sea autorizando o abortando la transacción. En el caso de las páginas ASP, esta raíz de la transacción suele ser la propia página ASP, que es ejecutada bajo la supervisión de los componentes COM del IIS, que en realidad son componentes MTS.

Existen tres formas en las que una transacción puede terminar:

• El objeto raíz llama a SetComplete o SetAbort: Es, además, el único objeto que puede terminar una transacción de esta forma, ya que los objetos que se han creado como parte de esa misma transacción no influyen en su duración. Eso sí, pueden emitir su voto, que influirá en el resultado final de la transacción: en cuanto que alguno de los elementos que forman la transacción emitan un voto negativa, la transacción se da por no-válida.

• La transacción expira porque se agota su tiempo: El tiempo de expiración por defecto para una transacción es de 60 segundos. Si desea cambiar este valor, haga clic con el botón derecho del ratón en el icono del ordenador que aparece en el Explorador de MTS y, luego, clic en Propiedades. Establezca entonces la propiedad “Transacción TimeOut” en la pestaña Opciones.

• El cliente libera al objeto raíz.

Cuando una transacción termina, MTS debe determinar su resultado y decidir si debe autorizar o abortar la transacción. Determinar el resultado de la transacción es un proceso análogo a la toma de decisión de un grupo en el que se ha de llegar a una decisión unánime. Si un miembro del grupo disiente, habrá que negociar una decisión unánime.

Del mismo modo, cada objeto en una transacción emite su voto llamando a un método, ya sea SetComplete, SetAbort, EnableCommit o DisableCommit. MTS hace el recuento de los votos emitidos por cada objeto y determina el resultado. Si todos los objetos llamaron a SetComplete o a EnableCommit, se autorizará la transacción, pero si alguno de ellos llamó a SetAbort o a DisableCommit, se abortará la transacción.

Activación en el momento Una de las consideraciones del diseño más importantes a la hora de desarrollar componentes de MTS es el establecer de que forma se va a controlar el estado. El control del estado influye directamente en la escalabilidad de los componentes de MTS. Por otro lado, estos componentes administran el estado de forma diferente a como lo hacen los componentes COM tradicionales.

El Estado es un conjunto de datos del objeto que se guarda después de haber realizado más de una llamada al objeto. El estado puede almacenarse en una de las tres capas: en la capa del cliente, en la de los objetos de MTS o en la de la base de datos.

El estado almacenado en objetos de MTS también recibe el nombre de estado local. Las propiedades son un buen ejemplo de lo que es un estado. Un objeto puede tener propiedades que almacenen el nombre de un cliente, su dirección y número de teléfono. También puede tener métodos que utilizan los valores de dichas propiedades. Un método añade la información del cliente a la base de datos y,

Page 207: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

207

más tarde, otro método hace un ingreso en su cuenta. El objeto existe y guarda la información del cliente hasta que es liberado. Un objeto como éste, que mantiene el estado internamente después de múltiples llamadas, recibe el nombre de stateful.

Sin embargo, si el objeto no expone propiedades y, el nombre del cliente, su dirección y su número de teléfono se pasan en cada llamada al método, estaremos ante un objeto stateless. Este tipo de objetos no recuerdan las llamadas realizadas con anterioridad, no mantienen el estado.

Es muy frecuente programar en un entorno de mono-usuario pensando que un objeto estará en activo todo el tiempo que lo necesite. Las llamadas a métodos son sencillas porque el objeto recuerda la información de una llamada a otra. Sin embargo, los objetos que mantienen el estado ("stateful") influyen en la escalabilidad de una aplicación. El estado puede consumir los recursos del servidor, como memoria, espacio en el disco y conexiones de la base de datos. Y, dado que el estado está vinculado a un cliente específico, se mantendrán los recursos hasta que el cliente libere al objeto. Esta decisión ha de tenerse en cuenta junto con otros requisitos de la aplicación.

Como norma general, se debe evitar mantener el estado que consume recursos escasos o caros; almacenar las conexiones de la base de datos reduce la escalabilidad dado que existe un número limitado de conexiones a la base de datos que pueden asignarse y las conexiones que se han utilizado no pueden reunirse en el fondo común.

La Activación en el momento ayuda a reducir el consumo de los recursos del sistema, ya que recicla los objetos cuando éstos terminan su trabajo. Este tipo de activación también asegura el aislamiento de las transacciones, de forma que la información de una transacción no se llevará a la siguiente.

Cuando un cliente llama a un método de un objeto, MTS activa el objeto, creándolo y permitiendo a la llamada del método llegar hasta éste. Una vez que el objeto termina y llama a SetComplete o a SetAbort y regresa de la llamada, MTS desactiva el objeto y libera sus recursos para que éstos puedan ser utilizados por otros objetos. El objeto volverá a activarse cuando el cliente llame a otro método.

Al desactivar el objeto, MTS libera todas sus referencias, destruyendo también todo su estado local, es decir, las variables locales y las propiedades. Sin embargo, MTS controla el puntero del cliente para que siga siendo válido. Cuando el cliente llama a un método del objeto desactivado, MTS lo activa creándolo de nuevo y permitiendo a la llamada del método continuar. MTS controla el puntero del cliente para que de esta forma no sea consciente de que el objeto ha sido destruido y vuelto a crear. Sin embargo, el estado local del objeto se ha perdido y no recuerda nada de la activación anterior.

Un objeto no está desactivado cuando llama a EnableCommit o al DisableCommit o cuando rechaza hacer una llamada a cualquier otro método del objeto contextual. Tampoco estará desactivado cuando termine la transacción por haberse agotado su tiempo. El objeto sólo se desactiva cuando llama a SetComplete o a SetAbort y regresa de la llamada del cliente.

La activación en el momento tiene un efecto sustancial sobre el estado del objeto. Dado que, cuando un objeto llama a SetComplete o a SetAbort pierde su estado en cuanto el método regresa, los objetos que participan en las transacciones han de ser stateless. Es decir, no pueden mantener ningún tipo de dato de la instancia desde que quedan desactivados. No obstante, esto no quiere decir que todas las aplicaciones deben diseñarse hacia un modelo de programa que no mantenga el estado, ya que éste puede almacenarse y mantenerse fuera del objeto.

Page 208: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

208

Almacenar el estado del objeto La activación en el momento obliga a los objetos a ser stateless, es decir, que si el objeto llama a SetComplete o SetAbort, no guardará el estado local en variables dentro del objeto. Sin embargo, existe un lado práctico para el desarrollo del componente que debe examinarse.

Habrá ocasiones en las que se necesite almacenar el estado para los objetos de MTS, por ejemplo, una aplicación en la que se necesite determinar el nombre de una ciudad a partir de un código postal dado. Encontrará esta información en una base de datos, pero utilizar repetidamente una base de datos para hacer búsquedas de este tipo de dato estático puede ser ineficaz. Sería mejor almacenar esta información en un objeto para búsqueda rápida.

Existen varias posibilidades para almacenar el estado.

En una transacción es posible almacenar las propiedades de una instancia. Un objeto no tiene que llamar a SetComplete o a SetAbort cuando regresa de una llamada. Las transacciones más complicadas podrían necesitar varias llamadas desde el cliente, cada una realizando una parte del trabajo, hasta que la última llamada al método llama a SetComplete o a SetAbort. En estas circunstancias, puede mantenerse el estado como dato de una instancia en variables locales. Cuando el último método llame a SetComplete o a SetAbort, el objeto quedará, finalmente, desactivado, liberando el dato de la instancia.

Otra solución obvia es la de almacenar el estado en variables dentro de los objetos Application o Session, según el ámbito que queramos que tengan.

También se puede almacenar el estado en un archivo. Los archivos crean una protección frente a accesos concurrentes y mantienen el estado a lo largo de múltiples transacciones. Sin embargo, no proporcionan bloqueo a nivel de registro; sólo puede bloquearse el archivo completo. Por lo tanto, no son útiles para almacenar el estado que es compartido por muchos objetos, ya que un objeto puede dejar fuera al resto.

Otra forma es utilizar el Administrador de Propiedades Compartidas, SPM (Shared Property Manager).

Administrador de Propiedades Compartidas (SPM) El SPM permite almacenar propiedades y compartir los datos con todos los objetos del mismo paquete MTS. El SPM es rápido porque accede a sus propiedades en el mismo proceso (y el mismo paquete) y proporciona mecanismos de bloqueo para protegerse ante accesos concurrentes. La información almacenada en el SPM no puede ser compartida entre paquetes distintos.

Un ejemplo de aplicación del SPM podría ser el de una aplicación bancaria en la que una serie de componentes realizan las operaciones de ingreso y retirada de efectivo, transferencias, ingreso de cheques, etc, y queremos asignar a cada una de estas operaciones un identificador único por medio de un contador. Es decir, queremos una propiedad que sea compartida por todos los objetos instanciados a partir de estos componentes

La solución sería meter todos estos componentes en un mismo paquete, y crear otro componente que utilice el SPM para definir ese contador. Interesaría no perder el estado si el paquete se descarga de memoria por estar en un período de inactividad. Esto puede ser configurado en los Servicios de Componentes del Windows 2000, de forma que en las propiedades avanzadas de configuración del

Page 209: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

209

paquete dejaríamos activado el botón de radio “Dejar ejecutando cuando esté inactivo”, como se muestra en la Figura 54.

Figura 54

El estado se guarda en propiedades con nombre (objeto SharedProperty), agrupadas en grupos de propiedades también con nombre (objeto SharedPropertyGroup). Todo es gestionado por el administrador de SPM (objeto SharedPropertyGroupManager).

En resumen, el SPM trabaja con tres objetos ordenados jerárquicamente:

• SharedPropertyGroupManager: Creargrupos de propiedades comunes y permite el acceso a los ya existentes.

• SharedPropertyGroup: Crea y permite el acceso a las propiedades comunes dentro de un grupo.

• SharedProperty: Establece o devuelve el valor de una propiedad concreta.

Obtener una referencia al SPM Vamos a hacer un componente que implemente el contador comentado anteriormente.

En un nuevo proyecto ActiveX DLL, al que podemos llamar CompContador, con un módulo de clase llamado Contador, tendremos que añadir la referencia al Shared Property Manager Type Library si

Page 210: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

210

trabajamos con el MTS de Windows NT, o la referencia a los servicios COM+ si trabajamos en Windows 2000, como se muestra en la Figura 55.

Figura 55

El Código fuente 160 basta para obtener una referencia al SPM.

Set objSPM = New SharedPropertyGroupManager

Código fuente 160

El MTS, o los Servicios de Componentes en Windows 2000, se encargan de asegurar que sólo exista una instancia por servidor de este objeto. Si ya existía esta instancia, se nos asignará una referencia a la ya existente.

Crear un grupo de propiedades compartidas El Código fuente 161 es el necesario para crear un grupo de propiedades.

Set objPG = objSPM.CreatePropertyGroup("contadores", LockSetGet, Process, bExiste)

Código fuente 161

Este método recibe cuatro argumentos:

Page 211: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

211

• Nombre: Es el nombre que tendrá el grupo de propiedades

• Nivel de aislamiento: Controla de qué forma funciona el bloqueo para el grupo. Dado que la propiedades en el grupo son comunes, habrá muchos objetos que accedan y actualicen propiedades al mismo tiempo. El SPM dispone de mecanismos de bloqueo para evitar el acceso simultáneo a las propiedades comunes. En la Tabla 8 se muestra los dos tipos de valores que existen para hacer el bloqueo.

Constante Valor Descripción

LockSetGet 0 Establecido por defecto. Bloquea una propiedad durante una

llamada; de esta forma se asegura que, cada operación de lectura/escritura común sea atómica. Con esto se consigue que dos clientes no puedan leer o escribir la misma propiedad simultáneamente, pero no impide que otros clientes de accesos concurrentes lo hagan con otras propiedades en el mismo grupo.

LockMethod 1 Bloquea todas las propiedades del grupo para uso exclusivo del

llamador; este bloqueo se mantendrá mientras esté ejecutándose el método en curso. Es apropiado utilizar este modo cuando existen interdependencias entre las propiedades o, en aquellos casos en los que un cliente tenga que actualizar una propiedad inmediatamente después de haberla leído y antes de que se acceda a ella otra vez.

Tabla 8

• Tiempo de vida: controla la forma en que se borra el grupo de propiedad común. En la Tabla 9

se muestran los dos valores posibles para este caso.

Constante Valor Descripción

Standard 0 Cuando todos los objetos MTS han liberado sus referencias del

grupo de propiedad, éste se destruye automáticamente.

Process 1 El grupo de la propiedad no se destruirá hasta que el proceso en el

que ésta fue creada haya terminado. Entonces tendrá que liberar todos los objetos SharedPropertyGroup enviándolos a Nothing.

Tabla 9

• El cuarto parámetro devuelve un booleano que indica si el grupo de propiedades existía o no

previamente. Si ya existía, se devolverá una referencia al grupo existente, y entonces el segundo y tercer parámetro no tienen validez, pues el grupo tendrá los valores que le fueron dados en el momento de su creación. Puede usarse el valor devuelto por este parámetro para verificar si se está creando el grupo o recibiendo la referencia a uno existente, ejecutando el código de inicialización de las variables del grupo sólo en el primer caso.

Page 212: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

212

Crear una propiedad compartida El objeto SharedPropertyGroup presenta dos métodos y dos propiedades:

• CreateProperty: Crea una nueva propiedad común, identificada por una cadena de caracteres que es única en su grupo de propiedad.

• CreatePropertyByPosition: Crea una nueva propiedad común, identificada por un índice numérico en su grupo de propiedad.

• Property: Devuelve una referencia a la propiedad común, una vez dado el nombre de la cadena por el que se identifica a tal propiedad.

• PropertyByPosition: Devuelve una referencia a la propiedad común, una vez dado su índice numérico en el grupo de propiedad común.

El Código fuente 162 permite crear una propiedad común llamada “id”. El segundo argumento del método devuelve un valor booleano que indica si la propiedad es creada en ese mismo momento o ya existía. En el primer caso, haríamos la inicialización del bloque “if”.

Set objP = objPG.CreateProperty("id", bExiste)If bExiste = False Then objP.Value = 100

Código fuente 162

Si todo este código lo incluimos en un método que devuelva la propiedad compartida “id” y la incremente en 1, el resultado final sería el del Código fuente 163.

Option Explicit

Public Function generaId() As IntegerDim objSPM As SharedPropertyGroupManagerDim objPG As SharedPropertyGroupDim objP As SharedPropertyDim bExiste As Boolean

Set objSPM = New SharedPropertyGroupManagerSet objPG = objSPM.CreatePropertyGroup("contadores", LockSetGet, Process,

bExiste)Set objP = objPG.CreateProperty("id", bExiste)If bExiste = False Then objP.Value = 100objP.Value = objP.Value + 1generaId = objP.Value

End Function

Código fuente 163

Podemos probar este componente con una página ASP tan simple como la que se muestra en el Código fuente 164.

Si pedimos esta página, incluso desde varias instancias distintas de navegador, podremos ver cómo el contador se va incrementando.

Page 213: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

213

Set objContador = Server.CreateObject("CompContador.Contador")Response.Write objContador.generaId

Código fuente 164

Si queremos probar más a fondo el comportamiento del SPM, hagamos un nuevo proyecto ActiveX DLL llamado CompContador2, con un módulo de clase Contador2. Este módulo de clase contendrá un método exactamente igual al del componente anterior.

Hagamos otra página ASP similar a la del Código fuente 164, pero que trabaje con este nuevo componente.

Podemos probar ahora varios casos:

• Si no registramos los componentes en el MTS, los componentes se ejecutan en el mismo proceso que el de la aplicación web. Luego como comparten proceso, también comparten el mismo grupo de propiedades, y la propiedad “id” a la que acceden es la misma.

• Si registramos uno de los dos componentes en un paquete del MTS, configurado como “Aplicación de servidor”, este componente se ejecutará en un espacio de proceso distinto al de la aplicación web, y no comparte el grupo de propiedades con el otro componente. En este caso los contadores “id” son distintos

• Si registramos los dos componentes en el mismo paquete, se ejecutan en el mismo proceso y comparten la propiedad “id”.

• Si los registramos en paquetes distintos, se ejecutan en distintos procesos y no comparten la propiedad “id”.

En definitiva, lo normal sería que estos dos componentes tuvieran funcionalidad diferente, por ejemplo uno podría ejecutar operaciones de transferencias bancarias y otro de ingreso de cheques, pero que quisiéramos numerar esas operaciones distintas con un contador único. En ese caso, registraríamos estos componentes en un mismo paquete, y dispondría cada uno de ellos de un método “generaId” que accediera a la propiedad común “id”, como hemos visto.

Esta propiedad común se conserva, incluso aunque el MTS esté haciendo activación justo a tiempo de los objetos.

Servicios de Componentes y COM+ El paso siguiente a COM y MTS era lógicamente integrar estos dos modelos en uno sólo, de tal forma que se produzca una mayor compenetración entre dos capas de runtime que antes eran distintas, con todos los problemas que esto suponía.

El resultado de la conjunción de estas dos tecnologías ha resultado en el COM+. Ahora el MTS no se sirve como un añadido opcional a la funcionalidad del COM, sino como una parte constituyente del modelo conjunto: al instalar Windows 2000, estamos instalando lo que antes se llamaba MTS 2.0, y que ahora sería el MTS 3.0, pero ya integrado en el modelo COM+.

COM+ está basado en COM: sigue siendo una especificación binaria que permite que los componentes se comuniquen entre sí, y permite una programación basada en interfaces.

Page 214: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

214

Pero COM+ también está basado en MTS. Esto significa que extiende la funcionalidad básica del COM, igual que hacía el MTS, pero añade aún más funcionalidad que éste. Ahora esta funcionalidad añadida no se llama MTS, sino Servicios de Componentes.

Igual que el MTS, los Servicios de Componentes aportan las siguientes funcionalidades:

• Monitor transaccional: Los componentes pueden ser ejecutados en el seno de una transacción, sin tocar una sola línea de código, y los Servicios de Componentes se encargan de gestionarla, haciendo el commit o rollback correspondiente. El comportamiento que un objeto tendrá ante las transacciones puede ser configurado administrativamente mediante propiedades declarativas.

• Gestor de componentes (ORB, Object Request Broker): Gestiona la vida del componente y guarda información de su contexto. Cada objeto está asociado con un único contexto durante su vida, como si se tratara de su sombra. Múltiples objetos pueden estar asociados a un mismo contexto.

• Gestor de seguridad: Algunas características de seguridad no necesitan que sea añadida ni una sola línea de código y son configuradas administrativamente.

Pero además, los Servicios de Componentes aportan algunas novedades:

• Componentes encolados: Combina COM con MSMQ. Permite invocar y ejecutar componentes de forma asíncrona, estando el cliente o el servidor desconectados El cliente pide un método de un componente encolado al Queued Components Recorder, que mete la petición en una cola. El Queued Components Listener coge el mensaje y se lo pasa al Queued Components Player, para que sea ejecutado finalmente el método sobre el componente.

• Fondo común de objetos (Object Pooling): Mantiene instancias de componentes en un fondo común o pool, que pueden ser usadas por cualquier cliente. Igual que el pool de conexiones a una BD. Actualmente sólo puede usarse con componentes C++.

• Component Load Balancing (CLB): Puedo tener un mismo componente COM+ servido por varios servidores de aplicación. Se utilizará uno u otro servidor en función de su carga de trabajo. No disponible todavía en Windows 2000.

Muchos de los conceptos de MTS siguen teniendo aplicación al hablar de los Servicios de Componentes. A veces sólo cambia el nombre. Por ejemplo, el MTS ahora se llama Servicios de Componentes. Es accesible desde la opción “Herramientas administrativas” del menú “Programas”. Lo que antes se llamaba “paquete” ahora recibe el nombre de “aplicación COM+”.

Al igual que los paquetes del MTS, las aplicaciones COM+ pueden ser configuradas como:

• Aplicación de biblioteca: Los objetos instanciados a partir de componentes registrados en esa aplicación se ejecutarán en el mismo espacio de proceso que el cliente que instació dicho objeto.

• Aplicación de servidor: Los objetos instanciados a partir de componentes registrados en esa aplicación se ejecutarán en un proceso de servidor dedicado. Este proceso que contiene la ejecución de esta aplicación era MTX.EXE en el MTS, y ahora pasa a ser DLLHOST.EXE, como puede verse en la Figura 56.

Page 215: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

215

Figura 56

La intercepción en COM+ Ya hemos visto que para que el MTS fuera capaz de añadir su funcionalidad a los componentes COM, es necesario que se “interponga” entre el cliente y el objeto, de forma que pueda controlar el ciclo de vida y la ejecución de éste.

Para conseguir esto, la capa runtime del MTS, el MTXEX.DLL, se valía de dos objetos. El objeto Context Wrapper es el que se interpone en el momento del intento de instanciación de un componente MTS por parte de un cliente: éste recibe una referencia a este objeto Context Wrapper, siendo así “engañado”, mientras que el MTS se encarga de gestionar la creación del objeto real.

Un segundo objeto, el objeto de contexto, se encarga de guardar información relativa al contexto de ejecución del objeto, actuando como su “sombra”.

El hecho de que el MTS no estuviera plenamente integrado en el modelo COM suponía un problema importante, una de cuyas consecuencias principales era la necesidad del uso del método CreateInstance del objeto de contexto.

Si un componente MTS instanciaba otro componente MTS, y se empleaba el método de Visual Basic CreateObject en vez de CreateInstance, ocurría lo siguiente: el runtime de Visual Basic pasaba la petición de creación del objeto al runtime del COM, que a su vez se la pasaba al MTS. Pero el runtime del COM no era capaz de pasar la información del contexto del objeto creador al del objeto creado. Como consecuencia, el MTS creaba un nuevo contexto para el nuevo objeto, pero que no era reflejo del contexto del objeto creador, luego no podía correr en la misma transacción.

Page 216: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

216

La capa runtime del COM+ se basa en la idea del contexto. Todos los objetos se ejecutan dentro de un contexto. Varios objetos pueden estar en un mismo contexto. La intercepción de la capa runtime del COM+ sólo se produce cuando la llamada se hace desde un contexto hasta otro distinto. Para esta intercepción no utiliza objetos Context Wrapper, sino objetos proxy especializados en hacer este cambio de contexto.

En el momento de crear un objeto, la capa runtime del COM+ debe decidir si el nuevo objeto necesita un nuevo contexto o puede utilizar el contexto de su creador. Para tomar esta decisión, COM+ se basa en la información almacenada en el objeto de contexto.

En la mayoría de las ocasiones, los objetos instanciados a partir de componentes no-configurados se crean en el contexto de su creador, y los instanciados a partir de componentes configurados se crean en un nuevo contexto. Se entiende por componente configurado aquél que está registrado dentro de una aplicación COM+, lo que significa que se le han configurado una serie de propiedades declarativas. Los objetos de ADO sin embargo son instancias de componente no-configurado.

Ya no es necesario el uso del método CreateInstance, aunque sigue pudiendo utilizarse para garantizar la compatibilidad con código ya escrito. Las rutinas de COM+ saben perfectamente cómo deben pasar información del contexto en el momento de la creación de objetos. Esto significa que el método CreateObject, que utiliza dichas rutinas COM+, tendrá el mismo efecto, y el objeto recién creado podrá, por ejemplo, ejecutarse en la misma transacción que el creador.

El operador New de Visual Basic todavía puede ser problemático si los componentes correspondientes al objeto creado y al creador están incluidos en la misma DLL. En este caso las rutinas de Visual Basic saben cómo crear el nuevo objeto y no utilizan las rutinas de COM+. Si están en DLLs distintas, el operador New equivale al método CreateObject y funcionará sin problemas.

La referencia a un objeto es siempre relativa al contexto. Si un objeto 1 dentro un contexto 1 obtiene mediante CreateObject una referencia a un objeto 2 dentro de otro contexto 2, en realidad lo que tiene es la referencia a un proxy capaz de hacer el cambio del contexto 1 al contexto 2. Si el objeto 1 invoca un método de un tercer objeto 3 dentro de un contexto 3, y le pasa como parámetro del método esta referencia al objeto 2, se creará automáticamente un nuevo proxy capaz de hacer el cambio del contexto 3 al contexto 2, y será la referencia a este proxy la que utilice el objeto 3.

Por lo tanto, pasar una referencia a un objeto como parámetro de un método no supone ningún problema, porque los proxys necesarios se crean automáticamente. Sin embargo, no sería correcto guardar la referencia que tenía el objeto 1 al objeto 2, que es un proxy especializado en cambiar del contexto 1 al 2, como una variable dentro de un módulo BAS de Visual Basic, ni como una propiedad compartida del SPM, porque esa referencia sólo sería utilizable por el objeto 1, pero no por el objeto 3, que necesitaría un proxy capaz de cambiar del contexto 3 al 2.

Otro problema que se ha eliminado con COM+ es el del registro de Windows. La clave InProcServer32 de un componente COM contiene la ruta de la DLL donde se encuentra el componente. Sin embargo, en el momento de registrar el componente dentro de un paquete MTS, el valor de esta clave cambiaba por C:\WINNT\SYSTEM32\MTXEX.DLL, es decir, la ruta del MTS Executive. Esto era necesario para que el MTS pudiera hacer la intercepción en el momento de la creación del componente, ya que las rutinas COM no eran capaces de hacerlo por sí mismas.

El problema venía en el momento de recompilar el componente desde el Visual Basic: después de la compilación, éste llama automáticamente a REGSVR32.EXE, y el componente volvía a ser registrado según la manera de COM, y el valor de la clave InProcServer32 volvía a ser el de la ruta de la DLL, con lo que el componente ya no funcionaba correctamente porque el MTS no podía hacer la intercepción.

Page 217: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 11. Servicios de componentes

217

Para mitigar este problema, el MTS contaba con la posibilidad de Actualizar los componentes de un paquete, que consistía en que el MTS inspeccionaba en el registro de Windows las claves de los componentes de dicho paquete, y corregía automáticamente sus valores.

Todas estas dificultades se han eliminado con COM+. La clave InProcServer32 siempre contiene la ruta de la DLL, sea el componente congifurado o no-configurado. La diferencia estriba en que los componentes configurados tienen información adicional en el registro. No es necesario refrescar los componentes después de cada recompilación en Visual Basic.

Page 218: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 219: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Diseño de componentes COM+

En este tema vamos a ver de qué forma los Servicios de Componentes de COM+ (antes MTS) pueden afectar al diseño de los componentes.

Comprobaremos cómo se produce la interceptación de la que hemos hablado anteriormente, siendo estos Servicios de Componentes los encargados de gestionar la creación y destrucción de los objetos que estén registrados en el catálogo de COM+.

Veremos cómo por el simple hecho de registrar un componente en una aplicación COM+ y configurar una serie de propiedades declarativas, podemos extender su funcionalidad sin necesidad de tocar una sola línea de código.

El interfaz ObjectControl Hemos dicho que cuando un componente es registrado en el catálogo de COM+, los Servicios de Componentes se encargan de gestionar su creación y destrucción. Si queremos conocer cuándo es creado y destruido realmente el componente, podemos hacerlo implementado dentro del mismo el interfaz ObjectControl.

Este interfaz tiene tres métodos:

• Activate: es invocado cuando el componente es activado o re-activado (en el caso de los componentes C++, que pueden ser desactivados, almacenados en el pool, y re-activados). Si hago que mi componente implemente el interfaz ObjectControl, este método será invocado automáticamente por las rutinas de COM+ antes que cualquier otro método. Sería lógico usar este método para incluir código de inicialización que sea global para todos los métodos del

Page 220: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

220

objeto. Si se trata por ejemplo de un objeto que accede a una base de datos a través de ADO, en este método podríamos crear la conexión. También es normal obtener aquí la referencia al objeto del contexto, para poder usarla luego en los métodos del componente.

• Deactivate: es invocado cuando el componente es desactivado. Igual que con el método anterior, aquí pondría código de finalización del objeto, como cierre de una conexión a través de ADO.

• CanBePooled: este método devuelve un valor booleano que indica si las rutinas COM+ pueden meter este objeto en un pool, una vez desactivado. Actualmente esta opción sólo estaría disponible para componentes escritos en C++. Para componentes escritos en Visual Basic este método devolverá siempre False.

Vamos a construir ahora un componente en Visual Basic para comprobar lo que acabamos de ver.

Abrimos un nuevo proyecto ActiveX DLL, al que llamaremos CompActivar, con un módulo de clase al que llamaremos Activar. El componente hará uso del objeto Response de ASP, para escribir directamente con Write. Implementará el interfaz ObjectControl, y además tendrá un método adicional.

Añadimos al proyecto las referencias a las librerías de COM+ y del modelo de objetos de ASP. El Código fuente 165 muestra cómo quedarían estos métodos.

Option ExplicitImplements ObjectControl

Private Sub ObjectControl_Activate()Dim objContext As ObjectContextDim objResponse As ResponseSet objContext = GetObjectContextSet objResponse = objContext("Response")objResponse.Write "activado a las " & Time & "<br>"

End Sub

Private Sub ObjectControl_Deactivate()Dim objContext As ObjectContextDim objResponse As ResponseSet objContext = GetObjectContextSet objResponse = objContext("Response")objResponse.Write "desactivado a las " & Time & "<br>"

End Sub

Private Function ObjectControl_CanBePooled() As BooleanObjectControl_CanBePooled = False

End Function

Public Sub escribe()Dim objContext As ObjectContextDim objResponse As ResponseSet objContext = GetObjectContextSet objResponse = objContext("Response")objResponse.Write "dentro del método a las " & Time & "<br>"

End Sub

Código fuente 165

Page 221: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

221

El hecho de añadir la línea Implements ObjectControl nos obliga a implementar los tres métodos del interfaz; si no lo hacemos así, no podremos compilar. Esta línea es necesaria para que los Servicios de Componentes puedan invocar automáticamente a los métodos del interfaz.

En los métodos ObjectControl_Activate, ObjectControl_Deactivate, y en el método “escribe”, obtenemos una referencia al objeto de contexto, y a través de él una referencia al objeto Response, para poder escribir directamente un corto mensaje y la hora del sistema.

Ahora escribimos una página ASP con el Código fuente 166.

<%@ Language=VBScript %><%Response.Buffer = false%><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Set objCom = Server.CreateObject("CompActivar.Activar")inicio = TimeResponse.Write inicio & "<br>"while Time<>DateAdd("s",5,inicio)wendResponse.Write Time & "<br>"objCom.escribe & "<br>"%>

</BODY></HTML>

Código fuente 166

Deshabilitamos el buffer en la segunda línea, para poder ir recibiendo gradualmente en el navegador el resultado de la ejecución de la página. Instanciamos el componente, obtenemos la hora del sistema y la escribimos con Write. El bucle While…Wend consiste en un temporizador muy rudimentario, que ralentizará la ejecución de la página durante cinco segundos. Obtenemos nuevamente la hora del sistema, la escribimos, e invocamos al método “escribe” del componente.

Si ejecutamos la página, obtendremos:

9:38:04 9:38:09 dentro del método a las 9:38:09

Es decir, no han sido invocados los métodos Activate ni Deactivate. Esto es así porque todavía el componente no está registrado en el catálogo de COM+, y los Servicios de Componentes no se han encargado de interceptar la creación y destrucción del objeto. Vamos pues a registrarlo.

Dentro de Programas | Herramientas administrativas, seleccionamos la opción Servicios de Componentes. Esto abrirá la consola de administración de estos servicios, como se muestra en la Figura 57. Vayamos extendiendo el árbol de la consola del panel izquierdo hasta llegar a la carpeta de Aplicaciones COM+.

Page 222: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

222

Figura 57

En el panel derecho veremos las aplicaciones COM+ actualmente instaladas en el equipo. Para crear una nueva, pulsamos con el botón derecho sobre la carpeta Aplicaciones COM+ del panel izquierdo, y seleccionamos Nuevo | Aplicación. En ese momento se inicia el asistente (ver Figura 58) para instalación de aplicaciones COM+.

Figura 58

En la siguiente ventana (ver Figura 59) pulsaremos sobre el botón de Crear una aplicación vacía. A esta aplicación añadiremos luego nuestro componente recién creado.

Page 223: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

223

Figura 59

En el siguiente paso (ver Figura 60) se nos pide el nombre de la nueva aplicación, y además se nos permite configurar en qué espacio de memoria queremos que se ejecuten los componentes de la aplicación. Tenemos dos opciones, según seleccionemos un tipo u otro de aplicación:

• Aplicación de biblioteca: las instancias de los componentes de la aplicación se ejecutan en el mismo espacio de memoria que el cliente que las crea. Esta opción puede ser recomendable en tiempo de desarrollo de los componentes.

• Aplicación de servidor: las instancias de los componentes se ejecutan en un proceso separado del de la aplicación cliente que los utiliza. Esta opción es la que debe utilizarse en tiempo de producción.

Figura 60

En la siguiente ventana (Figura 61) podemos elegir bajo que cuenta se ejecutarán los componentes. Si seleccionamos la opción marcada por defecto, entonces cuando instanciemos el componente desde una página ASP, y si está activado el acceso anónimo para la aplicación web a la que pertenece dicha página, la cuenta utilizada será la de invitado a internet (IUSR_nombreMáquina).

Page 224: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

224

Figura 61

En la siguiente ventana basta con pulsar el botón de Finalizar, y ya está nuestra aplicación creada. Ahora tenemos que añadir el componente. Para ello la expandimos en el árbol del panel izquierdo correspondiente a la aplicación COM+ recién creada hasta llegar a la carpeta Componentes, como muestra la Figura 62.

Figura 62

Page 225: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

225

La carpeta de Componentes no tiene ningún elemento, puesto que hemos creado una aplicación vacía. Vamos a añadirlo pulsando con el botón derecho sobre la carpeta Componentes del panel izquierdo, y seleccionando Nuevo | Componente. Con esto arranca el asistente para la instalación de componentes COM.

En la pantalla que se muestra en la Figura 63, debemos pulsar la opción Importar componentes ya registrados, puesto que al compilar el proyecto de Visual Basic, ya se ha encargado de registrarlo por nosotros en la máquina.

Figura 63

Después de un momento, el que tarda en buscar en el registro de Windows los componentes registrados en la máquina, nos aparece la lista de la Figura 64, de la que debemos seleccionar nuestro componente.

Figura 64

Con esto el componente queda registrado, como se ve en la Figura 65. Más adelante veremos las propiedades declarativas que podemos configurar, pero de momento nos basta con las que tiene por defecto.

Page 226: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

226

Figura 65

Antes de volver a ejecutar la página ASP, vamos a descargarla, para descargar con ello la dll del componente. Recordemos que esto podíamos hacerlo desde la consola de administración del IIS, pulsando con el botón derecho sobre el nombre de la aplicación web y seleccionando la opción Propiedades, y luego la pestaña Directorio. Si ahora pulsamos el botón Descargar, conseguiremos nuestro objetivo. Al ejecutar otra vez la página, el resultado que obtendremos será:

10:50:50

10:50:55

activado a las 10:50:55

dentro del método a las 10:50:55

desactivado a las 10:50:55

Como podemos ver, ahora los Servicios de Componentes han interceptado la creación del componente. Con la instrucción Server.CreateObject("CompActivar.Activar"), no se produce la instanciación inmediata del componente, sino que esta se produce al invocar el primer método, es decir, en la instrucción Response.Write objCom.escribe.

Por cierto, que si abrimos de nuevo la consola de administración de los Servicios de Componente y expandimos el árbol de la izquierda hasta la carpeta Aplicaciones COM+, veremos en el panel de la derecha que el icono correspondiente a la aplicación ASPComp muestra la bolita girando dentro de la caja. Esto significa que la DLL está cargada en memoria. Una de las ventajas de registrar el componente en una aplicación COM+ es que podemos controlar la descarga de las DLLs. Basta con

Page 227: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

227

pulsar con el botón derecho sobre el icono de la aplicación y seleccionar la opción Cerrar sistema. La DLL se descarga, y la bolita ahora deja de girar.

Si no cerramos nosotros la aplicación explícitamente, se cierra ella sola según la opción elegida en la pestaña Activación de las propiedades de la aplicación COM+, como se muestra en la Figura 66. Por defecto aparece marcada la opción “Minutos de inactividad antes de cerrar”, con un valor de tres. Esto significa que si transcurren más de tres minutos sin que se reciba una petición de algún método del componente incluido en dicha dll, la aplicación se descargará.

Figura 66

También podemos forzar nosotros mismos el comienzo de la aplicación si pulsamos con el botón derecho sobre el icono de la aplicación y seleccionamos la opción Iniciar. De esta forma la primera petición de la página ASP, que hace uso del componente de esta aplicación, no se ralentizará por el proceso de carga de la dll en memoria, sino que se encontrará con que ésta ya estaba cargada.

Activación Just-In-Time (JIT) Esta intercepción que realiza los Servicios de Componentes, podemos deshabilitarla. Para ello, descarguemos previamente la aplicación COM+, como hemos visto, y pasemos a ver las propiedades declarativas del componente, pulsando con el botón derecho sobre su icono dentro del administrador de los Servicios de Componentes, y seleccionando la opción Propiedades.

En la pestaña Transacciones (ver Figura 67), comprobemos que la opción seleccionada por defecto es la de “No se admite”. De esta forma el componente nunca tendrá voto en una transacción, pero dispone de un objeto de contexto (luego puede acceder al objeto Response de ASP).

Page 228: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

228

Figura 67

Vayamos ahora a la pestaña Activación para deseleccionar la casilla “Habilitar activación puntual”, es decir, deshabilitamos la activación Just-In-Time del componente. Esto se muestra en la Figura 68.

Figura 68

Page 229: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

229

Y si ahora ejecutamos de nuevo la página ASP, el resultado obtenido será:

12:02:13

12:02:18

dentro del método a las 12:02:18

que es el mismo que se obtenía cuando el objeto no estaba registrado en una aplicación COM+. Hemos impedido que los Servicios de Componentes intercepten la creación del objeto, luego no se invocan los métodos Activate y Deactivate.

Permitir que los Servicios de Componentes gestionen la activación del componente supone una mejora en la escalabilidad de la aplicación, pues los recursos del servidor son administrados de forma más eficiente. El cliente no tiene que preocuparse de en qué momento se activa el componente, sino que lo hacen por él los Servicios de Componentes, activándolo en el momento preciso (activación Just-In-Time).

Inicialización del componente Utilicemos lo visto en los apartados anteriores para hacer un componente que obtenga la referencia al objeto de contexto en la inicialización, dentro del método Activate, para que esté disponible en el resto de métodos a través de una variable miembro. Escribiremos un método listaApplication que genere una tabla HTML con las variables de ámbito de aplicación, y otro listaSession que haga lo mismo con las variables de ámbito de sesión.

Creamos un nuevo proyecto ActiveX DLL con el nombre de CompApliSes, con un módulo de clase llamado ApliSes. Añadimos al proyecto las referencias a las librerías de COM+ y del modelo de objetos de ASP.

El código de este módulo será el del Código fuente 167.

Option ExplicitImplements ObjectControlPrivate mvarobjContext As ObjectContextPrivate mvarobjResponse As Response

Private Sub ObjectControl_Activate()Set mvarobjContext = GetObjectContextSet mvarobjResponse = mvarobjContext("Response")mvarobjResponse.Write "activado a las " & Time & "<br>"

End Sub

Private Sub ObjectControl_Deactivate()mvarobjResponse.Write "desactivado a las " & Time & "<br>"

End Sub

Private Function ObjectControl_CanBePooled() As BooleanObjectControl_CanBePooled = False

End Function

Public Sub listaApplication()Dim strHTML As StringDim objApplication As Application

Page 230: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

230

Dim variable As Variant

Set objApplication = mvarobjContext("Application")strHTML = "<table border=1><tr><th>Variable</th><th>Valor</th></tr>"For Each variable In objApplication.Contents

strHTML = strHTML & "<tr><td>" & variable & "</td><td>" & _objApplication.Contents(variable) & "</td></tr>"

NextstrHTML = strHTML & "</table>"

mvarobjResponse.Write strHTMLEnd Sub

Public Sub listaSession()Dim strHTML As StringDim objSession As SessionDim variable As Variant

Set objSession = mvarobjContext("Session")strHTML = "<table border=1><tr><th>Variable</th><th>Valor</th></tr>"For Each variable In objSession.Contents

strHTML = strHTML & "<tr><td>" & variable & "</td><td>" & _objSession.Contents(variable) & "</td></tr>"

NextstrHTML = strHTML & "</table>"

mvarobjResponse.Write strHTMLEnd Sub

Código fuente 167

Como puede verse, en el método Activate del interfaz ObjectControl obtenemos la referencia al objeto de contexto, y a partir de él la referencia al objeto Response. Como los dos objetos van a ser utilizados por los métodos listaApplication y listaSession, nos interesa guardarlos como variables miembro.

En estos dos métodos tomamos la referencia al objeto de ASP correspondiente, Application o Session, generamos el código HTML necesario para la tabla, recorriendo la colección con un bucle For…each, y escribimos directamente sobre el objeto Response.

Registremos el componente dentro de la aplicación COM+, ASPComp, y probémoslo desde una página ASP con un código similar al del Código fuente 168.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Application("var1")="valor1"Application("var2")="valor2"Application("var3")="valor3"

Session("var1")="valor1"Session("var2")="valor2"

Set objCom = Server.CreateObject("CompApliSes.ApliSes")

Response.Write "<h3>Variables de Application</h3>"objCom.listaApplication

Page 231: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

231

Response.Write "<h3>Variables de Session</h3>"objCom.listaSession%>

</BODY></HTML>

Código fuente 168

Tendremos el resultado que se muestra a continuación:

VARIABLES DE APPLICATION

activado a las 13:14:47

Variable Valor

var1 valor1

var2 valor2

var3 valor3

VARIABLES DE SESSION

Variable Valor

var1 valor1

var2 valor2

desactivado a las 13:14:47

Podemos ver que el método Activate ha sido invocado automáticamente, y sólo en el momento de llamar al primer método, no en el CreateObject. Por eso el mensaje que genera este método aparece entre el título, escrito desde la página ASP, y la primera tabla, generada por el componente en el método listaApplication. El método Deactivate es invocado al finalizar la ejecución de la página, y salir de ámbito la variable de referencia objCom. Más adelante veremos que un objeto puede ser desactivado y reactivado entre las llamadas a sus métodos, en vez de activado en la primera llamada y desactivado después de la última.

Page 232: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

232

Estado de un componente El paradigma de Programación Orientada a Objetos nos dice que los objetos se caracterizan por su identidad, estado y comportamiento. Pues bien, veremos que si queremos diseñar componentes que aprovechen al máximo los Servicios de Componentes, debemos programar componentes sin estado.

Vamos a diseñar un componente que permita hacer un alta en una tabla. Esta tabla la crearemos en SQL Server, aunque podría valer otro gestor de base de datos, incluso Access. Añadiremos además un procedimiento almacenado para realizar el alta.

La secuencia SQL necesaria para crear la tabla y el procedimiento se muestra en el Código fuente 169.

CREATE TABLE Clientes(id smallint PRIMARY KEY,nombre varchar(25),saldo money

)

CREATE PROCEDURE alta@id smallint,@nombre varchar(25),@saldo money

ASINSERT INTO Clientes VALUES(@id,@nombre,@saldo)

Código fuente 169

Diseñaremos el interfaz del componente de forma que disponga de una propiedad “cadenaConex”, que contendrá la cadena de conexión, y un método “alta”, que será el que acceda mediante ADO a la base de datos, empleando para ello el procedimiento almacenado recién creado.

En el Código fuente 170 está el código necesario para este componente.

Private mvarcadenaConex As StringPrivate objCnx As ADODB.ConnectionPrivate objCmd As ADODB.CommandPrivate objRst As ADODB.RecordsetPrivate objContext As ObjectContext

Public Sub alta(ByVal id As Integer, ByVal nombre As String, ByVal saldo AsCurrency)

Dim objPar1, objPar2, objPar3 As ADODB.ParameterSet objContext = GetObjectContextSet objCnx = New ADODB.ConnectionobjCnx.Open mvarcadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "alta"Set objPar1=objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id)Set objPar2=objCmd.CreateParameter("par2", adVarChar, adParamInput, 25, nombre)Set objPar3=objCmd.CreateParameter("par3", adCurrency, adParamInput, 8, saldo)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Parameters.Append objPar3objCmd.Execute , , adCmdStoredProc

Page 233: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

233

objContext.SetCompleteobjCnx.CloseSet objCmd = NothingSet objCnx = Nothing

End Sub

Public Property Let cadenaConex(ByVal vData As String)mvarcadenaConex = vData

End Property

Public Property Get cadenaConex() As StringcadenaConex = mvarcadenaConex

End Property

Código fuente 170

Comentemos algunas cosas de este código.

Como puede verse, una propiedad está implementada en Visual Basic mediante una variable miembro, en este caso mvarcadenaConex, a la que puede accederse para modificar su valor mediante un método Property Let, o para obtener su valor mediante Property Get. En realidad una propiedad equivale pues a dos métodos, y modificar el valor de la propiedad o leerla supone invocar un método.

En el código obtenemos también la referencia al objeto de contexto, y cuando el método “alta” ha finalizado su ejecución, invocamos el método SetComplete. Esto puede parecer extraño, puesto que este método suele asociarse siempre con transacciones sobre bases de datos, al igual que el método SetAbort. Pero realmente este método nos permite aumentar la escalabilidad, porque equivale a informar a los Servicios de Componentes de que el objeto ha terminado su labor y puede ser desactivado. No es necesario que el componente sea transaccional para poder emplear cualquiera de estos dos métodos.

Vamos a crear ahora una página ASP con la que probar este componente. El Código fuente 171 podría ser un ejemplo.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><%Set objCom = Server.CreateObject("CompAlta.Alta")objCom.cadenaConex = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=ASPComp;DataSource=varrondo"Response.Write "La cadena de conexión es: " & objCom.cadenaConex & "<br>"objCom.alta 1,"pepe",1000Response.Write "La cadena de conexión es: " & objCom.cadenaConex & "<br>"On Error Resume NextobjCom.alta 2,"pepa",2000if Err<>0 then Response.Write Err.descriptionOn Error Goto 0Set objCom = Nothing%></BODY></HTML>

Código fuente 171

Page 234: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

234

Si la ejecutamos, veremos que funciona correctamente como podríamos esperar. Instanciamos el componente y le asignamos valor a la propiedad cadenaConex. Esto equivale a invocar un método, el Property Let. Luego obtenemos su valor y lo escribimos. Esto es una llamada al método Property Get.

Luego invocamos al método “alta”, y seguidamente volvemos a escribir la propiedad cadenaConex. Activamos el gestor de errores de VBScript e invocamos una segunda vez al método “alta”, con un nuevo valor de clave primaria.

Este componente parece correcto, desde el punto de vista de la Programación Orientada a Objetos. Tiene una propiedad de estado, la cadena de conexión, que es utilizada en uno de sus métodos, “alta”.

Sin embargo, vamos a ver lo que ocurre cuando registramos el componente en la aplicación COM+ que venimos utilizando. Previamente hemos de quitar la DLL de memoria, mediante la descarga de la aplicación web a través de la consola de administración del IIS.

Eliminemos también los registros de la tabla, para evitar infringir la restricción de clave primaria. Si ahora volvemos a ejecutar la página ASP, la primera alta se ejecuta correctamente, pero luego vemos que la propiedad cadenaConex aparece vacía, y la segunda alta falla al no serle suministrado al método Open del objeto Connection una cadena de conexión correcta.

¿Qué es lo que ha ocurrido? Los Servicios de Componentes han interceptado la creación del objeto, y están ahorrando recursos. Después de la llamada al primer método, el SetComplete comunica que el objeto ha terminado su labor y puede ser desactivado, y eso es exactamente lo que ocurre, con lo cual se pierde el estado.

Si llamáramos diez veces al método “alta”, estaríamos activando y desactivando el objeto diez veces, perdiendo entre las llamadas la información de estado del mismo. Esto puede parecer que tendrá poco rendimiento, pero no es así, y se ahorran recursos que estarían sin utilizar entre las llamadas.

Aunque la página ASP crea el objeto y no lo destruye hasta el final, realmente lo que obtiene no es la referencia al objeto real, sino al context wrapper, mientras el objeto real es creado y destruido bajo la gestión de los Servicios de Componentes.

Una forma de conseguir que el componente funcionara correctamente sería volver a asignar valor a la propiedad cadenaConex antes de llamar por segunda vez al método “alta”.

Otra manera sería modificando una de las propiedades declarativas del componente. Si de entre sus propiedades elegimos la pestaña Activación y desactivamos la casilla “Habilitar activación puntual”, conseguimos que los Servicios de Componentes no gestionen la activación Just-In-Time de este componente, que ahora se comportará como un objeto COM tradicional, cuyo tiempo de vida coincidirá con el tiempo durante el que la página ASP guarda una referencia a él. Para que estos cambios en la propiedad declarativa del componente tengan efecto, debemos descargar previamente de memoria la aplicación COM+.

Pero de este modo perdemos las ventajas de escalabilidad mediante el ahorro de recursos que nos proporcionan los Servicios de Componentes.

Más eficaz sería hacer que la cadena de conexión fuera suministrada como parámetro al método, junto con los otros tres. O permitir que el componente acceda al modelo de objetos de ASP mediante el objeto de contexto, para leer la cadena de conexión directamente de una variable de aplicación.

También podríamos usar el método Activate del interfaz ObjectControl, para asignar en ese momento el valor a la cadena de conexión, leída desde el objeto Application. Hagámoslo así, como en el Código fuente 172.

Page 235: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

235

Option ExplicitImplements ObjectControlPrivate mvarcadenaConex As StringPrivate objContext As ObjectContext

Public Sub alta(ByVal id As Integer, ByVal nombre As String, ByVal saldo AsCurrency)

Dim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objRst As ADODB.RecordsetDim objPar1, objPar2, objPar3 As ADODB.ParameterSet objContext = GetObjectContextSet objCnx = New ADODB.ConnectionobjCnx.Open mvarcadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "alta"Set objPar1=objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id)Set objPar2=objCmd.CreateParameter("par2", adVarChar, adParamInput, 25, nombre)Set objPar3=objCmd.CreateParameter("par3", adCurrency, adParamInput, 8, saldo)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Parameters.Append objPar3objCmd.Execute , , adCmdStoredProcobjContext.SetCompleteobjCnx.CloseSet objCmd = NothingSet objCnx = Nothing

End Sub

Private Sub ObjectControl_Activate()Dim objResponse As ResponseDim objApplication As ApplicationSet objContext = GetObjectContextSet objApplication = objContext("Application")mvarcadenaConex = objApplication("CadenaConex")Set objResponse = objContext("Response")objResponse.Write "activado a las " & Time & "<br>"

End Sub

Private Sub ObjectControl_Deactivate()Dim objResponse As ResponseSet objContext = GetObjectContextSet objResponse = objContext("Response")objResponse.Write "desactivado a las " & Time & "<br>"

End Sub

Private Function ObjectControl_CanBePooled() As BooleanObjectControl_CanBePooled = False

End Function

Código fuente 172

Si ahora ejecutamos la página con el Código fuente 173, funcionará correctamente, y podremos comprobar en la ventana del navegador que el componente ha sido activado y desactivado dos veces.

Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;InitialCatalog=ASPComp;Data Source=varrondo"Set objCom = Server.CreateObject("CompAlta.Alta")objCom.alta 1,"pepe",1000objCom.alta 2,"pepa",2000

Page 236: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

236

Set objCom = Nothing

Código fuente 173

Hagamos ahora otro componente, que extienda la funcionalidad del anterior, permitiendo un mantenimiento sencillo de la tabla recién creada, por medio de tres métodos: uno para hacer altas, otro bajas y otro consulta. Para hacer que el componente sea lo más reutilizable posible, haremos que la cadena de conexión se suministre por medio de una variable de aplicación, como acabamos de ver, y que el acceso a la base de datos sea a través de procedimientos almacenados. Tendremos que añadir los dos nuevos que aparecen en el Código fuente 174.

CREATE PROCEDURE baja@id smallint

ASDELETE FROM Clientes WHERE id=@id

CREATE PROCEDURE consultaASSELECT * FROM Clientes

Código fuente 174

El componente quedará como en el Código fuente 175.

Private objContext As ObjectContextPrivate objApplication As ApplicationPrivate mvarcadenaConex As StringPrivate objCnx As ADODB.ConnectionPrivate objCmd As ADODB.CommandPrivate objRst As ADODB.Recordset

Public Function consulta() As Variant()Set objContext = GetObjectContextSet objApplication = objContext("Application")mvarcadenaConex = objApplication.Contents("CadenaConex")Set objCnx = New ADODB.ConnectionobjCnx.Open mvarcadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "consulta"Set objRst = objCmd.Execute(, , adCmdStoredProc)consulta = objRst.GetRowsobjCnx.CloseSet objCmd = NothingSet objCnx = Nothing

End Function

Public Sub baja(ByVal id As Integer)Dim objPar1 As ADODB.ParameterSet objContext = GetObjectContextSet objApplication = objContext("Application")mvarcadenaConex = objApplication.Contents("CadenaConex")Set objCnx = New ADODB.ConnectionobjCnx.Open mvarcadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnx

Page 237: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

237

objCmd.CommandText = "baja"Set objPar1 = objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id)objCmd.Parameters.Append objPar1objCmd.Execute , , adCmdStoredProcobjCnx.CloseSet objCmd = NothingSet objCnx = Nothing

End Sub

Public Sub alta(ByVal id As Integer, ByVal nombre As String, ByVal saldo AsCurrency)

Dim objPar1, objPar2, objPar3 As ADODB.ParameterSet objContext = GetObjectContextSet objApplication = objContext("Application")mvarcadenaConex = objApplication.Contents("CadenaConex")Set objCnx = New ADODB.ConnectionobjCnx.Open mvarcadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "alta"Set objPar1 = objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id)Set objPar2 = objCmd.CreateParameter("par2", adVarChar, adParamInput, 25,

nombre)Set objPar3 = objCmd.CreateParameter("par3", adCurrency, adParamInput, 8,

saldo)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Parameters.Append objPar3objCmd.Execute , , adCmdStoredProcobjCnx.CloseSet objCmd = NothingSet objCnx = Nothing

End Sub

Código fuente 175

Y la página ASP necesaria para probar su funcionamiento está en el Código fuente 176.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Set objCom = Server.CreateObject("CompMantenimiento.Mantenimiento")Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;InitialCatalog=ASPComp;Data Source=varrondo"%>

<%Select Case Request.Form("boton")%><%Case "alta"%><form method="POST"><input name="id"><br><input name="nombre"><br><input name="saldo"><br><input type="submit" name="boton" value="confirmar alta"></form>

<%Case "confirmar alta"%><%objCom.alta Request.Form("id"),Request.Form("nombre"),Request.Form("saldo")

Page 238: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

238

menu%>

<%Case "baja"%><form method="POST"><input name="id"><br><input type="submit" name="boton" value="confirmar baja"></form>

<%Case "confirmar baja"%><%objCom.baja Request.Form("id")menu%>

<%Case "consulta"%><%contenido = objCom.consultaResponse.Write "<table border=1>"for i=0 to UBound(contenido,2)

Response.Write "<tr>"for j=0 to UBound(contenido,1)

Response.Write "<td>" & contenido(j,i) & "</td>"nextResponse.Write "</tr>"

nextResponse.Write "</table>"menu%>

<%Case Else%><%menu%>

<%End Select%>

<%Set objCom = Nothing%>

<%Sub menu%><form method="POST"><input type="submit" name="boton" value="alta"><input type="submit" name="boton" value="baja"><input type="submit" name="boton" value="consulta"></form>

<%End Sub%>

</BODY></HTML>

Código fuente 176

Cadena del constructor Otra forma de aumentar la posibilidad de reutilizar nuestros componentes es pasarle una cadena en el momento de la construcción de un objeto a partir del componente. El contenido de esta cadena es asignado por medio de propiedades declarativas.

Esto tiene una aplicación evidente en el caso de que el componente acceda a una base de datos. Si la cadena de conexión, necesaria para conectarse a la fuente de datos, se le suministra por medio de un parámetro en el instante de la construcción, podemos administrativamente modificar el contenido de esta cadena para que el mismo componente nos sirva para el acceso a distintas fuentes de datos.

Page 239: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 12. Diseño de componentes COM+

239

Además si le pasamos la cadena de conexión de esta forma, en vez de recuperarla del objeto Application, podemos reutilizar el componente desde clientes que no sean páginas ASP, puesto que ya no hacemos uso de un modelo de objetos específico.

Retomemos el ejemplo del componente de altas, que habíamos llamado CompAlta. Eliminemos del proyecto la referencia a la librería con el modelo de objetos de ASP, que ya no vamos a utilizar. Eliminemos también, por claridad, los métodos del interfaz ObjectControl.

Si sustituimos: Implements ObjectControl por Implements IobjectConstruct, tendremos disponible el combo izquierdo el interfaz, y al seleccionarlo se generará automáticamente el código inicial de su único método, Construct.

En este método sólo tenemos que tomar el parámetro pCtorObj, que es un objeto cuya propiedad ConstructString contiene precisamente la cadena del constructor, cuyo valor definimos mediante una propiedad declarativa. A continuación asignamos a la variable miembro mvarcadenaConex este valor. Todo esto puede verse en el Código fuente 177.

Option ExplicitImplements IObjectConstructPrivate mvarcadenaConex As String

Public Sub alta(ByVal id As Integer, ByVal nombre As String, ByVal saldo AsCurrency)

Dim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objRst As ADODB.RecordsetDim objPar1, objPar2, objPar3 As ADODB.ParameterSet objCnx = New ADODB.ConnectionobjCnx.Open mvarcadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "alta"Set objPar1=objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id)Set objPar2=objCmd.CreateParameter("par2", adVarChar, adParamInput, 25, nombre)Set objPar3=objCmd.CreateParameter("par3", adCurrency, adParamInput, 8, saldo)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Parameters.Append objPar3objCmd.Execute , , adCmdStoredProcobjCnx.CloseSet objCmd = NothingSet objCnx = Nothing

End Sub

Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object)mvarcadenaConex = pCtorObj.ConstructString

End Sub

Código fuente 177

Si ahora vamos a la consola de administración de los Servicios de Componentes, y dentro de las Propiedades del componente CompAlta seleccionamos la pestaña Activación, podemos marcar la casilla “Habilitar construcción de objetos” y dar valor a esta propiedad declarativa, como se ve en la Figura 69.

Si ejecutamos ahora una página ASP con un código tan sencillo como el del Código fuente 178, todo funcionará correctamente. Ya se adivina lo fácil que es hacer que este componente trabaje contra otra

Page 240: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

240

base de datos, incluso de otro fabricante, con tal de que disponga de un procedimiento almacenado llamado “alta” que necesite los mismos tres parámetros, y configuremos administrativamente su nueva cadena de conexión, sin necesidad de modificar en absoluto el código del componente, ni por supuesto de recompilarlo.

Figura 69

Set objCom = Server.CreateObject("CompAlta.Alta")objCom.alta 1,"pepe",1000objCom.alta 2,"pepa",2000Set objCom = Nothing

Código fuente 178

Page 241: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Componentes transaccionales

Introducción En este tema vamos a ver componentes transaccionales, es decir, aquellos cuyas operaciones sobre una base de datos deben ser englobadas dentro de una transacción. El caso más típico lo constituye la transferencia de dinero de una cuenta a otra.

Utilizaremos la tabla de Clientes, ya conocida de temas anteriores, a la que añadiremos una segunda tabla LogTransferencias y dos procedimientos almacenados. Para lograr una mayor claridad, reduciremos el código lo más posible.

El Código fuente 179 muestra las secuencias SQL para generar la tabla y los procedimientos almacenados nuevos.

CREATE TABLE LogTransferencias(fecha datetime NOT NULL,idEmi smallint NOT NULL,cantidad money NOT NULL,idRec smallint NOT NULL,PRIMARY KEY NONCLUSTERED(fecha,idEmi,cantidad,idRec)

)

CREATE PROCEDURE movimiento@id smallint,@cantidad money

ASUPDATE Clientes SET saldo = saldo + @cantidad WHERE id=@id

Page 242: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

242

CREATE PROCEDURE registro@fecha datetime,@idEmi smallint,@cantidad money,@idRec smallint

ASINSERT INTO LogTransferencias VALUES(@fecha,@idEmi,@cantidad,@idRec)

Código fuente 179

En vez de usar un único procedimiento almacenado para hacer la transferencia, invocaremos al procedimiento almacenado “movimiento” una vez para cada cuenta, la de origen y la de destino. Esto nos permitirá entender mejor los problemas transaccionales en ASP con componentes.

Antes de nada veremos unos conceptos previos, relativos a componentes transaccionales.

El contexto y las transacciones

Pautas para el desarrollo de componentes transaccionales • Conseguir una referencia del objeto de contexto. La información de contexto para un objeto

está almacenada en este tipo de objeto, que es capaz de vigilar el trabajo realizado por aquél, así como su información de seguridad. Los objetos obtienen una referencia de su objeto de contexto, llamando a la función GetObjectContext, función que proporcionan los Servicios de Componentes. Los objetos COM+ utilizan el objeto de contexto para informar de si han terminado o no su trabajo con éxito, así como para obtener información de la transacción o de seguridad.

• Llamar a SetComplete si la transacción tiene éxito. Cuando un objeto termina su trabajo en una transacción con éxito, debe llamar al método SetComplete del objeto de contexto. Esto indicará a los Servicios de Componentes que el trabajo realizado por el objeto puede ser confirmado cuando todos los objetos implicados en la transacción terminen su trabajo. El método SetComplete también indica a los Servicios de Componentes que cualquier recurso retenido por el objeto, incluido el propio objeto, puede ser reciclado.

• Llamar a SetAbort si la transacción falla. Cuando un objeto no termina con éxito su trabajo en una transacción, ha de llamar al método SetAbort del objeto de contexto. Esto indicará a los Servicios de Componentes que todos los cambios hechos por este objeto y los realizados por otros objetos en la misma transacción quedarán anulados. Este método también indicará a los Servicios de Componentes que cualquier recurso, incluido el propio objeto, puede ser reciclado.

• Administrar el estado cuidadosamente. El estado representa los datos del objeto que se mantienen después de haber realizado más de una llamada al método del objeto. Las variables locales o globales permiten mantener el estado del objeto, pero no debe almacenar los estados de esta forma si se participa en una transacción. Los Servicios de Componentes reciclan el objeto, cuando la transacción termina, para liberar, de esta manera, recursos o hará que se pierda cualquier tipo de información en las variables locales y globales.

La Propiedad MTSTransactionMode de Visual Basic, como se ve en la Figura 70, permite establecer el atributo de transacción para una clase. Cuando se compile el proyecto, Visual Basic guardará esta

Page 243: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 13. Componentes transaccionales

243

propiedad en la biblioteca de tipos del componente. Luego, si el componente se añade a una aplicación COM+, los Servicios de Componentes leerán el valor de la propiedad MTSTransactionMode y automáticamente establecerá el atributo de la transacción en ese valor, tarea que simplifica enormemente la administración de componentes escritos en Visual Basic.

Figura 70

Casos prácticos

La página contiene todo el código transaccional En el presente capítulo veremos una serie de casos, con distintas opciones de diseño de la aplicación para conseguir la misma funcionalidad final: efectuar una transferencia entre dos cuentas y guardar un registro de la misma en una tabla de log. Veremos cómo afecta cada diseño al comportamiento transaccional de la aplicación. Veremos una página ASP con todo el código, parte del código en componentes, todo el código en componentes, distintas configuraciones de dichos componentes, etc.

De este modo, viendo una serie de casos prácticos, se pretende que quede claro cómo se encargan los Servicios de Componentes de gestionar las transacciones cuando están involucradas páginas ASP y componentes registrados en aplicaciones COM+.

Veamos un primer ejemplo en el que todo el código de acceso a la base de datos se encuentra en el script de la página ASP, como se muestra en el Código fuente 180. En la rama if de esta página crearemos un formulario que permita efectuar una transferencia de dinero de una cuenta a otra. El formulario se submitirá a la propia página, que será tratado en la rama else.

<%@ transaction=required %><!--#INCLUDE file="ADOVBS.INC"--><html><head><title>Transferencia</title>

Page 244: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

244

</head><body>

<%Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;InitialCatalog=ASPComp;Data Source=varrondo"%>

<%if Request.Form("boton")="" then%>

<form method="POST"><input name="idEmi"><br><input name="cantidad"><br><input name="idRec"><br><input type="submit" name="boton" value="transferir"></form>

<%else

idEmi=Request.Form("idEmi")cantidad=Request.Form("cantidad")idRec=Request.Form("idRec")

Set objCnx=Server.CreateObject("ADODB.Connection")objCnx.Open Application("CadenaConex")Set objCmd=Server.CreateObject("ADODB.Command")objCmd.ActiveConnection=objCnxobjCmd.CommandText="movimiento"Set objPar1=objCmd.CreateParameter("par1",adSmallInt,adParamInput,2,idEmi)Set objPar2=objCmd.CreateParameter("par2",adCurrency,adParamInput,8,-

cantidad)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Execute numReg,,adCmdStoredProcif numReg=0 then

Response.Write "<b>No existe el idEmi</b>"ObjectContext.SetAbortobjCnx.CloseResponse.End

end if

objCmd.Parameters("par1")=idRecobjCmd.Parameters("par2")=cantidadobjCmd.Execute numReg,,adCmdStoredProcif numReg=0 then

Response.Write "<b>No existe el idRec</b>"ObjectContext.SetAbortobjCnx.CloseResponse.End

end if

objCmd.CommandText="registro"objCmd.Parameters.Delete "par1"objCmd.Parameters.Delete "par2"Set objPar1=objCmd.CreateParameter("par1",adDate,adParamInput,8,date)Set objPar2=objCmd.CreateParameter("par2",adSmallInt,adParamInput,2,idEmi)Set objPar3=objCmd.CreateParameter("par3",adCurrency,adParamInput,8,cantidad)Set objPar4=objCmd.CreateParameter("par4",adSmallInt,adParamInput,2,idRec)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Parameters.Append objPar3objCmd.Parameters.Append objPar4objCmd.Execute numReg,,adCmdStoredProc

objCnx.CloseSet objCmd=NothingSet objCnx=Nothing

end if%>

Page 245: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 13. Componentes transaccionales

245

<%Sub OnTransactionCommit

if Request.Form("boton")<>"" thenResponse.Write "<h2>Transacción completada</h2>"

end ifEnd Sub

Sub OnTransactionAbortResponse.Write "<h2>Transacción abortada</h2>"

End Sub%>

</body></html>

Código fuente 180

En la rama else creamos una única conexión sobre la que instanciamos un objeto Command, que reutilizaremos modificando o eliminando los parámetros de su colección Parameters, invocando sucesivamente a los procedimientos almacenados “movimiento”, una vez para la cuenta emisora y otra vez para la receptora, y “registro”, para escribir en la tabla de log de transferencias.

La variable numReg que nos devuelve el método Execute será la que nos permita comprobar si el cliente existía o no existía. Si su valor es igual cero, no hay ningún registro afectado, luego el cliente no existía. Si su valor es igual a uno, sí existía el registro.

Por simplificar el código, ésta será la única comprobación que hagamos. No verificaremos por ejemplo que el saldo del cliente después de la operación permanezca mayor que cero.

La directiva <%@ transaction=required %> indica a COM+ que la página debe ejecutarse en el contexto de una transacción. Si no existe una, como es el caso, es creada automáticamente. Podemos comprobar que si se produce un error porque alguno de los clientes no existe, o generamos nosotros alguno intencionadamente con la línea Err.Raise vbObjectError + numError, o hacemos explícitamente ObjectContext.SetAbort en la página, la transacción hace rollback automáticamente.

Recordemos que los eventos OnTransactionCommit y OnTransactionAbort se disparan automáticamente cuando la transacción ha tenido éxito o ha fracasado, respectivamente.

Acabemos diciendo que si la ejecución de la página llega a su fin y no se ha producido ninguna instrucción SetAbort, se considera implícitamente que el voto de la página en la transacción es de SetComplete.

Parte del código transaccional en un componente Hemos visto cómo con la sencilla directiva <%@ transaction=required %> podemos hacer que todo el código contenido en una página ASP sea englobado dentro de una misma transacción. Pero este curso trata de componentes, así que vamos a diseñar un componente con el código que accede a la tabla Clientes.

Creamos un nuevo proyecto ActiveX DLL, al que llamaremos CompTransferencia, con un módulo de clase llamado Transferencia. Dispondrá de un único método, llamado “mover”, que accederá a la base de datos a través del procedimiento almacenado “movimiento”. Este método será invocado tanto para

Page 246: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

246

retirar el dinero del cliente origen como para ingresarlo en el de destino. Caso de no existir el cliente solicitado, generará un error, que se encargará de recoger la página ASP.

Accederá a la cadena de conexión a través de la variable CadenaConex de ámbito de aplicación.

El código definitivo puede verse en el Código fuente 181.

Debemos añadir al proyecto las referencias a las librerías de los servicios de COM+, del modelo de objetos de ASP, y de ADO.

Option Explicit

Public Sub mover(ByVal id As Integer, ByVal cantidad As Currency)Dim objContext As ObjectContextDim objApplication As ApplicationDim cadenaConex As StringDim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objPar1, objPar2 As ADODB.ParameterDim numReg As Integer

Set objContext = GetObjectContextSet objApplication = objContext("Application")cadenaConex = objApplication.Contents("CadenaConex")Set objCnx = New ADODB.ConnectionobjCnx.Open cadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "movimiento"Set objPar1 = objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id)Set objPar2 = objCmd.CreateParameter("par2", adCurrency, adParamInput, 8,

cantidad)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Execute numReg, , adCmdStoredProcobjCnx.CloseSet objCmd = NothingSet objCnx = NothingIf numReg = 0 Then Err.Raise vbObjectError + 1000, "mover", "No existe el

cliente"End Sub

Código fuente 181

Compilemos el componente. La página ASP necesaria para utilizar este componente sólo necesita instanciarlo e invocar sus métodos, como se ve en el Código fuente 182. El código necesario para escribir en la tabla de log lo mantenemos todavía en la página ASP.

<%@ transaction=required %><!--#INCLUDE file="ADOVBS.INC"--><html><head><title>Transferencia</title></head><body><%Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;InitialCatalog=ASPComp;Data Source=varrondo"%><%if Request.Form("boton")="" then%>

Page 247: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 13. Componentes transaccionales

247

<form method="POST" id=form1 name=form1><input name="idEmi"><br><input name="cantidad"><br><input name="idRec"><br><input type="submit" name="boton" value="transferir"></form>

<%else

idEmi=Request.Form("idEmi")cantidad=Request.Form("cantidad")idRec=Request.Form("idRec")

Set objCom=Server.CreateObject("CompTransferencia.Transferencia")On Error Resume NextobjCom.mover idEmi,-cantidadif Err<>0 then

Response.Write "<b>Error en el idEmi: </b>" & Err.descriptionObjectContext.SetAbortResponse.End

end ifobjCom.mover idRec,cantidadif Err<>0 then

Response.Write "<b>Error en el idRec: </b>" & Err.descriptionObjectContext.SetAbortResponse.End

end ifOn Error Goto 0

Set objCnx=Server.CreateObject("ADODB.Connection")objCnx.Open Application("CadenaConex")Set objCmd=Server.CreateObject("ADODB.Command")objCmd.ActiveConnection=objCnxobjCmd.CommandText="registro"Set objPar1=objCmd.CreateParameter("par1",adDate,adParamInput,8,date)Set objPar2=objCmd.CreateParameter("par2",adSmallInt,adParamInput,2,idEmi)Set objPar3=objCmd.CreateParameter("par3",adCurrency,adParamInput,8,cantidad)Set objPar4=objCmd.CreateParameter("par4",adSmallInt,adParamInput,2,idRec)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Parameters.Append objPar3objCmd.Parameters.Append objPar4objCmd.Execute numReg,,adCmdStoredProc

objCnx.CloseSet objCmd=NothingSet objCnx=Nothing

end if%>

<%Sub OnTransactionCommit

if Request.Form("boton")<>"" thenResponse.Write "<h2>Transacción completada</h2>"

end ifEnd Sub

Sub OnTransactionAbortResponse.Write "<h2>Transacción abortada</h2>"

End Sub%></body></html>

Código fuente 182

Page 248: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

248

Si probamos ahora la página, veremos que funciona correctamente. Si ponemos por ejemplo un cliente de destino que no exista, aparece el mensaje de error correspondiente, y la transacción hace rollback automático, no habiéndose restado la cantidad del saldo del cliente de origen. Esto es así porque el código de la propia página es el encargado de decidir el rollback; el componente se limita a efectuar la operación con la base de datos y generar el error en caso necesario.

Pero si ahora registramos el componente en la aplicación COM+, veamos qué sucede. Dejemos el componente con la propiedad declarativa por defecto para las transacciones, es decir, “No se admite”. Esto es configurable en la pestaña Transacciones de las Propiedades del componente, como aparece en la Figura 71.

Figura 71

Si ejecutamos de nuevo la página y ponemos un cliente de destino que no exista, o se produce cualquier otro error en la página, no se hace rollback de las operaciones efectuadas por el componente. Esto es así porque la configuración “No se admite” para las transacciones significa que el componente no participa en la transacción de la página, y no tiene voto en la misma.

Sin embargo, las operaciones efectuadas por la página sí hacen rollback en caso de error, y no llega a escribirse la línea en la tabla LogTransferencias. Lo podemos comprobar haciendo ObjectContext.SetAbort explícitamente, a continuación de la línea del Execute que escribe en esa tabla. En este caso se hace rollback de la escritura en la tabla LogTransferencia, pero las actualizaciones en la tabla Clientes se mantienen.

La opción “Deshabilitada” para las transacciones del componente tiene el mismo efecto. Sin embargo, si configuramos el componente para que su comportamiento transaccional sea de “Compatible”, esto significa que el componente participa de la transacción del cliente, en este caso la página ASP, con lo cual todo el código ASP y el del componente forman una única transacción, que

Page 249: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 13. Componentes transaccionales

249

fallará o tendrá éxito en su conjunto. El componente también tiene voto en esa transacción, aunque no estamos utilizando ahora mismo esta posibilidad (lo haremos más adelante).

Si la página no hubiera arrancado la transacción, es decir, no incluye la directiva <%@transaction=required %>, entonces no habría ninguna transacción en curso y no se crearía una nueva para el componente. Podemos comprobar que en ese caso no se hace rollback ni de las operaciones efectuadas por el componente, ni de las efectuadas por el código de la página, en caso de hacerse SetAbort.

Al no estar la página definida como transaccional, no tiene acceso al ObjectContext y la instrucción ObjectContext.SetAbort genera un error. Dentro del bloque if de recepción del error del componente está activado el gestor de errores de VBScript con On Error Resume Next, y lo pasa por alto, pero no podría hacer este SetAbort por ejemplo al final de la página.

Si configuramos ahora la propiedad transaccional del componente como “Necesario”, y al no haber arrancado una transacción la página, se creará una transacción particular para el componente. Sin embargo, al no hacer el SetAbort desde dentro del componente, tampoco se hace rollback de las actualizaciones del componente ni de la página.

La opción “Necesita nuevo” produce en este caso el mismo efecto.

Pero si volvemos a declarar la página como transaccional, y el componente como “Necesita nuevo”, entonces se iniciará una transacción nueva para el componente, independiente de la transacción en la cual se está ejecutando la página. En este caso, el SetAbort efectuado por la página sólo tiene efecto en la transacción propia, y no hace rollback de los cambios en la base de datos que hubiera provocado el componente.

Voto transaccional de un componente En el caso de declarar la página como transaccional, y el componente como “Compatible” o “Necesario”, hemos visto que todo funciona correctamente.

Pero lo normal es aprovechar más las ventajas que nos proporcionan los Servicios de Componentes, y hacer que nuestro componente emita su voto respecto al SetCommit o SetAbort de la transacción. Esto puede hacerlo gracias al objeto de contexto, que guarda información sobre la transacción dentro de la cual se está ejecutando el componente. Ésta puede ser la suya propia, o la que ya había iniciado la página. Veremos esto con detalle.

Rediseñemos el componente de forma que ahora pueda emitir su voto transaccional. Dejaremos que siga generando un error en el caso de no existir el cliente, pero ya no será la página la que haga SetAbort al captar ese error, sino que lo hará el propio componente. Por supuesto, primero hará el SetAbort y luego generará el error, en ese orden. El Código fuente 183 será ahora el del componente.

Option Explicit

Public Sub mover(ByVal id As Integer, ByVal cantidad As Currency)Dim objContext As ObjectContextDim objApplication As ApplicationDim cadenaConex As StringDim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objPar1, objPar2 As ADODB.ParameterDim numReg As Integer

Page 250: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

250

Set objContext = GetObjectContextSet objApplication = objContext("Application")cadenaConex = objApplication.Contents("CadenaConex")Set objCnx = New ADODB.ConnectionobjCnx.Open cadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "movimiento"Set objPar1 = objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id)Set objPar2 = objCmd.CreateParameter("par2", adCurrency, adParamInput, 8,

cantidad)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Execute numReg, , adCmdStoredProcobjCnx.CloseSet objCmd = NothingSet objCnx = NothingIf numReg = 0 Then

objContext.SetAbortErr.Raise vbObjectError + 1000, "mover", "No existe el cliente"

ElseobjContext.SetComplete

End IfEnd Sub

Código fuente 183

En el Código fuente 184 puede verse el fragmento del código de la página ASP en que se invocan los métodos del componente.

Set objCom=Server.CreateObject("CompTransferencia.Transferencia")On Error Resume NextobjCom.mover idEmi,-cantidadif Err<>0 then

Response.Write "<b>Error en el idEmi: </b>" & Err.descriptionResponse.End

end ifobjCom.mover idRec,cantidadif Err<>0 then

Response.Write "<b>Error en el idRec: </b>" & Err.descriptionResponse.End

end ifOn Error Goto 0

Código fuente 184

Marquemos la página como transaccional, y el componente con la opción “Deshabilitada” o “No se admite”. En este caso si introducimos en el formulario un cliente de destino inexistente, el componente emite un voto de SetAbort, pero no tiene ninguna validez puesto que no participa de la transacción de la página. La transacción se da por buena y los cambios en la base de datos son definitivos. Además se disparará el evento OnTransactionCommit.

Si hago SetAbort desde la página, el registro insertado en la tabla de LogTransferencias hace rollback, pero no las modificaciones en la tabla Clientes, que permanecen.

Si ahora declaro el comportamiento transaccional del componente como “Compatible” o “Necesario”, entrará a formar parte de la transacción iniciada por la página, con lo que el código de la página y del

Page 251: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 13. Componentes transaccionales

251

componente forman una única transacción. El voto del componente afecta a toda la transacción conjunta, igual que el de la página, y si alguno de ellos hace SetAbort, se hace rollback de todas las modificaciones, tanto en la tabla LogTransferencias como en la tabla Clientes. Este es el comportamiento que normalmente nos va a interesar.

Si hacemos el cambio en el código de la página, de forma que desactivemos el gestor de errores de VBScript antes de la segunda llamada al método mover, y eliminamos las líneas del Response.End, como se ve en el Código fuente 185, veremos que si introducimos un id de cliente de origen inexistente, en la primera llamada a “mover” se hace SetAbort de la transacción, y en la segunda obtenemos el error “Realizó una llamada a un método en un componente COM+ que tiene una transacción que se ha anulado o que está en curso de anulación”. Esto se debe a que el SetAbort de la primera llamada hace que en el objeto de contexto asociado al componente se marca la transacción como anulada, y los Servicios de Componentes pueden así liberar los recursos asociados a este objeto, que es inservible mientras dura la transacción, que ya está anulada.

Set objCom=Server.CreateObject("CompTransferencia.Transferencia")On Error Resume NextobjCom.mover idEmi,-cantidadif Err<>0 then

Response.Write "<b>Error en el idEmi: </b>" & Err.descriptionend ifOn Error Goto 0objCom.mover idRec,cantidadif Err<>0 then

Response.Write "<b>Error en el idRec: </b>" & Err.descriptionend if

Código fuente 185

Sólo nos queda por probar declarar el componente como “Necesita nuevo”. Con esta configuración, se inicia una transacción para el componente, pero es independiente de la transacción iniciada para la página.

Si introducimos en el formulario un id de cliente inexistente, se hace rollback de la transacción del componente, no de la de la página. Hay un detalle más: la transacción iniciada para la página abarca todo el tiempo de ejecución de la página, pero para el componente se inicia una cada vez que se invoca al método “mover”. Por lo tanto, la operación de retirar el dinero de un cliente y la operación de ingresarlo en otro cliente no se consideran una única transacción, sino transacciones distintas, y no se hará rollback de las dos sino de aquélla que haya fallado.

Dos componentes transaccionales invocados desde ASP Hagamos ahora que el código que inserta el registro en la tabla LogTransferencias esté también dentro de un componente. Llamaremos al proyecto ActiveX DLL CompLog, y al módulo de clase Log, con un código como el del Código fuente 186.

Option Explicit

Public Sub registrar(ByVal fecha As Date, ByVal idEmi As Integer, ByVal cantidad AsCurrency, ByVal idRec As Integer)

On Error GoTo Errores

Page 252: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

252

Dim objContext As ObjectContextDim objApplication As ApplicationDim cadenaConex As StringDim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objPar1, objPar2, objPar3, objPar4 As ADODB.Parameter

Set objContext = GetObjectContextSet objApplication = objContext("Application")cadenaConex = objApplication.Contents("CadenaConex")Set objCnx = New ADODB.ConnectionobjCnx.Open cadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "registro"Set objPar1=objCmd.CreateParameter("par1", adDate, adParamInput, 8, fecha)Set objPar2=objCmd.CreateParameter("par2", adSmallInt, adParamInput, 2, idEmi)Set objPar3=objCmd.CreateParameter("par3",adCurrency,adParamInput,8,cantidad)Set objPar4=objCmd.CreateParameter("par4", adSmallInt, adParamInput, 2, idRec)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Parameters.Append objPar3objCmd.Parameters.Append objPar4objCmd.Execute , , adCmdStoredProcobjCnx.CloseSet objCmd = NothingSet objCnx = Nothing

Exit Sub

Errores:objContext.SetAbortErr.Raise vbObjectError + 1000, "registrar", "Falló el registro en el log"

End Sub

Código fuente 186

El código necesario en la página ASP, como se ve en el Código fuente 187, queda mucho más reducido. Es el entramado que aglutina la funcionalidad de los componentes, invocando ordenadamente sus métodos.

<%@ transaction=required %><!--#INCLUDE file="ADOVBS.INC"--><html><head><title>Transferencia</title></head><body><%Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;InitialCatalog=ASPComp;Data Source=varrondo"%>

<%if Request.Form("boton")="" then%>

<form method="POST" id=form1 name=form1><input name="idEmi"><br><input name="cantidad"><br><input name="idRec"><br><input type="submit" name="boton" value="transferir"></form>

<%else

Page 253: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 13. Componentes transaccionales

253

idEmi=Request.Form("idEmi")cantidad=Request.Form("cantidad")idRec=Request.Form("idRec")

Set objCom1=Server.CreateObject("CompTransferencia.Transferencia")On Error Resume NextobjCom1.mover idEmi,-cantidadif Err<>0 then

Response.Write "<b>Error en el idEmi: </b>" & Err.descriptionResponse.End

end ifobjCom1.mover idRec,cantidadif Err<>0 then

Response.Write "<b>Error en el idRec: </b>" & Err.descriptionResponse.End

end ifOn Error Goto 0

Set objCom2=Server.CreateObject("CompLog.Log")On Error Resume NextobjCom2.registrar date,idEmi,cantidad,idRecif Err<>0 then

Response.Write "<b>Error en el log: </b>" & Err.descriptionResponse.End

end ifOn Error Goto 0

end if%>

<%Sub OnTransactionCommit

if Request.Form("boton")<>"" thenResponse.Write "<h2>Transacción completada</h2>"

end ifEnd Sub

Sub OnTransactionAbortResponse.Write "<h2>Transacción abortada</h2>"

End Sub%></body></html>

Código fuente 187

Lo normal en este caso sería declarar la página como transaccional y declarar los componentes como “Compatible” o “Necesario” respecto a su comportamiento transaccional. Hagamos las pruebas pertinentes, y veremos que todo funciona correctamente.

Un componente transaccional invoca a otro Cambiemos ahora el interfaz del componente CompTransferencia, de forma que el método “mover” reciba los id del cliente de origen y de destino de la transferencia. De esta forma sólo hay que invocar al método una vez.

Además, este mismo componente será el encargado de instanciar al componente CompLog e invocar su método “registrar”.

En definitiva, el método del componente CompTransferencia queda como en el Código fuente 188.

Page 254: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

254

Option Explicit

Public Sub mover(ByVal idEmi As Integer, ByVal cantidad As Currency, ByVal idRec AsInteger)

Dim objContext As ObjectContextDim objApplication As ApplicationDim cadenaConex As StringDim objCnx As ADODB.ConnectionDim objCmd As ADODB.CommandDim objPar1, objPar2 As ADODB.ParameterDim numReg As IntegerDim objCom As CompLog.Log

Set objContext = GetObjectContextSet objApplication = objContext("Application")cadenaConex = objApplication.Contents("CadenaConex")Set objCnx = New ADODB.ConnectionobjCnx.Open cadenaConexSet objCmd = New ADODB.CommandobjCmd.ActiveConnection = objCnxobjCmd.CommandText = "movimiento"Set objPar1=objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, idEmi)Set objPar2=objCmd.CreateParameter("par2",adCurrency,adParamInput,8,-cantidad)objCmd.Parameters.Append objPar1objCmd.Parameters.Append objPar2objCmd.Execute numReg, , adCmdStoredProcIf numReg = 0 Then

objContext.SetAbortErr.Raise vbObjectError + 1000, "mover", "No existe el cliente de origen"

End If

objCmd.Parameters("par1") = idRecobjCmd.Parameters("par2") = cantidadobjCmd.Execute numReg, , adCmdStoredProcIf numReg = 0 Then

objContext.SetAbortErr.Raise vbObjectError + 1000, "mover", "No existe el cliente de destino"

End If

objCnx.CloseSet objCmd = NothingSet objCnx = Nothing

Set objCom = New CompLog.LogobjCom.registrar Date, idEmi, cantidad, idRec

objContext.SetComplete

End Sub

Código fuente 188

Y el código de la página ASP queda ahora todavía más reducido, como se muestra en el Código fuente 189.

<%@ transaction=required %><!--#INCLUDE file="ADOVBS.INC"--><html><head><title>Transferencia</title></head>

Page 255: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 13. Componentes transaccionales

255

<body><%Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;InitialCatalog=ASPComp;Data Source=varrondo"%>

<%if Request.Form("boton")="" then%>

<form method="POST" id=form1 name=form1><input name="idEmi"><br><input name="cantidad"><br><input name="idRec"><br><input type="submit" name="boton" value="transferir"></form>

<%else

idEmi=Request.Form("idEmi")cantidad=Request.Form("cantidad")idRec=Request.Form("idRec")

Set objCom1=Server.CreateObject("CompTransferencia.Transferencia")On Error Resume NextobjCom1.mover idEmi,cantidad,idRecif Err<>0 then

Response.Write "<b>Se produjo un error: </b>" & Err.description'Response.End

end ifOn Error Goto 0

end if%>

<%Sub OnTransactionCommit

if Request.Form("boton")<>"" thenResponse.Write "<h2>Transacción completada</h2>"

end ifEnd Sub

Sub OnTransactionAbortResponse.Write "<h2>Transacción abortada</h2>"

End Sub%></body></html>

Código fuente 189

Page 256: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 257: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Acceso a MSMQ desde ASP

Servicios de mensajería entre aplicaciones Los sistemas distribuidos han ido evolucionando. Al principio sólo había una máquina potente, el host, que era compartido por muchos ordenadores clientes. Al aumentar la potencia de cálculo y abaratarse el coste, los clientes empezaron a compartir el peso de la aplicación, y empezó a poderse hablar de aplicación distribuida, desapareciendo la figura del host. Pero empezó la preocupación por la comunicación entre esos ordenadores que comparten la lógica de la aplicación.

Los modelos de componentes como DCOM o CORBA permiten la comunicación entre distintos componentes de una aplicación, o entre distintas aplicaciones, ejecutándose en máquinas diferentes, pero esto lo hacen a través de mensajes síncronos, es decir, que una aplicación envía un mensaje a otra, y queda en espera hasta que no recibe una respuesta.

Esta suposición de que la aplicación de destino va a estar disponible para devolver una respuesta inmediata no siempre es cierta, sobre todo en un entorno como el de una aplicación web.

En situaciones así tienen su aplicación los sistemas de mensajería, como el MSMQ de Microsoft. Estos sistemas de mensajería entre aplicaciones usan mensajes asíncronos. Un cliente envía un mensaje a un servidor, pero en vez de esperar una respuesta inmediata, prosigue con su trabajo. El mensaje queda almacenado en una cola, de tal forma que cuando el servidor esté disponible para procesarlo, lo hará, y le enviará una respuesta al cliente.

Las aplicaciones que se comunican pueden estar en plataformas distintas, sistemas operativos distintos, incluso pueden no estar conectados permanentemente. Internet es un ejemplo de conexión no permanente entre plataformas y sistemas operativos distintos.

Page 258: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

258

Suele compararse un servicio de mensajería con un servicio de email. La diferencia principal es que un servicio de email intercambia información entre personas y un servicio de mensajería lo hace entre aplicaciones.

Los servicios de mensajería entre aplicaciones trabajan con mensajes y colas.

Un mensaje es un trozo de información intercambiado entre dos aplicaciones. El formato y contenido de este mensaje es específico de la aplicación (puede ser texto o binario), pero para el sistema de mensajería esto es indiferente. No exige un formato específico para estos mensajes. De hecho, ni siquiera inspecciona su contenido, limitándose a transmitirlo.

Sin embargo otras tecnologías, como HTTP, FTP, ODBC, etc, también permiten la comunicación entre plataformas distintas, pero son para tipos particulares de aplicaciones, y se exige un formato específico para los mensajes.

Las colas son los lugares donde se depositan estos mensajes.

MSMQ (Message Queuing Server) MSMQ no es algo nuevo. Existen otras tecnologías de mensajería para PCs. Este servicio está integrado en Windows NT Server en su versión Enterprise, y algo más reducido en la versión normal, bajo el nombre de MSMQ 1.0. También está incluido en Windows 2000, donde es un servicio más que recibe el nombre de Message Queuing Server. La parte cliente se encuentra en todas las versiones de Windows.

El MSMQ proporciona la tecnología necesaria para el envío de mensajes entre aplicaciones, y la gestión de colas.

Para acceder a estos servicios, podemos hacerlo a través de un API. Además ofrece un modelo COM para poder ser usado desde cualquier lenguaje que soporte esta tecnología. Podremos utilizarlo por tanto desde una página ASP.

Ya hemos dicho que los servicios de mensajería entre aplicaciones, como el MSMQ, son muy parecidos a los servicios de correo, pero presentan diferencias:

• Los servidores de correo transmiten mensajes entre personas, y el MSMQ los transmite entre aplicaciones.

• Garantizan mayor seguridad de que el mensaje ha llegado a su destino. En un servicio de correo no podemos estar seguros de que el mensaje enviado haya llegado correctamente. Con el MSMQ es posible saber exactamente cuándo ha llegado.

El MSMQ es más lento que otros métodos de comunicación de más bajo nivel, como sockets o canalizaciones con nombre, named pipes. De hecho, MSMQ usa internamente estos métodos, aunque de forma completamente transparente para mí. Sin embargo esta lentitud está compensada por las ventajas que ofrece.

Si quiero obtener más rendimiento, los mensajes se pueden almacenar en RAM. Esto supone mayor velocidad en la gestión de los mensajes, pero ante un fallo del servidor podría perderlos. Si quiero más fiabilidad ante posibles fallos, los mensajes se pueden almacenar en el disco duro y ser recuperados cuando el servidor se recupere del fallo.

Page 259: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

259

Habrá una serie de situaciones en las que interese utilizar el MSMQ para transmitir mensajes entre máquinas que comparten la lógica de una aplicación distribuida:

• Si prevemos que las comunicaciones entre los ordenadores pueden fallar o no ser permanentes, o incluso puede estar apagado temporalmente el ordenador de destino. Es decir, no esta garantizada la disponibilidad de la máquina. El MSMQ simplemente depositará el mensaje en la cola de destino correspondiente hasta que el ordenador vuelva estar disponible.

• Si queremos lograr más escalabilidad del sistema. Parece que esto no tiene sentido, puesto que la transmisión de mensajes con MSMQ es más lenta, pero en realidad conseguimos más escalabilidad en el sentido de que se puede manejar más tráfico con picos variables de mensajes sin fallo, aunque cada uno de ellos los maneje más lentamente. Con comunicaciones síncronas el servidor tiene que estar sobredimensionado para poder soportar los picos más fuertes en el tráfico de mensajes, y aún así puede llegar a sobrecargarse. Con comunicaciones asíncronas, sólo tiene que estar dimensionado para el tráfico medio esperado. En los momentos de picos, los mensajes simplemente se almacenarán hasta que puedan ser procesados.

• Cuando nos interese garantizar que el mensaje ha sido recibido por la aplicación de destino, pero no es necesario obtener una respuesta inmediata al mensaje.

Funcionamiento del MSMQ En un sistema MSMQ hay tres tipos de servidores:

• Controlador principal PEC (Primary Enterprise Controller): Gestiona la configuración de todo el sistema. Contiene los certificados para validar las claves.

• Controlador del sitio (Site Controller): Contiene información de todos los ordenadores y colas de un sitio (ordenadores conectados por una red rápida). Varios sitios forman el sistema. En el sitio donde esté el PEC, éste sirve también de controlador de sitio.

• Enrutador de mensajes (Message Router): Gestiona el envío de mensajes entre sitios. El controlador de sitio sirve también de router. Si un sitio tiene mucho tráfico se le pueden añadir routers adicionales.

Y hay dos tipos de clientes:

• Cliente independiente: Tiene su propia cola de mensajes. Se usa normalmente en portátiles.

• Cliente dependiente: No tiene cola; depende de un servidor MSMQ.

El MSMQ permite tres modos de envío de mensajes:

• Basado en memoria: Es el más rápido. El mensaje se almacena en la memoria hasta que el gestor puede contactar con el gestor de destino. Si hay un problema en la comunicación, esperará hasta poder hacerlo. El inconveniente es que si hay un fallo en la máquina, se pierde el mensaje.

• Basado en disco: Es más lento. El mensaje se almacena en el disco. Cuando llega a la máquina de destino, se elimina del disco. Si hay un fallo en la máquina, se puede recuperar luego del disco. Hace falta un sistema de archivos como el NTFS que permite esta recuperación.

Page 260: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

260

• Basado en transacciones: Utiliza los Servicios de Componentes, antes MTS.

Creación de una cola Para acceder a la consola de administración del servicio MSMQ en Windows 2000, debemos seleccionar “Administración de equipos”, dentro de las Herramientas administrativas del menú de Inicio. Si expandimos el árbol correspondiente a “Servicios y Aplicaciones”, obtendremos un resultado como el que aparece en la Figura 72.

Figura 72

Si pulsamos con el botón derecho sobre la carpeta de Colas privadas, y del menú emergente seleccionamos la opción Nuevo | Cola privada, podemos crear una nueva cola. Sólo hay que suministrar la información que se pide en una ventana como en la Figura 73, es decir, el nombre de la cola y su comportamiento transaccional.

Figura 73

Page 261: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

261

Si extendemos ahora el árbol de la cola1 recién creada obtendremos lo que aparece en la Figura 74.

Figura 74

Vemos que en la subcarpeta de Mensajes de la cola no hay ahora ninguno.

Modelo de objetos de MSMQ Trabajaremos con tres objetos principales de este modelo:

• MSMQQueueInfo: Permite almacenar las colas de un servidor MSMQ. Lo usaremos como punto de partida para cualquier operación con colas: crear, modificar, borrar, etc.

• MSMQQueue: Representa una cola abierta por medio del método Open del objeto MSMQQueueInfo.

• MSMQMessage: Representa un mensaje.

Vamos a ver que podemos utilizar este modelo COM para acceder al servicio MSMQ desde una página ASP. Y lo primero que haremos será repetir lo mismo que conseguimos desde la consola de administración del servicio. Para ello creemos una página ASP con el Código fuente 190.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD>

Page 262: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

262

<BODY>

<%Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo")objQueueInfo.PathName = ".\PRIVATE$\cola2"objQueueInfo.Create%>

</BODY>

</HTML>

Código fuente 190

En esta página simplemente recogemos una referencia al objeto MSMQQueueInfo. A continuación le asignamos a la propiedad PathName el nombre de la cola.

En caso de tratarse de colas privadas, este nombre es de la forma “nombreDelServidor\PRIVATE$ \nombreDeLaCola”, aunque el nombre del servidor puede sustituirse por un punto, quedando de la forma “.\PRIVATE$\nombreDeLaCola”.

Por último, basta llamar al método Create. Siempre debe asignarse la propiedad PathName antes de llamar al método Create.

Si ejecutamos la página podremos ver en la consola de administración del MSMQ que se ha creado una nueva cola privada, de nombre “cola2”. Ejecutando el Código fuente 191 conseguiríamos eliminarla.

Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo")

objQueueInfo.PathName = ".\PRIVATE$\cola2"

objQueueInfo.Delete

Código fuente 191

Envío de mensajes Ahora vamos a enviar un mensaje a la cola1 recién creada desde una página ASP. Lo primero es comprobar que se disponen de los permisos necesarios para enviar un mensaje a la cola.

Si desde el administrador del servicio MSMQ, pulsamos con el botón derecho sobre el nombre de la cola y seleccionamos la opción Propiedades, y luego la pestaña Seguridad, obtendremos lo que se muestra en la Figura 75.

Vemos que por defecto, el grupo Todos, en el que desde luego estará incluida la cuenta de invitado a internet IUSR_nombreServidor que normalmente usaremos al ejecutar una página ASP con acceso anónimo, tiene activado el permiso de “Escribir mensaje”, pero no así los de recibir ni inspeccionar mensaje. Pero como ahora sólo queremos escribir, con esto es suficiente.

En el Código fuente 192 se pueden ver las instrucciones que son necesarias para escribir un mensaje en la cola.

Page 263: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

263

Figura 75

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><!--METADATA type="typelib" file="C:\winnt\system32\mqoa.dll"-->

<%Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo")objQueueInfo.PathName = ".\PRIVATE$\cola1"

Set objQueue = objQueueInfo.Open(MQ_SEND_ACCESS,MQ_DENY_NONE)

Set objMsg = Server.CreateObject("MSMQ.MSMQMessage")objMsg.Label = "Mensaje 1"objMsg.Body = "Cuerpo del mensaje"objMsg.Send objQueue

objQueue.CloseSet objMsg = NothingSet objQueue = NothingSet objQueueInfo = Nothing%></BODY></HTML>

Código fuente 192

Page 264: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

264

Igual que antes, primero obtenemos la referencia al objeto MSMQQueueInfo, y le asignamos la propiedad PathName que identifica a la cola. A continuación aplicamos el método Open sobre este objeto para obtener una referencia a la cola.

Este método Open recibe dos parámetros, que son especificados por medio de constantes. Para poder utilizar los nombres de estas constantes en vez de tener que recordar su valor numérico, utilizamos la directiva METADATA con el nombre de la DLL en que se encuentran, que en este caso es MQOA.DLL. El parámetro Access especifica el modo de apertura de la cola por la aplicación, es decir, que va a hacer con ella. Puede tomar los valores:

• MQ_RECEIVE_ACCESS (1): Permite inspeccionar o recibir mensajes de la cola. En el segundo caso, los mensajes se eliminan a medida que son leídos.

• MQ_SEND_ACCESS (2): Permite enviar mensajes a la cola.

• MQ_PEEK_ACCESS (32): Sólo permite inspeccionar los mensajes, pero no recibirlos.

El parámetro ShareMode especifica qué acceso tienen los demás a la cola mientras está siendo utilizada por la aplicación. Puede tomar los valores:

• MQ_DENY_NONE (0): Si he abierto la cola en uno de los modos MQ_SEND_ACCESS o MQ_PEEK_ACCESS, ésta es la única opción. Permito a los demás el acceso total a la cola.

• MQ_DENY_RECEIVE_SHARE (1): Si he abierto en modo MQ_RECEIVE_ACCESS, tengo la opción anterior o ésta. Con ella impido que otros reciban mensajes de la cola, aunque pueden seguir enviando.

Luego creamos un objeto MSMQMessage y le asignamos valor a sus propiedades Label, que contiene la etiqueta del mensaje, y Body, que almacena su contenido. El método Send invocado sobre este objeto necesita como parámetro el nombre de la cola a la que va a ser enviado. Para finalizar, cerramos la cola y destruimos los objetos. En la consola de administración del servicio MSMQ podremos ver que el mensaje se ha enviado y almacenado en la cola, como se ve en la Figura 76.

Figura 76

Page 265: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

265

Por cierto, que podemos configurar las propiedades del mensaje que queremos que aparezcan en el panel izquierdo. Basta con pulsar con el botón derecho sobre la subcarpeta “Mensajes de la cola”, y seleccionar la opción Ver | Elegir columnas. Aparecerá una ventana como la de la Figura 77 en la que podremos seleccionar la información que queremos ver de los mensajes.

Figura 77

Prioridad de los mensajes El mensaje que acabamos de enviar tiene una prioridad por defecto de 3, que es el nivel de prioridad intermedio. Pero yo puedo modificar este valor por defecto, y asignar valores que van desde 0 para la prioridad mínima hasta 7 para la máxima.

Si cambiamos ahora la página ASP por el contenido del Código fuente 193, estamos asignando al nuevo mensaje una prioridad de 7, que es superior a la del mensaje anterior.

Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo")objQueueInfo.PathName = ".\PRIVATE$\cola1"

Set objQueue = objQueueInfo.Open(MQ_SEND_ACCESS,MQ_DENY_NONE)

Set objMsg = Server.CreateObject("MSMQ.MSMQMessage")objMsg.Label = "Mensaje 2"objMsg.Body = "Cuerpo del mensaje"objMsg.Priority = 7objMsg.Send objQueue

objQueue.CloseSet objMsg = NothingSet objQueue = NothingSet objQueueInfo = Nothing

Código fuente 193

Page 266: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

266

Podemos comprobar en la consola de administración del MSMQ, como se ve en la Figura 78, que este segundo mensaje se coloca delante del anterior en la cola, puesto que su prioridad es mayor.

Figura 78

Recepción de mensajes Una vez enviado el mensaje, vamos a intentar recuperarlo desde una página ASP. Normalmente las páginas ASP se limitarán a enviar mensajes a una cola, y será otra aplicación la encargada de recuperarlos y procesarlos, pero vamos a ver que también desde el VBScript de una página ASP podemos hacer esto mismo, aunque sólo sea en este caso para listarlos en una tabla.

De momento sólo vamos a inspeccionar el mensaje, es decir, veremos su contenido pero no lo eliminaremos de la cola. Creamos para ello una nueva página ASP con el código que puede verse en el Código fuente 194.

Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo")objQueueInfo.PathName = ".\PRIVATE$\cola1"

Set objQueue = objQueueInfo.Open(MQ_PEEK_ACCESS,MQ_DENY_NONE)

Set objMsg = objQueue.PeekCurrentResponse.Write objMsg.Label & " - " & objMsg.Body

objQueue.CloseSet objMsg = NothingSet objQueue = NothingSet objQueueInfo = Nothing

Código fuente 194

Page 267: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

267

Esta vez abrimos la cola en modo MQ_PEEK_ACCESS, es decir, para inspeccionar. A continuación obtenemos una referencia a un objeto MSMQMessage a partir del método PeekCurrent invocado sobre la cola. Este método recupera el mensaje sobre el que esté posicionado el cursor, que ahora mismo es el primer mensaje de la cola, que será el segundo enviado puesto que tenía mayor prioridad. Escribimos la etiqueta y el cuerpo del mensaje, cerramos la cola, y eliminamos los objetos.

Si ejecutamos esta página, obtendremos el error de Acceso denegado. Esto es debido a que la cuenta de invitado a internet no tiene los permisos necesarios para inspeccionar los mensajes almacenados en esta cola. Vamos a concedérselos a través del grupo Todos, como se ve en la Figura 79, activando la casilla de verificación correspondiente a “Inspeccionar mensaje”.

Figura 79

Ahora sí podremos ejecutar la página y obtener el contenido del mensaje sin problemas.

Si lo que queremos es inspeccionar el contenido de todos los mensajes de la cola, debemos hacerlo a través de un bucle, como se puede ver en el Código fuente 195.

Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo")objQueueInfo.PathName = ".\PRIVATE$\cola1"

Set objQueue = objQueueInfo.Open(MQ_PEEK_ACCESS,MQ_DENY_NONE)

Set objMsg = objQueue.PeekCurrent(,,100)Do While True

Page 268: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

268

If objMsg Is Nothing Then Exit DoResponse.Write "<b>" & objMsg.Label & "</b>: " & objMsg.Body & "<br>"Set objMsg = objQueue.PeekNext(,,100)

Loop

objQueue.CloseSet objMsg = NothingSet objQueue = NothingSet objQueueInfo = Nothing

Código fuente 195

Utilizamos el método de lectura anticipada, y luego un bucle infinito Do While True, del que sólo se sale con Exit Do en el caso de que el mensaje leído en un paso del bucle sea igual a Nothing, es decir, que ya no queden mensajes en la cola.

Tanto en el método PeekCurrent, que lee el mensaje actual, como el PeekNext, que lee el siguiente, son sólo métodos de inspección de mensajes: leen el mensaje pero no lo eliminan de la cola.

Cuando se invoca a cualquiera de estos dos métodos, la ejecución se detiene hasta que se lee el mensaje de la cola o hasta que se consume el tiempo de espera. Este tiempo de espera es el tercero de los tres parámetros opcionales que pueden recibir estos métodos, el ReceiveTimeout, que se especifica en milisegundos.

Antes no hemos utilizado este parámetro porque sabíamos que había un mensaje en la cola. Pero si en este caso no lo utilizamos, la ejecución de la página entraría en un bucle infinito, porque después de leer el último mensaje de la cola, volvería a ejecutar el bucle y se quedaría intentando leer uno nuevo de forma indefinida. En el código de ejemplo se han asignado 100 milisegundos de timeout de recepción.

Si en vez de sólo inspeccionar un mensaje queremos recibirlo, es decir, leerlo y eliminarlo de la cola, debemos escribir algo parecido al Código fuente 196.

Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo")objQueueInfo.PathName = ".\PRIVATE$\cola2"

Set objQueue = objQueueInfo.Open(MQ_RECEIVE_ACCESS,MQ_DENY_NONE)

Set objMsg = objQueue.ReceiveCurrent(,,,100)Response.Write objMsg.Label & " - " & objMsg.Body

objQueue.CloseSet objMsg = NothingSet objQueue = NothingSet objQueueInfo = Nothing

Código fuente 196

Ahora abrimos la cola en modo MQ_RECEIVE_ACCESS en vez de MQ_PEEK_ACCESS, e invocamos al método ReceiveCurrent en vez de PeekCurrent.

Para que funcione la página, debemos conceder permisos de recepción de mensajes en la cola activando la casilla de verificación correspondiente a “Recibir mensaje”, como se aprecia en la Figura 80.

Page 269: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

269

Figura 80

Se puede observar en la consola de administración del servicio MSMQ que el mensaje ha desaparecido de la cola después de haber sido leído.

Colas de diario Se pueden almacenar copias de los mensajes para llevar un control de los mensajes enviados y recibidos. Estas copias se llaman mensajes de diario, y se almacenan en las copias de diario.

Para que la cola permita almacenamiento de diario, desde el administrador del servicio MSMQ pulsamos con el botón derecho sobre el nombre de la cola y seleccionamos la casilla de verificación “Habilitado” dentro del apartado “Diario”, como se ve en la Figura 81.

De esta forma, al eliminarse el mensaje de la cola, se almacena una copia del mismo en la subcarpeta denominada “Mensajes del diario”.

Lo podemos comprobar si enviamos un nuevo mensaje y luego lo recibimos. La copia del mensaje queda almacenada como se ve en la Figura 82.

Page 270: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

270

Figura 81

Figura 82

Page 271: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

271

Envío de un componente COM+ Veamos ahora que a una cola podemos enviar datos binarios como cuerpo de un mensaje, y en concreto vamos a enviar la instancia de un componente. Continuamos trabajando con nuestra tabla de Clientes de capítulos anteriores.

Hacemos para ello un nuevo proyecto ActiveX DLL de Visual Basic al que llamaremos CompCliente, con un módulo de clase llamado Cliente. Con el complemento Generador de clases, añadimos tres propiedades al módulo, una por cada campo de la tabla Clientes.

Los objetos COM+ que envíe en un mensaje tienen que soportar la persistencia, o dicho de otra forma, ser serializables. Con C++ se pueden construir componentes que implementen el interfaz IPersist, de tal forma que cuando el MSMQ tiene que meter un objeto en el cuerpo de un mensaje, lo serializa a través de este interfaz. Esos datos binarios serializados son los que se almacenan en el cuerpo del mensaje.

Con Visual Basic no puedo hacer esto, pero las rutinas de su runtime se encargan de simular este interfaz: lee las variables y valores del objeto y las mete en un PropertyBag, y luego las serializa a través del interfaz IPersist. Realmente las clases de Visual Basic no implementan ese interfaz, sino que cuando el MSMQ busca ese interfaz, las rutinas del runtime se encargan de invocar los eventos Class_ReadProperties y Class_WriteProperties.

Por lo tanto, tenemos que declarar primero de todo el módulo de clase como serializable, configurando su propiedad “Persistable” al valor “1-Persistable”, como se ve en la Figura 83.

Figura 83

Además debemos implementar los procedimientos Class_ReadProperties y Class_WriteProperties, que serán invocados automáticamente en la serialización y en el proceso inverso, leyendo o escribiendo en el PropertyBag. El Código fuente 197 muestra el resultado definitivo.

Private mvarid As Integer

Page 272: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

272

Private mvarnombre As StringPrivate mvarsaldo As Currency

Public Property Let id(ByVal vData As Integer)mvarid = vData

End Property

Public Property Get id() As Integerid = mvarid

End Property

Public Property Let nombre(ByVal vData As String)mvarnombre = vData

End Property

Public Property Get nombre() As Stringnombre = mvarnombre

End Property

Public Property Let saldo(ByVal vData As Currency)mvarsaldo = vData

End Property

Public Property Get saldo() As Currencysaldo = mvarsaldo

End Property

Private Sub Class_ReadProperties(PropBag As PropertyBag)mvarid = PropBag.ReadProperty("id")mvarnombre = PropBag.ReadProperty("nombre")mvarsaldo = PropBag.ReadProperty("saldo")

End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)PropBag.WriteProperty "id", mvaridPropBag.WriteProperty "nombre", mvarnombrePropBag.WriteProperty "saldo", mvarsaldo

End Sub

Código fuente 197

Hay un inconveniente más, y es que las limitaciones inherentes a un lenguaje de script como es el VBScript nos impiden ejecutar desde una página ASP el código necesario para enviar, y posteriormente recibir, este componente serializado a una cola de MSMQ. Tenemos que hacerlo también a través de otro componente.

Vamos a hacerlo creando un nuevo módulo de clase en el mismo proyecto, al que llamaremos GestionMSMQ, y que tendrá dos métodos: uno para enviar el objeto a la cola y otro para recibir el objeto desde la cola. Debemos añadir al proyecto la referencia a la librería de “Microsoft Message Queue”, como se ve en la Figura 84.

El Código fuente 198 muestra el estado final de este nuevo módulo de clase.

En el método “EnviaComponente” asignamos a la propiedad Body del mensaje el objeto instanciado. En el otro método, “RecibeComponente”, recorremos en un bucle, sólo de inspección, la cola de mensajes hasta encontrar el primero cuya etiqueta coincide con la que recibe el método como parámetro. En ese momento, se recibe el mensaje, con lo que se borra de la cola, se sale del bucle y posteriormente de la función.

Page 273: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

273

Figura 84

Option ExplicitPrivate objCliente As CompCliente.ClientePrivate objQueueInfo As MSMQ.MSMQQueueInfoPrivate objQueue As MSMQ.MSMQQueuePrivate objMsg As MSMQ.MSMQMessage

Public Function EnviaComponente(ByVal id As Integer, ByVal nombre As String, ByValsaldo As Currency) As Variant

On Error GoTo Errores

Set objCliente = New CompCliente.ClienteobjCliente.id = idobjCliente.nombre = nombreobjCliente.saldo = saldo

Set objQueueInfo = New MSMQ.MSMQQueueInfoobjQueueInfo.PathName = ".\PRIVATE$\cola1"

Set objQueue = objQueueInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE)

Set objMsg = New MSMQ.MSMQMessageobjMsg.Label = "Mensaje Cliente"objMsg.Body = objClienteobjMsg.Send objQueue

objQueue.CloseSet objMsg = NothingSet objQueue = NothingSet objQueueInfo = Nothing

EnviaComponente = "Mensaje enviado"Exit Function

Errores:EnviaComponente = Err.Description

End Function

Page 274: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

274

Public Function RecibeComponente(Etiqueta As String) As VariantOn Error GoTo Errores

Set objQueueInfo = New MSMQ.MSMQQueueInfoobjQueueInfo.PathName = ".\PRIVATE$\cola1"

Set objQueue = objQueueInfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE)

RecibeComponente = "Mensaje no encontrado"

Set objMsg = objQueue.PeekCurrent(, , 100)Do While True

If objMsg Is Nothing Then Exit DoIf objMsg.Label = Etiqueta Then

Set objMsg = objQueue.ReceiveCurrent(, , , 100)Set RecibeComponente = objMsg.BodyExit Do

ElseSet objMsg = objQueue.PeekNext(, , 100)

End IfLoop

Salida:objQueue.CloseSet objMsg = NothingSet objQueue = NothingSet objQueueInfo = Nothing

Exit Function

Errores:RecibeComponente = Err.DescriptionResume Salida

End Function

Código fuente 198

Si enviamos ahora varios mensajes a la cola, algunos como ya hemos visto, y otros utilizando el módulo de clase recién creado, con una página ASP tan simple como la del Código fuente 199, tendremos en la cola un aspecto parecido al que muestra la Figura 85.

Set objCom = Server.CreateObject("CompCliente.GestionMSMQ")objCom.EnviaComponente 7,"pepe",7000Set objCom = Nothing

Código fuente 199

Probemos ahora que funciona el otro método. Cada vez que ejecutemos la página mostrada en el Código fuente 200, deben ir apareciendo uno a uno todos los objetos que hayamos almacenado en la cola, y deben irse eliminando de la misma conforme son recuperados. En esta página ASP sólo estamos recuperando el objeto, pero es fácil imaginar que podríamos hacer un alta en la tabla con los datos recuperados. De esta forma podríamos, por ejemplo, ir almacenando las peticiones de altas de clientes en la cola, para luego ser procesadas todas de golpe en otro momento.

Page 275: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 14. Acceso a MSMQ desde ASP

275

Figura 85

Set objCom = Server.CreateObject("CompCliente.GestionMSMQ")'objCom.EnviaComponente 7,"pepe",7000'Set objCom = Nothing

'Response.End

On Error Resume NextSet objCliente = objCom.RecibeComponente("Mensaje Cliente")if Err=0 then

Response.Write objCliente.id & "<br>"Response.Write objCliente.nombre & "<br>"Response.Write objCliente.saldo & "<br>"

elseResponse.Write "No hay más mensajes de clientes en la cola"

end if

Código fuente 200

Page 276: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 277: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Acceso a ADSI desde ASP

Directorios y Servicios de Directorio Lo primero que podríamos decir es que un directorio. Un directorio es una forma de almacenar información. Pero realmente una base de datos relacional es también una forma de almacenar información, aunque distinta. ¿Dónde está entonces la diferencia?

Las diferencias que hay entre un directorio y una base de datos relacional, aunque tampoco se puede establecer una separación muy precisa entre una y otra cosa, serían:

• Un directorio guarda información jerárquica, en forma de árbol, del mismo modo que el sistema de archivos está organizado en carpetas, subcarpetas y ficheros.

• La información que contiene el directorio está almacenada en objetos. Un directorio contiene objetos.

• Suelen estar replicados, es decir, su información almacenada de forma redundante en varios lugares distintos, sin que sea vital el hecho de que estén o no sincronizados.

• Están más optimizados para lectura que para escritura. Disponen, por ejemplo, de sofisticadas funciones de búsqueda, utilizando indexaciones para optimizar la velocidad.

El ejemplo más utilizado para explicar lo que podría ser un directorio sería el de un listín telefónico. Almacena información, que está replicada, sin importar demasiado que la información almacenada en distintos sitios coincida exactamente. Está más optimizado para lectura (búsqueda de un número de teléfono) que para escritura (en este caso la escritura significa hacer una nueva impresión de listines).

Page 278: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

278

No importa como esté implementado internamente el directorio (podría utilizarse una base de datos relacional). Lo que importa es cómo veo y como accedo yo a esa información desde fuera.

Si un Directorio es un almacenamiento de información, un Servicio de Directorio es el software que se encarga de obtener esa información. También se encarga de proporcionar la gestión de seguridad, de forma que sólo accedan a la información almacenada las personas que estén autorizadas.

Lo normal es que el Servicio de Directorio contenga internamente al Directorio. Ejemplos de esto son el Active Directory de Microsoft y los Servicios de Directorio de Novell.

Hay muchos más directorios, como los de Microsoft Exchange, Lotus Notes, etc. El problema está en que cada uno de ellos tiene su propio servicio de directorio específico, y la forma de acceder es distinta

Active Directory de Microsoft Es un directorio que almacena la información correspondiente a todos los recursos de un dominio: ordenadores, impresoras, aplicaciones, archivos, cuentas de usuario, permisos de seguridad, etc. Además, los administradores pueden añadir nuevos contenidos a este directorio, de forma que almacene otra información adicional que consideren útil.

El concepto que incorpora Active Directory no es algo nuevo. Lleva existiendo mucho tiempo en otros sistemas operativos. En Windows ha tardado en aparecer por la sencilla razón de que este sistema operativo empezó siendo un simple entorno gráfico. Es sólo últimamente, con Windows NT y Windows 2000 cuando ha comenzado a ser un sistema operativo realmente potente, y ha necesitado de la incorporación de este directorio.

En Windows NT 4 ya se almacenaba la información en un directorio, pero sólo era accesible con una API específica para ese directorio. Active Directory cumple el protocolo estándar LDAP. Además el modelo de seguridad es mejor que el que había en Windows NT.

Por defecto, el Active Directory guarda información global del dominio, pero apenas guarda información local de cada miembro del dominio, como cuentas de usuario. Esta información se guarda en las máquinas individuales.

Pero hemos dicho que el Active Directory puede ser configurado por los administradores para que almacene nueva información. Algunas posibilidades serían:

• Replicar en el directorio la información de las máquinas individuales, de forma que podría ser recuperada en el caso de que una de estas máquinas falle.

• Guardar mis preferencias de escritorio en el Active Directory. Así puedo recuperarlas cuando me conecte desde cualquier PC del dominio.

• Si una aplicación que corre en una máquina necesita un componente que no tiene instalado, podría buscar en el Active Directory para encontrar en qué máquina se encuentra y solicitarlo.

La información almacenada en el Active Directory es realmente de dos tipos. Por una parte está la información que se necesita para la gestión del dominio, como equipos, cuentas, impresoras, etc. Por otra parte está la información que se quiera guardar, como un directorio de propósito general

Disponer de un servicio de directorio como el Active Directory de Microsoft supone varias ventajas:

Page 279: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 15. Acceso a ADSI desde ASP

279

• Simplifica la gestión del administrador, que a través de este servicio de directorio puede configurar de igual forma cuentas, servidores, equipos, aplicaciones, etc.

• Permite la instalación automática de aplicaciones según el usuario, independientemente de la maquina desde la cual éste haga login en el sistema, utilizando tecnologías IntelliMirror. Por ejemplo, se podría configurar de tal forma que todos los empleados del departamento de Nóminas de la compañía tengan acceso a una cierta aplicación de gestión de nóminas.

• Permite una búsqueda más eficientes de los recursos de los que dispone el dominio. Por ejemplo, se puede hacer una búsqueda de una impresora con unas determinadas características de impresión en color o calidad.

• Permite que el administrador delegue funciones y asigne privilegios a usuarios y grupos.

• Proporciona una seguridad más robusta, al ser este servicio de directorio el único punto de entrada a los recursos del dominio. Funciona como la autoridad central que gestiona el control de acceso a los recursos del dominio, mediante varios mecanismos de autenticación. Además este control de acceso es independiente de si el usuario hizo login a través de la red local o desde internet.

• Permite controlar mejor los equipos, concediendo sólo a ciertos usuarios o grupos la posibilidad de instalar aplicaciones en los equipos y modificar el registro de la máquina

• Permite el desarrollo de aplicaciones que se adapten al usuario, según la información que hay almacenada sobre él en el directorio. En el caso del departamento de Nóminas, por ejemplo, se podría desarrollar una aplicación que tuviera una opción de menú disponible sólo para el jefe del departamento, pero no para los empleados.

ADSI (Active Directory Services Interface) Hemos dicho que hay muchos servicios de directorio, cada uno con su forma específica de acceder a la información almacenada. Esto complica mucho la labor del administrador.

Es aquí donde interviene el ADSI. Es un conjunto de interfaces COM que permiten acceder a los servicios de directorio para los que tenga un proveedor ADSI. Estos proveedores son objetos COM que implementan estos interfaces.

La idea es similar a la de OLE DB, que es un conjunto de objetos COM de propósito general que permiten acceder a distintas BDs para las que tenga un proveedor OLE DB. No importa que estas bases de datos sean de fabricantes distintos y estén implementadas de formas completamente diferentes. De igual forma, con ADSI puedo acceder a los servicios de directorio para los que tenga proveedor.

Los proveedores ADSI hacen de intermediarios. La aplicación cliente se comunica con ellos a través de los interfaces estándar de ADSI, y ellos se comunican con el servicio de directorio con su API específica. Igual sucede con OLE DB: la aplicación cliente (a través de ADO) se comunica con los proveedores OLE DB a través de interfaces comunes, y estos proveedores se comunican con el gestor de base de datos correspondiente.

El Active Directory de Microsoft es sólo uno de los muchos servicios de directorio a los que se puede acceder utilizando ADSI. No hace falta que los servicios de directorio sean compatibles con LDAP. Mediante ADSI también puedo acceder a servidores web, FTP, de email, etc.

Page 280: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

280

Gracias a que ADSI proporciona unos interfaces comunes para acceder a varios servicios de directorio distintos, los administradores pueden gestionar de forma única varios de estos servicios de directorio, y los usuarios pueden tener un único login para acceder a todos los servicios (no uno para la red, otro para email, etc).

Hay varios proveedores ADSI:

• Proveedor ADSI para LDAP (Lightweight Directory Access Protocol). Para acceder a Active Directory de Windows 2000, al directorio de servidores Exchange, o al directorio de Site Server, se usa este proveedor, puesto que estos tres directorios mencionados cumplen con el protocolo LDAP. ADSI usa COM y es de alto nivel, luego puedo usarlo desde cualquier lenguaje que acepte COM. LDAP sin embargo está escrito en C, y es de bajo nivel. Es algo parecido a ODBC y OLE DB: ODBC es de bajo nivel, y es más difícil trabajar con él que con OLE DB. De igual manera, se puede acceder a Active Directory directamente con LDAP, pero resulta más cómodo como programador hacerlo con ADSI. Desde nuestras páginas ASP usaremos el proveedor ADSI para LDAP para acceder a Active Directory.

• Proveedor ADSI para Winnt. Sirve para dos cosas. Por una parte, en Windows NT 4.0 no había Active Directory. Este proveedor recoge información de las máquinas de la red, y la presenta como si estuviera almacenada en un directorio similar al Active Directory de Windows 2000, aunque con una funcionalidad más limitada. Por otra parte, en Windows 2000 sirve para recuperar información de la máquina local, que por defecto no se almacena en el Active Directory.

• Proveedor ADSI para IIS. Accede a la metabase que guarda la información de configuración del servicio web, ftp, etc.

• Proveedor ADSI para los servicios de directorio de Novell.

Estructura de Active Directory La información de un directorio se guarda en unas entidades llamadas objetos, como impresoras, equipos, etc. Estos objetos se organizan en una estructura jerárquica, tipo árbol, y disponen de una serie de propiedades o atributos. Pero no hay que confundir estos objetos con los objetos COM. Es decir, estas propiedades no son las propiedades de un objeto COM, sino una pequeña información almacenada en el objeto bajo un nombre, por ejemplo la propiedad Description.

Las propiedades de un objeto del directorio son parejas nombre – valor, aunque algunas propiedades pueden tener múltiples valores.

Hay dos tipos de objetos ADSI: containers y leafs. Parecido a las carpetas y archivos del sistema de ficheros de Windows, con la diferencia de que los contenedores también son objetos con su propia información. Es decir, que siguiendo con el símil, un contenedor es como una carpeta y un archivo juntos.

ADO ofrece un conjunto de interfaces que permiten acceder de forma similar a los datos contenidos en distintas bases de datos, usando sentencias SQL para localizar estos datos. De la misma forma, ADSI ofrece un conjunto de interfaces que permiten acceder de forma similar a los objetos contenidos en distintos directorios, usando cadenas que podríamos comparar con la ruta física (Path) de un archivo en el sistema de ficheros. Estas cadenas se llaman ADsPath, y sirven para localizar esos objetos dentro del directorio.

Cada proveedor usa una sintaxis distinta para estas cadenas que identifican los objetos del directorio, pero la cadena siempre empieza con el nombre del proveedor. De esta forma, no hay que hacer igual

Page 281: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 15. Acceso a ADSI desde ASP

281

que cuando abrimos una conexión de ADO, a la cual estoy obligado a suministrar el proveedor mediante una cadena de conexión. Con ADSI la propia cadena ADsPath incluye las dos cosas: el proveedor y la identificación del objeto del directorio.

Proveedor ADSI para WinNT Recordemos que en Windows 2000 este proveedor sirve para recuperar información de la máquina local, que por defecto no se almacena en el Active Directory.

Para acceder a los objetos del directorio se usa el binding. Los objetos ya existen en el directorio, es decir, no tengo que hacer CreateObject. Lo que quiero es recoger una referencia a una instancia concreta, mediante el método GetObject, pasando como parámetro el nombre del objeto, en vez del nombre de la clase del componente, como haría con el método CreateObject. Por ejemplo, para coger una referencia a la raíz del directorio WinNT hago Set objRaiz = GetObject(“WinNT:”) .

De esta forma obtengo un objeto COM que referencia al objeto real almacenado en el directorio. Este objeto COM tendrá unas propiedades por ser objeto COM, y otras propiedades por ser objeto de directorio, en las cuales almacena información.

Si escribimos en una página ASP el Código fuente 201, obtendremos un resultado parecido al que se muestra en la Tabla 10.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY><%Set objRaiz = GetObject("ADs")%><div align="center"><table border="1"><tr><th>Nombre</th><td><%=objRaiz.Name%></td></tr><tr><th>Ruta</th><td><%=objRaiz.ADsPath%></td></tr><tr><th>Clase</th><td><%=objRaiz.Class%></td></tr><tr><th>Padre</th><td><%=objRaiz.Parent%></td></tr></table></div></BODY></HTML>

Código fuente 201

Nombre ADs:

Ruta ADs:

Clase Namespaces

Padre

Tabla 10

Page 282: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

282

En la página ASP nos limitamos a recoger una referencia al objeto raíz del directorio, y luego mostramos en una tabla algunas de sus propiedades. Comentemos algunas cosas.

La clase del objeto ha resultado ser Namespaces, y no tiene padre. Conviene recordar que la estructura de los objetos dentro del directorio sigue una estructura jerárquica en forma de árbol. Si este objeto no tiene padre, significa que es el raíz. Este objeto también se conoce como ADSI Router, y de él derivan en jerarquía todos los proveedores ADSI intalados en el equipo. Estos proveedores son objetos de la clase Namespace, como podemos ver si ejecutamos la página anterior, sustituyendo el parámetro ADsPath por Set objProveedor = GetObject("WinNT:"). En la Tabla 11 está el resultado obtenido.

Nombre WinNT:

Ruta WinNT:

Clase Namespace

Padre ADs:

Tabla 11

Como se puede ver, hemos bajado un nivel en el árbol del directorio. Este objeto, de la clase Namespace, tiene como padre al anterior. Este objeto representa al proveedor ADSI para WinNT. Hay que hacer notar que el nombre del proveedor es sensible a las mayúsculas (devolvería error si ponemos “Winnt” en vez de “WinNT”), pero no así el resto de la cadena ADsPath. Esto es así en la mayoría de los proveedores ADSI.

Si ponemos Set objDominio = GetObject("WinNT://nombreDominio"), donde nombreDominio es el nombre del dominio al que está conectado el equipo, avanzamos un nivel más, y obtenemos el objeto que representa al dominio. Pero además para este objeto podemos mostrar una propiedad más, llamada Schema. La Tabla 12 muestra un posible resultado.

Nombre GRUPO

Ruta WinNT://GRUPO

Clase Domain

Padre WinNT:

Schema WinNT://GRUPO/Schema/Domain

Tabla 12

Page 283: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 15. Acceso a ADSI desde ASP

283

La propiedad Schema devuelve el ADsPath del objeto Schema, que especifica qué información (propiedades obligatorias y opcionales) debe contener un objeto de la clase a la que pertenece el objeto con el que estamos trabajando.

Estas propiedades que estamos mostrando pertenecen al interfaz IADs, que deben implementar todos los objetos de un directorio ADSI. Son propiedades de objeto COM, no de objeto de directorio.

Las propiedades, todas de sólo lectura, del interfaz IADs son las siguientes:

• ADsPath: contiene la ruta que identifica al objeto en el directorio.

• Class: clase a la que pertenece el objeto.

• Guid: GUID único que identifica al objeto o a su clase, según el proveedor.

• Name: nombre común del objeto.

• Parent: contiene la ruta que identifica al objeto superior en la jerarquía del árbol.

• Schema: contiene la ruta del objeto Schema que describe a este objeto, es decir, qué tipo de información debe almacenar (propiedades obligatorias y opcionales).

Y los métodos del interfaz IADs son:

• Get: obtiene el valor de una propiedad identificada por su nombre.

• GetEx: igual que Get, pero también para propiedades con valores múltiples. En vez de devolver un valor único, devuelve un array de valores Variant.

• GetInfo: carga los valores de las propiedades de este objeto desde el servicio de directorio. En vez de acceder a las propiedades del objeto del directorio allí donde estén almacenadas, normalmente en otra máquina de la red, lo que sería muy lento, accedo a una copia local in-process llamada caché de propiedades. Esta copia local puede actualizarse con este método.

• Put: asigna valor a una propiedad.

• PutEx: igual que Put, pero también para propiedades con valores múltiples.

• PutInfo: hace el proceso inverso a GetInfo, es decir, envía los valores de las propiedades desde la caché hasta el servicio de directorio.

• GetInfoEx: igual que GetInfo, pero no carga los valores de todas la propiedades, sino sólo lo de aquellas en las que esté interesado.

Contenedores El último objeto del cual hemos obtenido una referencia, el correspondiente al dominio, es en realidad un objeto container dentro de la jerarquía del directorio suministrado por el proveedor para WinNT.

Un contenedor tiene objetos hijo, que pueden recorrerse con la misma sintaxis empleada para recorrer las colecciones de ASP, como puede verse en el Código fuente 202.

Page 284: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

284

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Set objDominio = GetObject("WinNT://nombreDeDominio")%><div align="center"><table border="1"><tr><th>Nombre</th><th>Ruta</th><th>Clase</th><th>Padre</th></tr><%for each objHijo in objDominio%><tr><td><%=objHijo.Name%></td><td><%=objHijo.ADsPath%></td><td><%=objHijo.Class%></td><td><%=objHijo.Parent%></td></tr><%next%></table></div>

</BODY></HTML>

Código fuente 202

Donde nombreDeDominio es el nombre de un dominio. El resultado devuelto sería similar al de la Figura 86.

Figura 86

Page 285: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 15. Acceso a ADSI desde ASP

285

Los contenedores, aparte de ofrecer el interfaz IADs, presentan también el interfaz IADsContainer. Este interfaz tiene las propiedades:

• Count: Contiene el número de objetos hijo del contenedor. Es sólo de lectura. No está implementada actualmente por el proveedor para WinNT.

• Filter: contiene un array de cadenas que representan las clases de objetos que queremos listar del contenedor. Es de lectura/escritura.

• Hints: Permite especificar qué propiedades queremos cargar de los objetos incluidos en el contenedor. Es de lectura/escritura.

Los métodos del interfaz IADsContainer son:

• CopyHere: copia aquí, como hijo de este contenedor, un objeto del servicio de directorio desde su ubicación original.

• Create: crea un objeto de directorio como hijo de este contenedor.

• Delete: elimina un objeto de directorio que es hijo de este contenedor.

• GetObject: obtiene una referencia a un objeto de directorio que es hijo de este contenedor.

• MoveHere: igual que CopyHere, con la diferencia de que elimina el objeto de su ubicación original.

Propiedades de los objetos del directorio Las propiedades que hemos visto hasta ahora, de los interfaces IADs e IADsContainer, son las propiedades que tienen los objetos de directorio igual que otros objetos COM.

Pero además de estas propiedades, los objetos de un directorio tienen otras propiedades, en unos objetos distintas que en otros, según esté especificado en el Schema correspondiente. A estas propiedades no puedo acceder con la sintaxis del punto, como hago con las propiedades de cualquier objeto COM, sino con unos métodos especiales, ya nombrados antes, como Get y Put.

Si por ejemplo queremos obtener una tabla con las propiedades obligatorias y opcionales del objeto que representa al servicio del IIS, escribiremos el Código fuente 203.

<%@ Language=VBScript %><HTML><HEAD><META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"></HEAD><BODY>

<%Set objIIS = GetObject("WinNT://GRUPO/varrondo/IISADMIN")Set objSchema = GetObject(objIIS.Schema)%><h3>Propiedades obligatorias</h3><table border="1"><%for each prop in objSchema.MandatoryProperties%>

<tr>

Page 286: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

286

<th><%=prop%></th><td><%= objIIS.Get(prop)%></td></tr>

<%next%></table>

<h3>Propiedades opcionales</h3><table border="1"><%On Error Resume Next%><%for each prop in objSchema.OptionalProperties%>

<tr><th><%=prop%></th><td><%= objIIS.Get(prop)%></td></tr>

<%next%></table>

</BODY></HTML>

Código fuente 203

Es necesario activar el manejador de errores de VBScript con On Error Resume Next, por un motivo que veremos a continuación, pero que podemos adelantar diciendo que algunas propiedades no almacenan un valor, sino un array de valores, que no es directamente representable con Response.Write.

Después de obtener la referencia al objeto que representa al servicio IIS, obtenemos la referencia al objeto que representa al Schema, es decir, al objeto que especifica qué propiedades obligatorias y opcionales tiene que guardar el primer objeto. Los dos son objetos del directorio: el segundo especifica las propiedades que almacena el primero, es decir, su “esquema”. Podemos ver que el Path del objeto Schema es WinNT://GRUPO/Schema/Service.

Si queremos ver todos los objetos Schema almacenados en el directorio, no tenemos más que ejecutar el Código fuente 202, pero obteniendo ahora la referencia al objeto contenedor de esquemas, con SetobjSchema = GetObject("WinNT://GRUPO/Schema").

Después recorremos cada una de las colecciones de propiedades, obteniendo el valor almacenado para cada propiedad mediante el método Get con objIIS.Get(prop). Utilizamos las propiedades MandatoryProperties y OptionalProperties, que pertenecen al interfaz IADsClass implementado por todos los objetos Schema, y que contienen la colección de propiedades obligatorias y opcionales que debe tener un objeto de directorio representado por ese objeto Schema.

El resultado que se obtiene será parecido al de la Tabla 13.

PROPIEDADES OBLIGATORIAS

StartType 2

ServiceType 32

DisplayName Servicio de admin. IIS

Page 287: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

© Grupo EIDOS 15. Acceso a ADSI desde ASP

287

Path G:\WINNT\System32\inetsrv\inetinfo.exe

ErrorControl 1

PROPIEDADES OPCIONALES

HostComputer WinNT://GRUPO/varrondo

LoadOrderGroup

ServiceAccountName LocalSystem

Dependencies

Tabla 13

Las propiedades de un objeto del directorio pueden estar almacenadas en cualquier lugar del dominio. Acceder a esa propiedad allí donde esté sería muy lento. Por eso lo que se hace es acceder a una copia local llamada caché de propiedades. Realmente los métodos Get, GetEx, Put y PutEx acceden a esta copia local.

Para actualizar el contenido de este caché se usa el método GetInfo del interfaz IADs. Si sólo quiero actualizar algunas propiedades, se usa GetInfoEx. Para hacer la actualización en sentido contrario, es decir, para enviar las propiedades de nuestra caché, que quizá hemos modificado, de vuelta al directorio, se usa el método SetInfo.

La primera vez que pido una propiedad, se invoca automáticamente al método GetInfo para traer las propiedades a la caché. No hace falta que lo haga yo explícitamente, a no ser que piense que la copia local está obsoleta.

Propiedades con valores múltiples Los valores de las propiedades obtenidos con el método Get son del tipo Variant. Eso significa que puede ser cualquier cosa: vacío, una cadena, un objeto, un array de valores, etc. De hecho, en el ejemplo anterior había algunas propiedades que guardaban un array de valores. Para recorrer estos valores puede usarse el método GetEx.

Si en el código anterior cambiamos por el Código fuente 204 las líneas encargadas de recorrer las propiedades opcionales, obtendremos un resultado como en la Tabla 14.

<h3>Propiedades opcionales</h3><table border="1"><%for each prop in objSchema.OptionalProperties%>

<tr><th><%=prop%></th><td><%for each valor in objIIS.GetEx(prop)%>

Page 288: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Desarrollo de aplicaciones COM+ para Internet / Intranet con ASP 3.0 © Grupo EIDOS

288

<%=valor%><%next%></td></tr>

<%next%></table>

Código fuente 204

PROPIEDADES OPCIONALES

HostComputer WinNT://GRUPO/varrondo

LoadOrderGroup

ServiceAccountName LocalSystem

Dependencies RPCSS ProtectedStorage

Tabla 14

La propiedad Dependencies, que antes no podía mostrarse, ahora sí. Vemos que es un array formado por dos elementos.

Modificación de propiedades Para poder modificar una propiedad de un objeto del directorio, primero debemos contar con los permisos adecuados. La cuenta bajo la que se ejecutan normalmente las páginas ASP es la cuenta de invitado a internet IUSR_NombreMáquina, y esta cuenta normalmente tiene permisos muy restringidos.

Luego para poder ejecutar con éxito una página ASP que modifique propiedades de objetos de directorio debemos, o bien conceder permisos a esta cuenta de invitado a internet, o bien ejecutar la página ASP bajo otra cuenta con los permisos adecuados.

Una vez hecho esto, el Código fuente 205 muestra cómo podríamos cambiar el valor de la propiedad DisplayName del objeto que representa al servicio IIS. Esta propiedad es el texto descriptivo del servicio que aparece al seleccionar la opción Servicios de las Herramientas administrativas de Windows 2000.

Set objIIS = GetObject("WinNT://GRUPO/varrondo/IISADMIN")objIIS.Put "DisplayName","Nuevo nombre para el Servicio"objIIS.SetInfo

Código fuente 205

Page 289: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Si quiere ver más textos en este formato, visítenos en: http://www.lalibreriadigital.com.

Este libro tiene soporte de formación virtual a través de Internet, con un profesor a su disposición, tutorías, exámenes y un completo plan formativo con otros textos. Si desea inscribirse en alguno de nuestros cursos o más información visite nuestro campus virtual en: http://www.almagesto.com.

Si quiere información más precisa de las nuevas técnicas de programación puede suscribirse gratuitamente a nuestra revista Algoritmo en: http://www.algoritmodigital.com. No deje de visitar nuestra reviata Alquimia en http://www.eidos.es/alquimia donde podrá encontrar artículos sobre tecnologías de la sociedad del conocimiento.

Si quiere hacer algún comentario, sugerencia, o tiene cualquier tipo de problema, envíelo a la dirección de correo electrónico [email protected].

© Grupo EIDOS

http://www.eidos.es

Page 290: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Page 291: 53099643 ASP Eidos Desarrollo de Aplicaciones Com Con ASP

Si quiere ver más textos en este formato, visítenos en: http://www.lalibreriadigital.com. Este libro tiene soporte de formación virtual a través de Internet, con un profesor a su disposición, tutorías, exámenes y un completo plan formativo con otros textos. Si desea inscribirse en alguno de nuestros cursos o más información visite nuestro campus virtual en: http://www.almagesto.com. Si quiere información más precisa de las nuevas técnicas de programación puede suscribirse gratuitamente a nuestra revista Algoritmo en: http://www.algoritmodigital.com. No deje de visitar nuestra reviata Alquimia en http://www.eidos.es/alquimia donde podrá encontrar artículos sobre tecnologías de la sociedad del conocimiento. Si quiere hacer algún comentario, sugerencia, o tiene cualquier tipo de problema, envíelo a la dirección de correo electrónico [email protected]. © Grupo EIDOS http://www.eidos.es