Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ASP Eidos Desarrollo de Aplicaciones Com Con ASP
ASP Eidos Desarrollo de Aplicaciones Com Con ASP
Este texto est pensado para aquellos que, teniendo conocimientos de la tecnologa 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 caractersticas ms importantes de ASP, mientras que la segunda se centra en el diseo y uso de componentes. Se tratan temas como la creacin de libreras de enlace dinmico (DLLs), uso de componentes desde pginas ASP, modelo COM+, Servicios de Componentes, componentes de acceso a datos, componentes transaccionales, MSMQ y ADSI. Se requieren unos conocimientos bsicos de Windows, fundamentos de Internet/Intranet, lenguaje HTML y tecnologa ASP, as como ciertas nociones de programacin con Visual Basic.
ADVERTENCIA LEGAL
Todos los derechos de esta obra estn reservados a Grupo EIDOS Consultora y Documentacin Informtica, S.L. El editor prohbe cualquier tipo de fijacin, reproduccin, transformacin, distribucin, ya sea mediante venta y/o alquiler y/o prstamo y/o cualquier otra forma de cesin de uso, y/o comunicacin pblica de la misma, total o parcialmente, por cualquier sistema o en cualquier soporte, ya sea por fotocopia, medio mecnico o electrnico, incluido el tratamiento informtico 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), transmisin o puesta a disposicin (an en sistema streaming). La vulneracin de cualesquiera de estos derechos podr ser considerada como una actividad penal tipificada en los artculos 270 y siguientes del Cdigo Penal. La proteccin 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 autorizacin para el uso profesional, puede obtenerla enviando un e-mail fmarin@eidos.es o al fax (34)-91-5017824. Si piensa o tiene alguna duda sobre la legalidad de la autorizacin de la obra, o que la misma ha llegado hasta Vd. vulnerando lo anterior, le agradeceremos que nos lo comunique al e-mail fmarin@eidos.es o al fax (34)-91-5017824). Esta comunicacin 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 ms obras como sta. Victor Arrondo y ngel Esteban, 2000 Grupo EIDOS Consultara y Documentacin Informtica, S.L., 2000 ISBN 84-88457-20-0
ndice
NDICE................................................................................................................................................... 5 INTRODUCCIN A ASP................................................................................................................... 11 ANTECEDENTES DE ASP: LA ESPECIFICACIN CGI .......................................................................... 11 DEFINICIN 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 INTRODUCCIN .................................................................................................................................. 35 EL OBJETO RESPONSE ........................................................................................................................ 36 Colecciones del objeto Response................................................................................................... 37 Propiedades del objeto Response .................................................................................................. 39 Mtodos del objeto Response......................................................................................................... 41 EL OBJETO REQUEST .......................................................................................................................... 44
Colecciones del objeto Request ..................................................................................................... 44 MODELO DE OBJETOS DE ASP. PARTE II ................................................................................ 49 EL OBJETO APPLICATION ................................................................................................................... 49 Colecciones del objeto Application ............................................................................................... 51 Mtodos 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 Mtodos del objeto Session............................................................................................................ 60 Eventos del objeto Session............................................................................................................. 60 EL OBJETO SERVER ............................................................................................................................ 61 Propiedades del objeto Server....................................................................................................... 61 Mtodos del objeto Server ............................................................................................................. 62 EL OBJETO OBJECTCONTEXT ............................................................................................................. 64 Mtodos del objeto ObjectContext................................................................................................. 66 EVENTOS DEL OBJETO OBJECTCONTEXT ........................................................................................... 66 EL OBJETO ASPERROR ...................................................................................................................... 67 Propiedades del objeto ASPError ................................................................................................. 67 COMPONENTES DE SERVIDOR ................................................................................................... 69 INTRODUCCIN .................................................................................................................................. 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 INTRODUCCIN .................................................................................................................................. 93 MODELO DE OBJETOS DE ADO .......................................................................................................... 96 EL OBJETO CONNECTION ................................................................................................................... 97 Abrir una conexin ........................................................................................................................ 98 Ejecutar comandos sobre una conexin ...................................................................................... 102 Cerrar la conexin....................................................................................................................... 104 EL OBJETO COMMAND ..................................................................................................................... 104 Crear un objeto Command .......................................................................................................... 105 La coleccin Parameters ............................................................................................................. 107 Ejecutar un comando................................................................................................................... 109 EL OBJETO RECORDSET ................................................................................................................... 111 Creacin y apertura de un objeto Recordset ............................................................................... 114 CDONTS Y ASP ................................................................................................................................ 119 INTRODUCCIN ................................................................................................................................ 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
6
INTRODUCCIN A LOS COMPONENTES ............................................................................................. 143 CONCEPTOS ...................................................................................................................................... 144 ESPECIFICACIN COM..................................................................................................................... 144 VENTAJAS DEL USO DE COMPONENTES............................................................................................ 145 LOS INTERFACES .............................................................................................................................. 146 IDENTIFICADORES NICOS GLOBALES (GUIDS)............................................................................. 147 ENLACE TEMPRANO Y TARDO ......................................................................................................... 148 ESPACIO DE PROCESO DE UN COMPONENTE ..................................................................................... 149 EL INTERFAZ IUNKNOWN ................................................................................................................ 150 WINDOWS DNA ............................................................................................................................... 150 COMPONENTES EN VISUAL BASIC .......................................................................................... 153 INTRODUCCIN ................................................................................................................................ 153 COMPONENTES EN VISUAL BASIC Y VISUAL C++........................................................................... 153 UN PRIMER EJEMPLO DE COMPONENTE............................................................................................ 154 Fases en el diseo del componente.............................................................................................. 154 Creacin del proyecto ActiveX DLL............................................................................................ 155 Diseo del interfaz....................................................................................................................... 156 Generacin de la DLL y registro del componente....................................................................... 159 Rediseo del componente ............................................................................................................ 161 Reutilizacin del componente ...................................................................................................... 164 TIPOS DE COMPONENTES.................................................................................................................. 167 MODELOS DE APLICACIONES CLIENTE/SERVIDOR.......................................................... 171 INTRODUCCIN ................................................................................................................................ 171 ARQUITECTURA CLIENTE/SERVIDOR EN DOS CAPAS........................................................................ 171 ARQUITECTURA CLIENTE/SERVIDOR EN TRES CAPAS ...................................................................... 172 EJEMPLO DE UNA APLICACIN ASP EN TRES CAPAS ....................................................................... 174 COMPONENTIZACIN DE LA CAPA INTERMEDIA .............................................................................. 175 Diseo de la capa intermedia con un componente ...................................................................... 175 Rediseo del componente de la capa intermedia......................................................................... 178 Un segundo rediseo del componente de la capa intermedia ..................................................... 178 ARQUITECTURA CLIENTE/SERVIDOR EN N CAPAS ............................................................................ 180 DISEO DE COMPONENTES PARA ASP................................................................................... 181 INTRODUCCIN ................................................................................................................................ 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 Recompilacin de componentes con enlace temprano ................................................................ 192 IMPLEMENTACIN DE INTERFACES EN VISUAL BASIC .................................................................... 193 SERVICIOS DE COMPONENTES ................................................................................................ 197 INTRODUCCIN ................................................................................................................................ 197 CARACTERSTICAS 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 comn de recursos............................................................................................................ 199 Activacin en el momento (Just-In-Time).................................................................................... 199 Seguridad..................................................................................................................................... 200 CONCEPTOS PRINCIPALES DEL MTS ................................................................................................ 200 La intercepcin ............................................................................................................................ 200
7
Propiedades declarativas. El catlogo 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 pgina ASP con VBScript.......................................................... 204 INTRODUCCIN A LAS TRANSACCIONES .......................................................................................... 205 Duracin y resultado de una transaccin.................................................................................... 206 ACTIVACIN 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 intercepcin en COM+........................................................................................................... 215 DISEO DE COMPONENTES COM+ .......................................................................................... 219 EL INTERFAZ OBJECTCONTROL ....................................................................................................... 219 ACTIVACIN JUST-IN-TIME (JIT) .................................................................................................... 227 INICIALIZACIN DEL COMPONENTE ................................................................................................. 229 ESTADO DE UN COMPONENTE .......................................................................................................... 232 CADENA DEL CONSTRUCTOR ........................................................................................................... 238 COMPONENTES TRANSACCIONALES..................................................................................... 241 INTRODUCCIN ................................................................................................................................ 241 EL CONTEXTO Y LAS TRANSACCIONES ............................................................................................ 242 PAUTAS PARA EL DESARROLLO DE COMPONENTES TRANSACCIONALES ......................................... 242 CASOS PRCTICOS ........................................................................................................................... 243 La pgina contiene todo el cdigo transaccional........................................................................ 243 PARTE DEL CDIGO 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 MENSAJERA ENTRE APLICACIONES .......................................................................... 257 MSMQ (MESSAGE QUEUING SERVER)............................................................................................ 258 FUNCIONAMIENTO DEL MSMQ ....................................................................................................... 259 Creacin de una cola................................................................................................................... 260 Modelo de objetos de MSMQ....................................................................................................... 261 Envo de mensajes........................................................................................................................ 262 Prioridad de los mensajes ........................................................................................................... 265 Recepcin de mensajes ................................................................................................................ 266 Colas de diario ............................................................................................................................ 269 ENVO 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
8
PROVEEDOR ADSI PARA WINNT .................................................................................................... 281 CONTENEDORES ............................................................................................................................... 283 PROPIEDADES DE LOS OBJETOS DEL DIRECTORIO ............................................................................ 285 PROPIEDADES CON VALORES MLTIPLES ........................................................................................ 287 MODIFICACIN DE PROPIEDADES .................................................................................................... 288
Introduccin a ASP
Antecedentes de ASP: La especificacin CGI
ASP no es una idea realmente nueva, encontramos un antecedente muy importante y muy utilizado en Internet denominado comnmente scritps CGI. Las siglas CGI se corresponden en ingls a Common Gateway Interface, es decir, interfaz de pasarela comn. 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 especificacin 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 grficos, texto o audio enviados a un navegador Web. La programacin en CGI implica disear programas que se ejecutarn en el entorno de Internet, y ms 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 informacin especial para el CGI cuando pasa a ejecutarlo, y el servidor esperar una respuesta del programa CGI como resultado de su ejecucin. Es esta comunicacin o interaccin entre el servidor Web y el programa CGI es lo que define realmente la especificacin CGI. Los programas CGI tambin 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 traduccin de
Grupo EIDOS
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 contendrn una informacin muy variada acerca del cliente que ha realizado la peticin o del propio servidor Web en el que se ejecuta el programa CGI. Una vez que el servidor ha iniciado la ejecucin del programa CGI esperar un resultado de la ejecucin del mismo. Este resultado suele ser una serie de encabezados de respuesta del protocolo HTTP y cdigo HTML. Estos encabezados y cdigo HTML sern recogidos por el servidor Web y enviados al cliente que realiz la peticin, es decir, al navegador o cliente Web. Despus de ver esta pequea introduccin podemos definir un programa CGI como un programa que se encuentra en un servidor Web y que recibe peticiones desde un cliente Web travs del servidor Web. Y gracias al entorno que le ofrece el servidor Web el programa CGI puede obtener informacin sobre la peticin realizada, adems de otra informacin til, que le permitir procesar la peticin. La respuesta a esta peticin ser generada por el programa CGI en forma de cabeceras de respuesta del protocolo HTTP y etiquetas del lenguaje HTML (HyperText Markup Language), que sern enviadas por el servidor Web al navegador Web que realiz la peticin. CGI no es un lenguaje de programacin sino que es una especificacin. La especificacin CGI va a realizar la funcin 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 especificacin CGI, es decir, interactuar con el servidor atendiendo a unos principios establecidos por la especificacin CGI. CGI ya lleva siendo utilizado muchos aos en la red y todava se sigue utilizando en muchos sitios Web a la hora de acceder a datos o construir pginas dinmicas, pero cada vez ms los sitios Web van adoptando la utilizacin de Active Server Pages. Active Server Pages (ASP) es el nombre que reciben las pginas activas de servidor, es decir, las pginas que se ejecutan en el servidor. ASP se basa en la especificacin CGI, podemos considerar que ASP es una evolucin de la especificacin CGI.
Definicin de ASP
La filosofa de ASP resulta muy sencilla, en pocas palabras se puede definir de la siguiente forma: las pginas ASP, tambin llamadas pginas activas, son pginas que contienen cdigo HTML, script de cliente y un script que se ejecuta en el servidor, dando como resultado cdigo HTML. Por lo tanto al cargar una pgina ASP en nuestro navegador, en realidad no estamos cargando la pgina ASP como tal, sino el resultado de la ejecucin de la pgina ASP, es decir la salida de la pgina ASP, y como se ha apuntado anteriormente se trata de cdigo HTML. Es decir, son pginas que se ejecutan en el servidor enviando como resultado al cliente cdigo 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 ms general y que se utiliza para un entorno muy determinado, en este caso el entorno es la Web. Una pgina ASP podr contener los siguientes elementos: texto, componentes ActiveX, cdigo 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.
12
Grupo EIDOS
1. Introduccin a ASP
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 pgina sea enviada al navegador. ASP no es un lenguaje de script, ASP ofrece un entorno para procesar scripts que se incorporan dentro de pginas 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 dinmicas, interactivas y de alto rendimiento...". Realmente, ASP es un componente (asp.dll) que se instala en un servidor Web y cuya misin es la de procesar ficheros que terminan con la extensin .asp y transmitir el resultado al cliente que solicit la pgina ASP. El script de servidor incluido en una pgina 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 enva una pgina HTML al explorador. ASP incluye un motor de interpretacin de scripts del lado del servidor. Las pginas ASP son ficheros con la extensin asp. Crear un fichero .asp resulta muy sencillo, se puede crear a partir de una pgina HTML existente, simplemente renombrando el fichero .html o .htm a un fichero .asp. Para hacer esta pgina ASP disponible para los usuarios de la Web, el fichero .asp se debe almacenar en un directorio de publicacin en Internet, se debe tener en cuenta que el directorio virtual asociado debe tener permisos de ejecucin de secuencias de comandos. La ltima versin de la tecnologa ASP es la versin 3.0. Esta versin es muy similar a su predecesora, y todas las nuevas caractersticas que presenta se deben a que se utiliza una nueva versin del servidor Web (Internet Information Services 5.0), recordemos que las pginas 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 captulo sobretodo a los alumnos que ya conozcan ASP 2.0.
Aplicaciones ASP
Una aplicacin basada en ASP consta de un directorio virtual en un servidor Web y de todos los subdirectorios y archivos contenidos en l. Una aplicacin puede ser una pgina principal sencilla, o bien puede estar formada por un conjunto completo de pginas interrelacionadas entre s. Al usar aplicaciones en ASP es posible mantener un estado, es decir, se tiene la capacidad de mantener informacin. Dentro de una aplicacin ASP se pueden mantener dos tipos de estado: Estado de la aplicacin, en la que toda la informacin relativa a una aplicacin est disponible para todos los usuarios de la misma. Estado de sesin, en la que la informacin slo est disponible para un usuario o sesin especficos. Una sesin por lo tanto, pertenece a un solo usuario.
Un ejemplo prctico de una aplicacin ASP puede ser este mismo sitio Web. Almagesto est completamente realizado con pginas ASP constituyendo por lo tanto una aplicacin ASP, este sitio
13
Grupo EIDOS
Web demuestra los diferentes usos que puede tener la tecnologa 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 pginas, imgenes y recursos, por lo tanto se trata de aplicaciones muy particulares que requieren para su ejecucin de un servidor Web que soporte las pginas ASP.
Aportaciones de ASP
En este apartado se comentan las aportaciones que ofrece ASP desde su primera versin, es decir, se trata de aportaciones muy genricas de la tecnologa ASP. Para entender las aportaciones que ofrecen las pginas ASP se deben tener en cuenta una serie de caractersticas 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 peticin/respuesta. Se deben tener en cuenta un par de puntos a la hora de establecer la comunicacin entre clientes (navegadores Web) y servidores (servidores Web) del protocolo HTTP: Despus de realizar una peticin el cliente se desconecta del servidor y espera una respuesta. El servidor debe restablecer la conexin despus de que haya procesado la peticin. El servidor y el cliente slo se tienen en cuenta durante la conexin, despus, se olvidan el uno del otro. Por esta razn, ni el cliente ni el servidor pueden retener informacin entre diferentes peticiones o a travs de diferentes pginas Web. Sin embargo, ASP permite al servidor almacenar informacin, 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 transaccin es coherente y completa. Como peticin del usuario se enva una cabecera y el servidor interpreta esta cabecera y enva una respuesta HTTP cuyo cuerpo sera el contenido del recurso demandado por el cliente. ASP permite al desarrollador intervenir en todo el proceso de comunicacin del protocolo HTTP. Los objetos integrados dentro de ASP Request y Response interactan 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 informacin del mismo, as como del usuario. Y tambin se permite, como se haba comentado anteriormente, mantener el estado entre diferentes peticiones del cliente. Se puede considerar ASP como una nueva (aunque ya no tan nueva) aproximacin a la creacin de pginas web complejas que pueden acceder a bases de datos o a otros objetos del servidor. Ofrece lo siguiente:
14
Independencia del navegador, ASP puede ejecutar complejas operaciones en el servidor y enviar solamente los resultados al cliente. Construccin de pginas 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 ms verstiles para el desarrollo de aplicaciones en el entorno de Internet/Intranet.
Grupo EIDOS
1. Introduccin a ASP
Desarrollo de complejas aplicaciones Web. Facilidad de uso de componentes de terceras partes ejecutndose en el servidor, es decir, se pueden utilizar componentes para liberarnos de realizar tareas complejas. Estos componentes se deben registrar en el servidor y podrn ser utilizados desde el script correspondiente. Estos componentes se denominan componentes ActiveX de servidor. Posibilidad de definir pginas ASP transaccionales para realizar todas las operaciones contenidas en la misma dentro de una transaccin. Una tecnologa en constante evolucin y mejora.
A lo largo del curso se profundizar ms en todos estos puntos, aqu se han comentado simplemente los ms evidentes y tambin para poseer una visin general de lo que supone la tecnologa ASP.
Sintaxis de ASP
Como se ha comentado anteriormente ASP no es un lenguaje de script, sino que ofrece un entorno para la ejecucin de estos lenguajes que se encuentran dentro de pginas ASP. ASP posee una sintaxis para poder distinguir cada uno de los elementos que nos podemos encontrar dentro de una pgina ASP. Encerrado dentro de los delimitadores <%%> se va a encontrar todo el cdigo 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 expresin <%=nombre%> enviar al navegador el valor Pepe, es decir, el valor actual de la variable, ms adelante se ver una equivalencia de estos delimitadores con un mtodo de un objeto integrado de ASP. Entre los delimitadores <%%> se puede y debe incluir varias sentencias en distintas lneas de cdigo del lenguaje de secuencias de comandos, sin embargo los delimitadores <%=%> slo podemos encerrar una sentencia por lnea. Entre los delimitadores de ASP se puede incluir cualquier tipo de expresin vlida en el lenguaje de script principal. Por ejemplo el Cdigo fuente 1 genera un texto que contiene la hora actual del servidor.
En este caso el servidor Web devuelve al navegador el valor de la funcin Now de VBScript junto con el texto. Dentro de los delimitadores de script de servidor se pueden encontrar tambin instrucciones del lenguaje de script correspondiente, as por ejemplo puede aparecer una instruccin If...Then...Else del lenguaje VBScript como se puede apreciar en el Cdigo fuente 2.
15
Grupo EIDOS
Else variable="Hola amigo "&nombre End If %> <FONT COLOR="GREEN"> <%=variable%> </FONT> Cdigo fuente 2
En el cdigo anterior se comprueba si la variable nombre tiene algn valor, si lo tiene saludamos con el valor de la variable, mostrando el saludo en color verde. Tambin se puede incluir cdigo HTML entre las instrucciones del script. Por ejemplo la secuencia de comandos del Cdigo fuente 3 mezcla HTML con una instruccin 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> Cdigo fuente 3
Para poder realizar una lectura ms sencilla del cdigo ASP se recomienda utilizar los delimitadores de script de servidor encerrando varias lneas de cdigo en lugar de un par de delimitadores por cada lnea. As, en lugar de escribir lo que se muestra en el Cdigo fuente 4, se debera escribir lo que se muestra en el Cdigo fuente 5.
16
Grupo EIDOS
1. Introduccin a ASP
Cada uno de estos objetos se explicarn con una mayor profundidad ms adelante. La sintaxis utilizada para poder acceder a los mtodos 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 coleccin es un conjunto de elementos de informacin relacionados y que se accede a ellos de una misma forma. Se puede acceder a cada elemento de una coleccin mediante el bucle For...Each. La utilizacin de colecciones se ver en detenimiento en los captulos dedicados a estos dos objetos integrados. Un mtodo es un procedimiento que acta sobre un objeto, la sintaxis para poder invocar un mtodo de un objeto es la del Cdigo fuente 6.
Donde el tipo de parametros depender del mtodo invocado. Una propiedad es un atributo de un objeto. Las propiedades son caractersticas de un objeto que describen su estado, as por ejemplo un objeto podra tener las caractersticas tamao, nombre, color, etc. Para obtener el valor de una propiedad utilizamos la sintaxis del Cdigo fuente 7.
17
Grupo EIDOS
Y para asignarle un valor a una propiedad de un objeto debemos utilizar la sintaxis del Cdigo fuente 8.
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 Automatizacin. Estos componentes estn diseados 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 pginas 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 mtodos asociados al componente o establecer y leer sus propiedades. Los componentes ActiveX Server que incluye ASP en su versin 3.0 son los siguientes: Componente de acceso a bases de datos, ADO (ActiveX Data Objects). A travs de la utilizacin de este componente se puede ofrecer acceso a bases de datos desde una pgina 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 imgenes alternativas con un vnculo a otra direccin desde la imagen presentada. Este componente se suele utilizar para mostrar diferentes anuncios de forma alternativa dentro de una pgina ASP. Componente Funciones del explorador. A travs de este componentes podemos recuperar datos acerca del tipo de navegador del cliente y que capacidades o funciones tiene. Componente vnculo de contenidos. Facilita el desplazamiento lgico entre las diferentes pginas ASP de una aplicacin ASP. Componente Content Rotator (rotador de contenidos). Este componente permite hacer rotaciones de cadenas de contenido HTML en una pgina.
18
Grupo EIDOS
1. Introduccin a ASP
Componente Page Counter (contador de pginas). Permite llevar una cuenta del nmero de veces que se ha accedido a una pgina determinada dentro de nuestro sitio Web. Componente Counters. A travs de este componente podremos almacenar, crear, incrementar y consultar cualquier contador. Componente MyInfo. Nos permite almacenar informacin 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 generacin de nmeros aleatorios o la comprobacin de la existencia de un fichero en el servidor. Componente Permission Checker. A travs 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 extrao pero es as. Nos ofrece una informacin variada acerca del estado del servidor Web. Componente de registro de IIS. Mediante este componente tenemos acceso a la informacin y manipulacin de los ficheros de registro (log) generados por el servidor Web IIS 5.0.
Adems de todos estos componentes, el programador puede crear sus propios componentes ActiveX Server. Estos componentes se pueden desarrollar en lenguajes de programacin 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 pgina ASP, al igual que hacamos con los componentes que vienen por defecto con ASP. Tambin se puede adquirir estos componentes a terceros, existen empresas que se dedican al diseo de componentes para que sean utilizados desde pginas ASP.
Grupo EIDOS
Se ha producido una mejora en el procesamiento de las pginas ASP por parte de la librera ASP.DLL. Se ofrece lo que se denomina ajuste automtico, que consiste en detectar cundo una peticin est bloqueada por recursos externos, en ese caso se proporcionan automticamente ms subprocesos para ejecutar peticiones adicionales y continuar de esta forma con el procesamiento normal de forma simultnea. Los objetos COM se liberan ms rpidamente 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 ofrecan 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 bsica para la creacin de aplicaciones Web.
El objeto Response
Los nicos objetos integrados dentro de ASP que han sufrido alguna modificacin 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 tena por defecto el valor de False (falso). Debido a esto, en ASP 3.0 el resultado de la ejecucin de una pgina ASP nicamente es enviado al cliente cuando se termina de procesar la pgina ASP correspondiente, o bien cuando se utilizan los mtodos Flush o End del objeto Response. Por lo tanto, a no ser que se indique otra cosa, de forma predeterminada el resultado de la ejecucin de la pgina ASP se enviar al bfer. Segn afirma Microsoft la tcnica del bfer ofrece una entrega de pginas ms eficiente al cliente. En el objeto Response tambin cambia la forma de utilizar la propiedad IsClientConnected, mediante esta propiedad podemos consultar si un cliente se encuentra todava conectado a nuestro servidor o por el contrario si ha finalizado su sesin con el mismo. En ASP 2.0 podamos consultar esta propiedad slo si antes habamos 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 mtodos: Transfer y Execute, que permiten controlar el control de flujo del programa, ampliando las capacidades de control de flujo de las pginas ASP, anteriormente slo se dispona del mtodo Redirect del objeto Response. En ASP 2.0 si queramos transferir la ejecucin a otra pgina ASP tenamos que utilizar el mtodo Redirect del objeto Response, pero esto supona enviar una respuesta al cliente para indicarle la carga de una nueva pgina, que es la pgina a la que pasamos la ejecucin.
20
Grupo EIDOS
1. Introduccin a ASP
La utilizacin del mtodo Redirect es bastante costosa y problemtica ya supone un envo de informacin ms del servidor al cliente para indicarle mediante una cabecera HTTP de redireccin que la pgina ha cambiado de localizacin, siendo la nueva localizacin la pgina que deseamos cargar. Esto es problemtico 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 tambin ocurre cuando la conexin la realiza el cliente a travs de proxy. Pero ahora con ASP 3.0 podemos evitar esta redireccin, que como hemos visto, tiene lugar en el cliente, mediante los mtodos Execute y Transfer del objeto Server que permiten que la redireccin tenga lugar en el servidor, quedando el cliente completamente ajeno. Ambos mtodos reciben como parmetro la ruta de la pgina a la que queremos redirigir al cliente. La utilizacin del mtodo Execute es muy similar a realizar una llamada a un procedimiento o funcin. Cuando lanzamos el mtodo Execute se empieza a ejecutar la pgina que indicamos por parmetro, y cuando termina la ejecucin de esta nueva pgina, el control pasa a la siguiente sentencia despus de la llamada al mtodo Execute en la pgina inicial, siguiendo a partir de aqu con la ejecucin de la pgina, es decir, el navegador del cliente recibe una salida formada por la combinacin de la ejecucin de ambas pginas. El mtodo Transfer se comporta de distinto modo, al lanzar este mtodo se pasa la ejecucin a la nueva pgina, pero una vez que finaliza la ejecucin de la misma no se vuelve a la pgina inicial, como ocurra con el mtodo Execute. En ambos mtodos se mantiene el contexto de la pgina inicial, es decir, en la nueva pgina tenemos acceso a las variables, objetos y a todos los objetos intrnsecos de ASP (Request, Session, Response...) de la pgina inicial o pgina de origen. Tambin se mantienen las transacciones entre distintas pginas, siempre que proceda, atendiendo a la directiva @TRANSACTION. De esta forma como la redireccin entre pginas se produce en el servidor, el navegador cree que sigue recibiendo todava la pgina original que habia demandado, incluso en la barra de direcciones del navegador sigue apareciendo la misma URL y los botones Atrs y Adelante funcionan correctamente. Vamos a ofrecer un sencillo cdigo de una pgina ASP que utiliza los mtodos Transfer y Execute para ejecutar otra pgina, y as se puede ver ms claramente la utilizacin de estos dos nuevos mtodos del objeto Server. Nuestra pgina, llamada PaginaInicial.asp, va a constar de un formulario con dos botones, y segn el botn que se pulse se lanzar el mtodo Execute o Transfer para ejecutar la pgina OtraPagina.asp. El cdigo de de la pgina PaginaInicial.asp se muestra en el Cdigo fuente 9, y el de OtraPagina.asp en el Cdigo fuente 10.
<%If Request.Form("Execute")<>"" Then Response.Write "Se est ejecutando la pgina "_ & Request.ServerVariables("SCRIPT_NAME") & "<br>" Server.Execute "OtraPagina.asp" Response.Write "Se est ejecutando de nuevo la pgina "_ & Request.ServerVariables("SCRIPT_NAME") & "<br>" ElseIf Request.Form("Transfer")<>"" Then Response.Write "Se est ejecutando la pgina "_ & Request.ServerVariables("SCRIPT_NAME") & "<br>" Server.Transfer "OtraPagina.asp" Response.Write "Se est ejecutando de nuevo la pgina "_ & Request.ServerVariables("SCRIPT_NAME") & "<br>" End if%> <FORM ACTION="PaginaInicial.asp" METHOD="POST"> <input type="submit" name="Execute" value="Lanza Server.Execute"><br>
21
Grupo EIDOS
<hr> Se est ejecutando la pgina OtraPagina.asp<br> Esta pgina se ha cargado con el mtodo <%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 ejecucin de OtraPagina.asp<br> <hr> Cdigo fuente 10
Si ejecutamos la pgina PAGINAINICIAL.ASP y pulsamos cada uno de sus botones, vemos el distinto comportamiento de los mtodo Execute y Transfer, en el primer caso se intercala el resultado ejecucin de ambas pginas, y en el segundo paso una vez que se ha terminado de ejecutar la segunda pgina finaliza tambin la ejecucin de la secuencia de comandos, sin retornar a la pgina inicial. Las siguientes figuras muestran estas dos situaciones. La Figura 1 muestra la pgina PAGINAINICIO.ASP cuando todava no se ha pulsado ningn botn. En la Figura 2 se muestra cuando se ha pulsado el botn Execute. Y en la Figura 3 cuando se ha pulsado el botn Transfer.
Figura 1
22
Grupo EIDOS
1. Introduccin a ASP
Figura 2
Figura 3
Otro nuevo mtodo que ofrece el objeto Server, y que est relacionado con el tratamiento de errores, es el mtodo GetLastError. Mediante el uso del mtodo GetLastError podemos tener acceso a toda la informacin referente al ltimo error que se ha producido en la pgina ASP actual. Pero es necesario aclarar que su utilizacin no es similar al tratamiento de errores que realizbamos con la sentencia On Error Resume Next y el objeto Err de VBScritp, que preguntbamos por la propiedad Number del objeto Err para averiguar si se haba producido algn error, el mtodo GetLastError se puede utilizar
23
Grupo EIDOS
nicamente dentro de una pgina 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 pginas de error personalizadas y es en estas pginas dnde podemos hacer uso de este mtodo. El mtodo 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 informacin referente al error que se ha producido. Este nuevo objeto lo trataremos con ms 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 travs de la llamada al mtodo GetLastError del objeto Server. La funcin de este objeto es la de ofrecer de forma detallada toda la informacin disponible del ltimo error que se ha producido. El objeto ASPError nicamente dispone de una serie de propiedades de slo lectura, que contienen la informacin relativa al ltimo error que se ha producido. Estas propiedades se comentan de forma breve en la Tabla 1.
Descripcin Un entero generado por IIS. Una cadena que es una descripcin detallada del error si est relacionado con ASP. Cadena que indica si se trata de una error interno de ASP, del lenguaje de secuencia de comandos o de un objeto. Entero que indica la posicin de la columna del archivo ASP que gener el error. Breve descripcin del error. Nombre del archivo ASP que se estaba procesando cuando se produjo el error. Lnea del archivo ASP que gener el error. Cdigo de error estndar de COM. Devuelve el cdigo fuente real, si est disponible, de la lnea que caus el error.
Tabla 1
Category
Column
24
Grupo EIDOS
1. Introduccin a ASP
En el Cdigo fuente 11 se muestra un sencillo cdigo de ejemplo que hace uso del objeto ASPError, y que podra pertenecer a una pgina de error personalizada de IIS 5.0. Primero se obtiene una referencia al objeto ASPError mediante el mtodo GetLastError del objeto Server, y a continuacin 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> Cdigo de error ASP: <i><b><%=objASPError.ASPCode%></b></i><br> Nmero de error: <i><b><%=objASPError.Number%></b></i><br> Cdigo fuente que lo ha producido: <i><b><%=Server.HTMLEncode(objASPError.Source)%></b></i><br> Categora del error: <i><b><%=objASPError.Category%></b></i><br> Fichero en el que se producido el error: <i><b><%=objASPError.File%></b></i><br> Lnea y columna en la que se ha producido el error: <i><b><%=objASPError.Line%>, <%=objASPError.Column%></b></i><br> Descripcin del error: <i><b><%=objASPError.Description%></b></i><br> </body> </html> Cdigo fuente 11
Un ejemplo de la ejecucin del cdigo 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
25
Grupo EIDOS
Es importante sealar 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 annimo, el componente de registro de IIS no funcionar correctamente. Para manipular los ficheros de registro de IIS el componente IISLog ofrece una serie de mtodos que se muestran en la Tabla 2.
Descripcin Indica si se leyeron o no todos los registros del archivo. Cierra todos los archivos de registro abiertos. Abre un archivo de registro para lectura o escritura. Filtra los registros del archivo segn la fecha y la hora. Lee el siguiente registro disponible del archivo de registro actual. Escribe un registro en el archivo actual.
Tabla 2
26
Grupo EIDOS
1. Introduccin a ASP
Para obtener la informacin del registro actual el componente IISLog ofrece veinte propiedades de slo lectura, como se muestra en la Tabla 3, que se corresponden con los distintos campos de un registro de un archivo de registro.
Descripcin Nmero de bytes recibidos del navegador como una peticin. Nmero de bytes enviados al navegador como una respuesta. Direccin IP del cliente. Indica los contenidos de cualquier cookie enviada en la peticin. Un vector de cabeceras personalizadas que se aadieron a la peticin. La fecha y hora de la peticin en formato GMT. El tipo de operacin, tal como puede ser GET o POST. El mensaje de estado devuelto al cliente, por ejemplo 200 OK.
ProtocolVersion Una cadena con la versin del protocolo utilizado, por ejemplo HTTP/1.1. Referer ServerIP ServerName ServerPort ServiceName La URL de la pgina que contiene el enlace que inici la peticin, si est disponible. La direccin IP del servidor Web. El nombre del servidor Web. El nmero de puerto por el que se recibi la peticin. Nombre del servicio, como puede ser el servicio FTP (MSFTPSVC) o Web (W3SVC). El tiempo de procesamiento total para devolver y crear la pgina devuelta. Cualquier parmetro aadido a la cadena de consulta (QueryString) de la URL en la peticin.
TimeTaken URIQuery
27
Grupo EIDOS
La URL que demand el cliente. La cadena de agente de usuario (tipo de navegador) enviada por el cliente. Nombre de inicio de sesin del usuario si no ha accedido de forma annima. Cdigo de estado Win32 despus de haber procesado la peticin.
Tabla 3
Se puede configurar el tipo de registro que queremos en nuestro servidor a travs de IIS 5.0, de esta forma podremos aadir o eliminar de nuestro fichero de registro los campos descritos anteriormente. Para ello acudiremos a las propiedades del sitio Web y en la pestaa sitio Web pulsaremos el botn Propiedades contenido en el epgrafe 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 opcin registro ODBC no sera vlida.
Figura 5
28
Grupo EIDOS
1. Introduccin a ASP
En el Cdigo fuente 13 se muestra la utilizacin de este nuevo objeto ActiveX de servidor. En este sencillo cdigo 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,0 objRegistro.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>Mtodo</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> <%Wend objRegistro.CloseLogFiles(ForReading)%> </body> </html> Cdigo fuente 13
Se ha utilizado un filtro para recuperar la informacin del fichero de registro referente al servicio Web y nicamente de las ltimas 24 horas. Tambin se puede observar que se utiliza una directiva METADATA, ms tarde comentaremos su utilidad y sintaxis, de momento diremos nicamente que nos permite incluir las constantes definidas en la librera que contiene al componente de registro. La informacin que se va a mostrar del fichero de registro va a ser la fecha y hora de la peticin, la direccin IP del cliente que ha realizado la peticin, el mtodo que se ha utilizado y la URL correspondiente. En la Figura 6 se puede ver un ejemplo de ejecucin de la pgina anterior. El nombre del fichero de registro variar segn sea nuestra configuracin del registro en el sitio Web correspondiente, la ubicacin de estos ficheros de registro suele ser el directorio C:\WINNT \SYSTEM32\LOGFILES\W3SVc1 para el servicio Web. Esta pgina ASP que utiliza el componente de registro se puede utilizar nicamente restringiendo el acceso annimo a la propia pgina 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.
29
Grupo EIDOS
Figura 6
Descripcin Las aplicaciones ASP se ejecutan todas en el mismo espacio de memoria que el servidor Web IIS 5.0. Si una aplicacin ASP falla afectar a todo el servidor Web, poniendo en peligro la ejecucin de la aplicacion InetInfo.exe, que es el ejecutable del servidor Web. Ofrece la ejecucin ms rpida y eficiente de las aplicaciones ASP, pero tambines la que ofrece ms riesgos.
30
Grupo EIDOS
1. Introduccin a ASP
Media (agrupada)
Esta es la proteccin 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 aplicacin ASP no afecta al servidor Web, pero s a resto de las aplicaciones ASP. Cada aplicacin ASP se ejecuta en un espacio de memoria distinto, es decir, cada aplicacin se ejecuta en una instancia distinta y exclusiva del ejecutable DLLHost.exe. De esta forma si una aplicacin 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 ms de diez aplicaciones aisladas. Este tipo de proteccin es recomendable para aplicaciones ASP de alto riesgo o crticas.
Tabla 4
Alta (aislada)
Por defecto el sitio Web predeterminado se define como una aplicacin ASP agrupada o con grado de proteccin medio, este es el modo de proteccin de la aplicacin ms usual y recomendable, ya que ofrece una buena relacin en lo que a rendimiento y seguridad se refiere, con el grado de proteccin alto comprometemos el rendimiento y con el grado de proteccin bajo se compromete la seguridad del funcionamiento del servidor Web. En la Figura 7 se puede ver la forma de configurar el grado de proteccin de una aplicacin.
Figura 7
31
Grupo EIDOS
Otros cambios
En la versin anterior de ASP si necesitbamos utilizar las constantes definidas en una librera de componentes, como puede ser ADO, tenamos que incluir un fichero con la definicin de dichas constantes mediante la tambin conocida directiva INCLUDE de ASP, en el caso de ADO se trataba del famoso fichero ADOVBS.INC. Pero con ASP 3.0 esta situacin ha cambiado, podemos incluir las constantes definidas en una librera de forma directa desde la propia librera, sin tener que crear un fichero de definicin de constantes diferenciado. Para incluir una referencia a una librera un componentes utilizamos la nueva directiva METADATA, cuya sintaxis se muestra en el Cdigo fuente 14.
<!-- METADATA TYPE="TypeLib" FILE="camino y nombre del fichero" UUID="identificador de la librera" VERSION="numVersionMayor.numVersionMenor" LCID="identificador de localizacin" --> Cdigo fuente 14
Las propiedades que son obligatorias son FILE o UUID, siempre deberemos indicar uno u otro para identificar la librera, 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 Cdigo fuente 15.
Se debe sealar que o bien podemos utilizar la directiva METADATA en cada una de las pginas ASP en las que necesitemos incluir las constantes o tambin se puede incluir en el fichero GLOBAL.ASA y de esta forma estar disponible la definicin de constantes y la referencia a la librera para todas las pginas de la aplicacin ASP. Como curiosidad hago notar que le nombre de la librera de ADO sigue siendo MSADO15.DLL cuando lgicamente debera ser MSADO25.DLL, ya que ya nos encontramos en la versin 2.5 de ADO, aunque de todas formas esta librera contiene la ltima versin de ADO. Para incluir archivos en nuestras pginas ASP ya hemos visto que utilizamos la directiva INCLUDE, pero en ASP 3.0 hay otra alternativa que es la utilizacin de la etiqueta <SCRIPT> como muestra el Cdigo fuente 16.
<SCRIPT RUNAT="SERVER" SRC="ruta relativa, fsica o virtual al fichero de scrip"></SCRIPT> Cdigo fuente 16
32
Grupo EIDOS
1. Introduccin a ASP
El fichero que incluimos, a diferencia de la directiva INCLUDE, nicamente puede contener secuencias de comandos, no puede contener texto ni cdigo HTML, adems no debe existir ningn elemento entre las etiquetas <SCRIPT></SCRIPT>. Si un usuario accede a un sitio Web indicando nicamente el nombre del mismo, sin indicar ninguna pgina, se enviar al usuario el documento o pgina por defecto. Sin embargo, si se aada una cadena de consulta (QueryString) a esta URL en la versin anterior de ASP esta cadena era ignorada. Pero ahora con ASP 3.0 y combinacin con IIS 5 la cadena de consulta si es considerada por la pgina 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 pgina predeterminada del sitio Web del Grupo EIDOS.
33
Grupo EIDOS
Los objetos integrados adems de poseer mtodos y propiedades, tambin ofrecen colecciones. Una coleccin es un grupo de objetos del mismo tipo. Un objeto y una coleccin son ambos contenedores, pero de distinto tipo. Un objeto contendr cero o ms colecciones de diferente tipo, mientras que una coleccin contendr cero o ms 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 coleccin Form, esta coleccin contiene informacin 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 informacin variada pero las colecciones no. La mayora de los objetos integrados de ASP proporcionan colecciones. Una coleccin es una estructura de datos, similar a una matriz, que almacena cadenas, nmeros, objetos y otros valores. A diferencia de las matrices, las colecciones se amplan y reducen automticamente al recuperar o almacenar elementos. La posicin de un elemento tambin cambia al modificar la coleccin. Es posible tener acceso a un elemento de una coleccin por su clave de cadena nica, por su ndice (posicin) en la coleccin o si se iteran todos los elementos de la coleccin. El acceso a las colecciones, su sintaxis y utilizacin la veremos segn vayamos avanzando en el temario con distintos ejemplos. Todas las colecciones ofrecen una serie de mtodos comunes a todas ellas y son los siguientes: Count: devuelve nmero de elementos contenidos en la coleccin. Item: devuelve el elemento que se corresponde con el ndice o cadena clave que se pasa por parmetro. Key: devuelve el nombre de una clave dado su ndice.
Las colecciones que no son slo de lectura, sino tambin de escritura, permiten adems los mtodos: Remove: elimina un elemento determinado de la coleccin, del que indicamos su clave o ndice. La coleccin debe ser de escritura. RemoveAll: elimina todos los elementos presentes en una coleccin. Al igual que el mtodo anterior requiere que la coleccin 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 asignrselo 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 ejecucin la aplicacin ASP.
El objeto Response
Este objeto integrado en el modelo de objetos de ASP tiene la funcin de enviar datos al cliente, es decir, al navegador que ha cargado la pgina ASP. A travs de este objeto podremos escribir en la pgina que visualizar el usuario e incluso podremos redirigir al usuario a otra direccin en Internet. Tambin 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 peticin.
36
Grupo EIDOS
Por lo tanto el uso de cookies nos puede permite personalizar las pginas ASP segn 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 pgina su color favorito o tambin podremos indicarle el nmero 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 ocasin 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 informacin ha quedado almacenada en la cookie. Esta informacin se almacena fsicamente 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 aplicacin ASP: Las cookies se pueden perder, por lo tanto nunca se debe depender de las cookies para almacenar una informacin que no se pueda volver a generar. Este tipo de informacin se debera 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 daar, ser borrados o sobreescritos. Las cookies pueden ser modificadas por el cliente, por lo tanto nunca se debe considerar que la informacin ofrecida por una cookie es autntica. Si estamos usando una cookie para determinar la fecha de la ltima vez que un usuario visit nuestro sitio Web podemos considerar como autntica esta informacin sin ningn problema, pero sin embargo no es nada recomendable considerar autntica una cookie que posee el nmero de cuenta de un usuario. Como regla general nunca se debe utilizar una cookie para almacenar informacin
37
Grupo EIDOS
confidencial, este tipo de informacin se debera almacenar en una base de datos en el servidor Web. Las cookies pueden ser copiadas sin el consentimiento del propietario, nunca se debera utilizar una cookie para identificar a un usuario, una solucin mejor es utilizar una contrasea y validarla con una base de datos del servidor. Algunos navegadores no reconocen las cookies. Incluso los ms populares como el Internet Explorer y el Communicator, se pueden configurar para no utilizar cookies.
Se debe sealar que ASP para mantener estados, es decir, valores de variables, objetos..., entre diferentes pginas de una aplicacin 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 utilizacin lgica de las cookies, todo ello gracias a los objetos Session y Application que las gestionan internamente (estos dos objetos los trataremos en los captulos correspondientes). As por ejemplo, cuando se inicia una sesin 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 aplicacin ASP no podr mantener el estado entre diferentes pginas. Si tenemos configurado nuestro navegador para que nos avise cuando recibe una cookie, al iniciar una sesin con una aplicacin ASP aparecer una ventana similar a la que se muestra en la Figura 8.
Figura 8
La coleccin Cookies tambin aparece en el objeto Request, pero en el objeto Request la coleccin es slo de lectura, mientras que en el objeto Response es slo de escritura. De esta forma en el objeto Response la coleccin Cookies ser utilizada para crear las cookies o para modificar su valor, y en el objeto Request para recuperar el valor de las cookies.
38
Grupo EIDOS
Para crear una cookie se utiliza la sintaxis del Cdigo 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 parmetro 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: slo de escritura, indica la fecha en la que caduca la cookie. Si no se especifica ningn valor, por defecto caduca cuando termina la sesin. Domain: slo 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: slo 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 pgina ASP que gener la cookie. Secure: slo de escritura, para indicar si la cookie es segura. HasKeys: slo 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 debera escribir lo que indica el Cdigo fuente 18.
<% Response.Cookies("datosPersonales").Expires= #December 31, 2001# Response.Cookies("datosPersonales")("nombre")="Angel" Response.Cookies("datosPersonales")("apellidos")="Esteban Nez" Response.Cookies("datosPersonales")("edad")=25 %> Cdigo fuente 18
En el caso de que se quiera eliminar una cookie que ya exista, basta con cambiar el valor de su propiedad Expires, asignndole una fecha anterior a la actual. Las cookies se envan desde el servidor al navegador del cliente como un encabezado del protocolo HTTP.
39
Grupo EIDOS
El objeto Response posee las siguientes propiedades: Buffer: indica si los datos de la pgina se almacenan en un bfer. ContentType: especifica el tipo de contenido HTTP de la respuesta. Expires: especifica el intervalo de tiempo que debe transcurrir para que caduque una pgina 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 pgina en la cach del navegador. Status: valor de la lnea 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 pgina ASP. CharSet: indicar el juego de caracteres que est utilizando la pgina ASP. PICS: mediante esta propiedad indicaremos el tipo de contenido que posee nuestra pgina ASP. IsClientConnected: propiedad de slo lectura con la que podremos averiguar si el cliente se ha desconectado del servidor.
Si utilizamos la propiedad Buffer del objeto Response asignndole 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 bfer no es enviado al navegador hasta que no se haya terminado de procesar la pgina o hasta que los mtodos End o Flush del objeto Response no son invocados. Una vez activado el almacenamiento en bfer, 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 ningn valor de las propiedades del objeto Response.As por ejemplo el Cdigo fuente 19 generara un error.
El error devuelto por el navegador sera similar a Los encabezados HTTP ya estn escritos en el explorador cliente. Cualquier cambio en el encabezado HTTP se debe hacer antes de escribir el contenido de la pgina. En las versiones anteriores de ASP la propiedad Buffer tena por defecto la propiedad False, de esta forma segn se iba procesando la pgina ASP se enviaba el resultado de la ejecucin al cliente. Segn Microsoft con este cambio se obtiene un mejor rendimiento en la ejecucin de pginas ASP. En realidad lo que se tiene tambin es un mayor control sobre la salida que va a recibir el usuario.
40
Grupo EIDOS
El uso de este bfer puede ser til en el caso de que sea necesario procesar el contenido de una pgina ASP antes de enviar ningn contenido previo al navegador del cliente. De esta forma se puede redireccionar al navegador hacia otra pgina con el mtodo Redirect del objeto Response, este mtodo se comentar en su apartado correspondiente, pero se puede adelantar que una llamada a este mtodo producir un error en el caso de que se haya enviado anteriormente algn contenido al usuario. La propiedad Buffer tambin puede ser utilizada para verificar errores antes de enviar informacin al navegador, de esta forma si se detecta un error se puede detener el proceso de la pgina y redireccionar al navegador del cliente hacia una pgina determinada. Cuando la propiedad Buffer, tiene su valor por defecto, es decir, el valor True se pueden utilizar una serie de mtodos del objeto Response, estos mtodos, cuya funcin se ver en el apartado correspondiente, son: Clear, End y Flush y bsicamente lo que permiten es controlar el resultado o salida que se le enva al cliente.
Los mtodos 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 bfer existen varias formas de enviar la informacin del bfer al navegador del cliente:
41
Grupo EIDOS
Llamando al mtodo Flush. Llamando al mtodo End. De esta forma tambin se detiene la ejecucin de la pgina ASP. Cuando finaliza le ejecucin de la pgina ASP, es decir, cuando se ejecuta la ltima lnea de las secuencias de comandos de servidor.
El mtodo Clear se utiliza cuando se quiere eliminar todo el contenido que posee el bfer, 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 Cdigo fuente 20 producira un error.
<HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> </HEAD> <BODY> <b>Esto es contenido</b> <%Response.Flush Response.Clear Response.Redirect "pruebas.asp"%> </BODY> </HTML> Cdigo fuente 20
La utilizacin de estos mtodos junto con la propiedad Buffer nos permite controlar el procesamiento de la pgina ASP de una forma muy sencilla y eficaz. Para mostrar el uso de estos mtodos junto con el almacenamiento en bfer vamos a ver un sencillo ejemplo, en el Cdigo 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 pausa For j=1 To 100000 Next Response.Write Mid(strTexto,i,1) 'se enva el contenido del bfer Response.Flush Next%> Cdigo fuente 21
El efecto de este cdigo es que se va enviando el texto caracter a caracter mediante el mtodo Flush, para que se produzca una pausa se realiza un bucle For adicional. Si situamos la sentencia Response.Flush al final del cdigo, 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 funcin de este mtodo del objeto Response. Pero tambin para escribir se han utilizado los delimitadores <%=%>. Estos delimitadores son equivalentes a escribir Response.Write, se pueden considerar como su abreviatura. El mtodo
42
Grupo EIDOS
Response.Write se utilizar dentro de una bloque de script de servidor, es decir, un bloque de cdigo encerrado por los delimitadores <%%>, y el uso de los delimitadores <%=%> ser adecuado cuando se necesite intercalar una lnea aislada entre cdigo HTML: Como ya se ha visto, el mtodo Write se puede utilizar para escribir texto en el navegador. Las llamadas a mtodos y las variables dentro del mtodo Write sern evaluadas y slo el resultado se escribir en el navegador del cliente. Por ejemplo, el Cdigo fuente 22 mostrar el valor de la variable contador en el navegador del cliente.
<%Response.Write("La variable contador contiene el valor: " & contador)%> Cdigo fuente 22
El uso de parntesis en el mtodo Write es opcional. Si tenemos en cuenta los delimitadores <%=%>, de forma equivalente podramos haber escrito lo que se muestra en el Cdigo fuente 23 o en el Cdigo fuente 24.
Si en nuestro cdigo tenemos diferentes lneas con los delimitadores <%=%> intercaladas dentro de cdigo HTML, para una mayor eficiencia es recomendable sustituirlos por una nica lnea mediante Response.Write. Adems se consigue un cdigo ms legible, se debe tender a bloques de HTML y de script de servidor bien diferenciados, siempre que sea posible. El mtodo Redirect recibe como parmetro una cadena de texto en forma de URL que especifica la nueva direccin 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 mtodo Redirect en realidad lo que estamos haciendo es enviar una cabecera HTTP al navegador Web del cliente para indicarle que la pgina se ha movido y le indicamos la nueva localizacin, que es la URL que hemos indicado al mtodo Redirect. La informacin que se enva al navegador es HTTP/1.1 Object Moved Location /directorio/pagina.asp. Como se puede observar la redireccin se realiza en el cliente, indicndole que la pgina se ha movido a una nueva direccin, que en realidad es otra pgina completamente distinta. Aqu nos hemos centrado en redireccionar el navegador a otra pgina (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.
43
Grupo EIDOS
El objeto Request
Este objeto integrado es utilizado para obtener informacin del usuario, por lo tanto realiza las funciones contrarias al objeto Response. Cuando un navegador cliente se comunica con el servidor Web a travs del protocolo HTTP, el navegador manda un gran nmero de informacin adems de la pgina que se quiere cargar, esta informacin puede ser: variables de entorno, informacin sobre certificados, cookies, formularios, etc. Toda esta informacin es codificada y enviada a travs 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 informacin a travs del objeto Request y sus diferentes colecciones. Esta informacin enviada por el navegador, se puede utilizar para: validar un usuario, obtener informacin sobre el usuario el navegador, almacenar informacin para su posterior uso, enviar informacin al servidor a travs de formularios, etc. ASP almacena toda esta informacin en colecciones del objeto Request. Mediante llamadas del tipo Request.coleccin se puede obtener de forma sencilla la informacin que sea necesaria. El objeto Request presenta cinco colecciones que veremos en el siguiente apartado
Para tener acceso a la informacin de las colecciones del objeto Request se puede utilizar la sintaxis general Request.NombreColeccion(variable), donde NombreColeccion es el nombre de la coleccin que se quiere consultar y variable es el nombre de la variable de la coleccin a la que se quiere tener acceso y recuperar su valor. Las variables contenidas en las colecciones del objeto Request son nicamente de lectura. Tambin se puede acceder a una variable de una coleccin sin especificar el nombre de la coleccin (Request(variable)). En este caso se realizar una bsqueda por todas las colecciones del objeto Request hasta que se obtenga la variable deseada. El orden de bsqueda entre las colecciones es el siguiente: QueryString, Form, Cookies, ServerVariables y por ltimo ClientCertificate. Se obtendr la primera variable que coincida con el parmetro variable. Esto no es muy recomendable ya que es ms lento y pueden existir variables con el mismo nombre en distintas colecciones.
44
Grupo EIDOS
Para obtener todos los valores de las variables de una coleccin se puede utilizar la instruccin For Each...in..., el Cdigo fuente 25 muestra como se obtendra el nombre y el valor de cada variable de la coleccin ServerVariables:
<%For each variable in Request.ServerVariables Response.Write("La variable: "&variable&" tiene el valor: "&_ Request.ServerVariables(variable)&"<br>") Next%> Cdigo fuente 25
El objeto Request mediante su coleccin Form permite acceder a los datos enviados a travs de un formulario mediante el mtodo POST. Para obtener los datos de un formulario, que por ejemplo tuviera los campos Nombre y Edad, se debera escribir el Cdigo fuente 26 dentro de la pgina ASP llamada PROCESAINFO.ASP.
Si se quiere obtener los datos sin decodificar bastara con escribir el Cdigo fuente 27.
En el navegador aparecera lo siguiente: Datos: nombre=Pepe&edad=30&boton=Enviar. Se puede observar que adems de los campos de texto del formulario tambin se enva el botn 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 informacin se deber utilizar un ndice. Por ejemplo si tenemos el formulario del Cdigo 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> Cdigo fuente 28
45
Grupo EIDOS
Para poder recuperar la informacin enviada se debera tratar como un array, y se realizara de la forma que se indica en el Cdigo fuente 29.
Como se puede observar los ndices comienzan en 1, y para saber el nmero de elementos del array se utiliza el mtodo Count que devuelve el nmero de elementos de un array. Las pginas ASP se pueden utilizar para recoger y procesar valores de formularios HTML de varias maneras: Un archivo htm o html esttico puede contener un formulario que enve sus valores a una pgina ASP, como ha sido el caso de los ejemplos anteriores. Una pgina ASP puede contener un formulario que enve informacin a otra pgina ASP. Una pgina ASP puede contener un formulario que enve informacin as misma, es decir, a la pgina ASP que contiene el formulario.
La ltima opcin es la ms potente y la ms recomendable, de esta forma una pgina ASP se llama as misma. Para poder utilizar esta estrategia lo que se debe tener en cuenta es si la pgina 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 pgina y por lo tanto se validarn o mostrarn los datos; y si no existe, la pgina se est cargando por primera vez y se mostrar el formulario. En el Cdigo fuente 30 de ejemplo se puede observar esta tcnica.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <HEAD> <TITLE>Misma pgina 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> Cdigo fuente 30
46
Grupo EIDOS
En este caso se pregunta por el valor del botn de envo, ya que siempre que se enve el formularo se enviar tambin el botn de tipo submit. Adems se supone el cdigo mostrado pertenece a una pgina ASP llamada mismaPagina.asp tal como se indica en la propiedad ACTION de la etiqueta <FORM>. Si cargamos por primera vez esta pgina pasaremos por la rama de la instruccin Else y veramos el formulario en el navegador. Una vez cargada la pgina, si rellenamos los campos de texto y pulsamos sobre el botn etiquetado como Enviar, pasaramos por el primer bloque del If, ya que la pgina ASP se volvera a cargar as misma y la variable botonEnviar de la coleccin Form ya contendra un valor. Como se puede observar da la impresin que son dos pginas distintas, pero en realidad es la misma pgina ASP que genera diferente cdigo HTML segn la ejecucin del script de servidor. Para obtener los valores de un formulario que se ha enviado con el mtodo GET o para recuperar los valores de una cadena de consulta de un enlace, utilizaremos esta otra coleccin del objeto Request: QueryString. Todo lo visto para la coleccin Form es vlido para la coleccin QueryString. La nica diferencia es que los datos aparecen visibles en la barra de direcciones del navegador y existe un tamao mximo de 1024K. La decisin de utilizar una coleccin u otra depende del tamao de los datos a enviar y del nmero de ellos. Cuando el tamao es mayor de 1024K slo tendremos la opcin de usar la coleccin Form. Yo personalmente sigo la siguiente regla, para los formularios de HTML siempre utilizao el mtodo de envo POST y por lo tanto para recuperar los valores de los campos utilizo Form, y la coleccin 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 ningn problema que el usuario modifique la cadena de consulta.
47
Grupo EIDOS
En este punto se debe sealar que una variable en una aplicacin ASP puede tener cuatro mbitos diferentes, se va a ir del ms global al ms particular. La creacin de una variable con un mbito u otro depender del uso que queramos hacer de ella. mbito de aplicacin: esta variable la podrn manipular todos los usuarios de la aplicacin ASP, es comn a todos ellos. Se almacena dentro del objeto Application. mbito de sesin: las variables con este mbito son propias de cada uno de los usuarios de la aplicacin, es decir, cada usuario tendr acceso a las variables de su sesin. Estas variables se almacenan dentro del objeto integrado Session. mbito de pgina: estas variables son las que se crean dentro del script de servidor de una pgina ASP, slo tienen vigencia dentro de la pgina en la que se declararon, al abandonar la pgina se destruirn. mbito de procedimiento: a este mbito pertenecen las variables declaradas dentro de un procedimiento (Sub o Function). Estas variables slo existirn 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 aplicacin se debe utilizar la sintaxis del Cdigo fuente 31.
Tambin 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 continuacin. En cuanto a tipos de variable se refiere, una variable de aplicacin 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 aplicacin, a excepcin de los objetos del modelo de objetos de ASP (ASPError, Request, Server, Response, Application, Session, ObjectConext) de esta forma la instruccin del Cdigo fuente 32 generara un error.
Si almacenamos una variable array a nivel de aplicacin, para modificar sus valores no podremos hacerlo directamente, sino que se debe hacer a travs de una variable auxiliar, que ser la que se modificar y luego asignar a la variable de aplicacin correspondiente. En el Cdigo fuente 33 se muestra la utilizacin de una variable de aplicacin que es un array de cadenas.
50
Grupo EIDOS
vector(2)="Tercero" vector(3)="Ultimo Valor" Application("valores")=vector '---'---'Para modificar los valores recuperamos la variable vectorAux=Application("valores") vectorAux(2)="Elemento modificado" Application("valores")=vectorAux For i=0 to UBound(Application("valores")) Response.Write "Application('valores')("&i&")="&Application("valores")(i)&"<br>" Next%> Cdigo fuente 33
Sin embargo los valores de cada elemento de array si que se pueden recuperar directamente de la variable de aplicacin. No es recomendable almacenar objetos a nivel de aplicacin, ya que esto supone que el objeto va a existir durante toda la vida de la aplicacin ASP y puede ser accedido por distintos usuarios de manera concurrente. Lo ideal para almacenar en variables de aplicacin son variables de tipo entero, booleano o cadenas de caracteres.
Ambas colecciones nos van a permitir recuperar o acceder a las variables y objetos creados a nivel de aplicacin, aunque ya hemos visto en el apartado anterior que podemos acceder directamente a ellos. La coleccin Contents contiene todos los objetos y variables creados a nivel de aplicacin, excluyendo aquellos objetos que han sido creados utilizando la etiqueta de HTML <OBJECT>. Esta etiqueta se utiliza para la creacin de objetos, de todas formas veremos con detalle el uso de la etiqueta <OBJECT> en este mismo apartado a la hora de comentar la coleccin StaticObjects. En esta coleccin se incluirn, por tanto, los objetos creados a nivel de aplicacin con la sentencia Server.CreateObject y las variables creadas con Application("variable")=valor. La coleccin Contents del objeto Application permite utilizar un par de mtodos que son comunes a todas las colecciones de escritura y que son los siguientes: RemoveAll: elimina todas las variables de aplicacin, a excepcin de las creadas con la etiqueta <OBJECT>. Este mtodo carece de parmetros. Remove: elimina una variable de aplicacin determinada que est contenida en la coleccin Contents. Este mtodo recibe por parmetro el ndice o nombre de la variable correspondiente.
51
Grupo EIDOS
La coleccin StaticObjects contiene todos los objetos a nivel de aplicacin que se han creado mediante la etiqueta <OBJECT>, por lo tanto la coleccin StaticObjects nicamente contendr variables que son referencias a objetos. De la misma forma que veamos en el ejemplo anterior, podremos recorrer la coleccin StaticObjects para acceder a los objetos estticos creados a nivel de aplicacin. 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 coleccin StaticObjects no ofrece ningn mtodo como los de la coleccin Contents, nicamente ofrece los mtodos 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.
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 mtodo Lock y la correspondiente llamada a UnLock, ya que las variables del objeto Application podran quedar bloqueadas demasiado tiempo afectando de esta forma al correcto funcionamiento de la aplicacin ASP correspondiente. Lock y UnLock se utilizarn normalmente en el momento en el que se vaya a modificar el valor de una variable de aplicacin.
52
Grupo EIDOS
Nunca se debe olvidar el corresponder cada llamada Lock con una llamada UnLock, ya que podramos caer en el error de dejar bloqueada las variables de la aplicacin de forma indefinida.
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 Cdigo fuente 35.
53
Grupo EIDOS
<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> Cdigo fuente 35
Si se escribe script fuera de las etiquetas <SCRIPT></SCRIPT> o se declara un objeto que no tiene mbito de sesin o de aplicacin se producir un error. Tampoco se pueden incluir ficheros de ningn 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 tambin se debe indicar en que lugar se ejecutar el script, esto se consigue a travs del atributo RUNAT de la etiqueta <SCRIPT>, en realidad este atributo slo 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 sesin o aplicacin se deber seguir la sintaxis del Cdigo fuente 36.
La declaracin de los objetos deber ir fuera de las etiquetas de script. Los objetos declarados de esta forma no se crearn hasta que el servidor procese una secuencia de comandos en el que se haga referencia a ellos. As se ahorran recursos, al crearse slo los objetos que son necesarios. Estos objetos pasaran a formar parte de la coleccin StaticObjects del objeto Application. El parmetro 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 ms, adems de los de sesin y de aplicacin, y se trata del mbito de pgina SCOPE="PAGE". El mbito de pgina indica que el objeto que se instancie slo existir en el pgina actual, pero este mbito no se puede
54
Grupo EIDOS
utilizar en el fichero global.asa sino que se puede utilizar en cualquier pgina ASP. Sin embargo en las pginas ASP no se puede utilizar la etiqueta <OBJECT> con el mbito de aplicacin o de sesin, nicamente se pueden instanciar objetos con mbito de pgina. El Cdigo fuente 37 dentro del fichero global.asa creara un objeto Connection de ADO con mbito de sesin.
Para utilizar este objeto posteriormente dentro de una pgina ASP, por ejemplo, para ejecutar una sentencia SQL sobre la conexin con la base de datos, bastara con escribir la lnea del Cdigo 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 aplicacin ASP y pide una sesin, es decir, carga la primera pgina de la aplicacin ASP. Cuando se crea el objeto Application, el servidor busca el fichero GLOBAL.ASA en el directorio raz de esa aplicacin ASP, si el fichero existe se ejecuta el script del evento Application_OnStart. A continuacin se crea el objeto Session. La creacin 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 pgina indicada por la peticin del navegador cliente. Cuando el objeto Session caduca o se lanza el mtodo Session.Abandon, se ejecutar el script que se corresponde con el evento Session_OnEnd, el cdigo de este evento se procesar antes de destruir la sesin. Cuando finaliza la ltima sesin de los usuarios, es decir, se ejecuta el cdigo 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 ms peticiones hasta que no se procese el evento Application_OnEnd. Los usuarios que se intenten conectar durante este proceso recibirn un mensaje que le indica que la peticin no puede ser procesada mientras la aplicacin es reiniciada. Durante este proceso se dan los siguientes pasos: Las sesiones activas se destruyen, dando lugar al procesamiento del evento Session_OnEnd. La aplicacin se destruye, producindose el evento Application_OnEnd.
55
Grupo EIDOS
La primera peticin reiniciar el objeto Application y crear un nuevo objeto Session, es decir, se darn los eventos Application_OnStart y Session_OnStart, respectivamente.
Tambin se ejecutar la el evento Application_OnEnd cuando se descargue la aplicacin ASP desde el Administrador de servicios de Internet o cuando se apague el servidor Web.
El objeto Session
Al igual que ocurra con el objeto Application, el objeto Session nos va a permitir almacenar informacin entre diferentes pginas ASP incluidas en una misma aplicacin ASP. La diferencia con el objeto Application se encuentra en el mbito de las variables, cada variable del objeto Session es particular a una sesin de un usuario determinado, no a toda la aplicacin. 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 sesin, cada usuario tiene su espacio de almacenamiento. Las variables de aplicacin son valores globales y comunes a toda la aplicacin, y las variables de sesin son particulares para cada usuario de la aplicacin. El servidor Web crea automticamente un objeto Session, cuando un usuario que an no estableci una sesin solicita una pgina ASP perteneciente a la aplicacin ASP actual. El servidor Web sabe si un navegador tiene ya una sesin debido a que la cookie ASPSESSIONID es enviada junto con la peticin de la pgina ASP. Un uso comn del objeto Session es almacenar las preferencias del usuario o informacin personal. Se debe sealar que se podrn almacenar variables dentro del objeto Session si el navegador acepta cookies, ya que el objeto Session para almacenar informacin se basa en la cookie ASPSESSIONID. Aunque la utilizacin de esta cookie es completamente transparente para el programador. Para una aplicacin ASP tendremos tantas sesiones como usuarios conectados a la aplicacin ASP. Las recomendaciones realizadas para el objeto Application en cuanto a utilizacin de objetos y variables de tipo array, son tambin vlidas para el objeto Session. La sintaxis para manipular variables del objeto Session es la misma que en el objeto Application. El Cdigo fuente 39 crea una variable del objeto Session con el nombre que el usuario facilita en un formulario.
56
Grupo EIDOS
Ambas colecciones nos van a permitir recuperar o acceder a las variables y objetos creados, en este caso, a nivel de sesin. La coleccin Contents contiene todos los objetos y variables creados a nivel de sesin, excluyendo a los objetos que han sido creados utilizando la etiqueta <OBJECT>. En esta coleccin se incluirn, por tanto, los objetos creados a nivel de sesin con Server.CreateObject y las variables creadas con las sentencias del tipo Session("variable"). La coleccin StaticObjects contiene todos los objetos que se han creado mediante la etiqueta <OBJECT> dentro del alcance de la sesin. Si suponemos que tenemos el fichero GLOBAL.ASA que aparece en el Cdigo fuente 40.
<SCRIPT LANGUAGE="VBScript" RUNAT="Server"> Sub Session_OnStart Session("variableUno")="valor" Session("variableDos")=2 Session("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> Cdigo fuente 40
<%@ Language=VBScript %> <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> </HEAD> <BODY> Nmero de elementos de la coleccin Contents: <b><%=Session.Contents.Count%></b><br> <%For Each variable in Session.Contents Response.Write variable & " = "&Session.Contents(variable)&"<br>" Next%> <br> Nmero de elementos de la coleccin StaticObjects: <b><%=Session.StaticObjects.Count%></b><br> <%For Each objeto in Session.StaticObjects Response.Write objeto&"<br>" Next%> <br> <%'accedemos la variable de aplicacin definida con <OBJECT> conex.Open "DSN=BD;UID=sa;PWD=" Response.Write "Base de datos predeterminada: "&conex.DefaultDatabase conex.Close%> </BODY> </HTML> Cdigo fuente 41
57
Grupo EIDOS
Se producir este resultado: Nmero de elementos de la coleccin Contents: 3 variableUno = valor variableDos = 2 variableTres = Verdadero Nmero de elementos de la coleccin StaticObjects: 2 conex recordset Base de datos predeterminada: Cursos
Las ltimas dos propiedades han sido incluidas con la versin 2.0 de ASP. Se puede configurar si queremos utilizar el estado de sesin o no, mediante el Administrador de servicios de Internet. Pulsamos sobre la aplicacin con el botn derecho del ratn y seleccionamos la opcin de men propiedades, aparecern las hojas de propiedades del directorio como se ve en la Figura 9.
58
Grupo EIDOS
Figura 9
En el epgrafe denominado configuracin de aplicacin podemos observar un botn etiquetado como Configuracin, si lo pulsamos aparece una nueva ventana de la que elegiremos la pestaa etiquetada como opciones de aplicacin. Ver Figura 10. Desde esta hoja de propiedades podemos configurar algunos parmetros de nuestra aplicacin ASP, entre ellos el que nos interesa, es decir, la posibilidad de habilitar o deshabilitar el estado de la sesin.
Figura 10
59
Grupo EIDOS
Adems podemos configurar la propiedad Timeout de la sesin y el lenguaje del intrprete de comandos por defecto. Tambin podemos habilitar o deshabilitar el almacenamiento en bfer. Los valores que especifiquemos en esta pantalla se pueden sobreescribir desde el cdigo ASP indicando los valores de las propiedades o directivas de procesamiento correspondientes
60
Grupo EIDOS
En el evento Session_OnEnd slo estn disponibles los objetos Application, Server y Session, y tampoco se puede utilizar el mtodo 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 pginas ASP mediante la posibilidad de la creacin y utilizacin de objetos externos y componentes en el lenguaje de secuencias de comandos. El objeto Server est diseado para realizar tareas especficas en el servidor. Adems de la posibilidad de instanciar componentes el objeto Server ofrece una serie de mtodos muy tiles como pueden se los que permiten dar formato URL o HTML a cadenas de caracteres, los que modifican la lnea de ejecucin de un script de una pgina con la posibilidad de ejecutar distintas pginas, y tambin existe un mtodo utilizado para el tratamiento de errores dentro de ASP, etc. Todos estos mtodos los veremos en el presente captulo. En algunas definiciones del objeto Server se suele indicar tambin 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.
61
Grupo EIDOS
Los cuatro ltimos mtodos han sido aadidos en la versin 3.0 de ASP. El mtodo ms utilizado del objeto Server es, posiblemente, el mtodo CreateObject. Este mtodo permite la instanciacin de componentes de servidor, para que a continuacin sean manipulados por las secuencias de comandos de nuestras pginas ASP. Para crear una instancia de un componente de servidor se debe utilizar la sintaxis general del Cdigo fuente 42.
La palabra reservada Set siempre se debe utilizar en la instanciacin 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[.Versin]. 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 asignndole Nothing, con el Cdigo fuente 43.De esta forma se libera la memoria ocupada por el objeto.
62
Grupo EIDOS
Las instancias de un objeto, por defecto, se destruyen cuando la pgina ASP termina de ser procesada, aunque es ms seguro destruirlas mediante la palabra reservada Nothing. Para crear un objeto con mbito de sesin o de aplicacin se debe almacenar el objeto en una variable de sesin o de aplicacin, o bien utilizando la etiqueta de HTML <OBJECT> en el fichero global.asa y asignando al parmetro SCOPE los valores Session o Application, como vimos en el captulo anterior. De esta forma el objeto se destruir cuando haya finalizado la sesin o la aplicacin. No es demasiado recomendable utilizar objetos a nivel de sesin o aplicacin, 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 sesin o de aplicacin. El mtodo MapPath devuelve la ruta fsica que se corresponde con el la ruta virtual que se le pasa por parmetro. El objeto Server posee informacin sobre los directorios fsicos, virtuales y relativos de la mquina servidor y sabe como debe realizar la traduccin de rutas virtuales a fsicas. Se puede necesitar obtener rutas fsicas cuando se quieran crear directorios o manipular ficheros en el servidor. La forma ms frecuente de utilizar este mtodo es la del Cdigo fuente 44, que devuelve la ruta fsica de la carpeta en que se encuentra la pigna ASP en ejecucin.
Se recomienda por eficiencia evitar el uso del mtodo MapPath, cada llamada a este mtodo supone una nueva conexin al servidor Web para que IIS devuelva la ruta actual del servidor. En su lugar es ms rpido utilizar la ruta literal, si se conoce. Cuando tratamos el objeto Response en su captulo correspondiente vimos que presentaba un mtodo llamado Redirect que nos permita pasar a ejecutar una pgina distinta, pero esto supona enviar una respuesta al cliente para indicarle la carga de una nueva pgina, que es la pgina a la que pasamos la ejecucin. La utilizacin del mtodo Redirect es bastante costosa y problemtica ya supone un envo de informacin ms del servidor al cliente para indicarle mediante una cabecera HTTP de redireccin que la pgina ha cambiado de localizacin, siendo la nueva localizacin la pgina que deseamos cargar. Esto es problemtico 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 tambin ocurre cuando la conexin la realiza el cliente a travs de proxy. Pero mediante los mtodos Execute y Transfer podemos evitar esta redireccin, que como hemos visto, tiene lugar en el cliente. Estos dos mtodos permiten que la redireccin tenga lugar en el servidor, quedando el cliente completamente ajeno. Ambos mtodos reciben como parmetro la ruta de la pgina a la que queremos redirigir al cliente.
63
Grupo EIDOS
La utilizacin del mtodo Execute es muy similar a realizar una llamada a un procedimiento o funcin. Cuando lanzamos el mtodo Execute se empieza a ejecutar la pgina que indicamos por parmetro, y cuando termina la ejecucin de esta nueva pgina, el control pasa a la siguiente sentencia despus de la llamada al mtodo Execute en la pgina inicial, siguiendo a partir de aqu con la ejecucin de la pgina, es decir, el navegador del cliente recibe una salida formada por la combinacin de la ejecucin de ambas pginas. El cliente ni siquiera observa la URL correspondiente a la segunda pgina, ya que la redireccin entre pginas se produce en el servidor. El navegador cree que sigue recibiendo todava la pgina original que habia demandado, incluso en la barra de direcciones del navegador sigue apareciendo la misma URL y los botones Atrs y Adelante funcionan correctamente. En ambos mtodos se mantiene el contexto de la pgina inicial, es decir, en la nueva pgina tenemos acceso a los mismos objetos intrnsecos de ASP (Request, Session, Response...) de la pgina inicial o pgina de origen. Es decir, la coleccin Request.Form de la segunda pgina coincide con la de la primera. El mtodo Transfer tambin permite la redireccin entre pginas en el servidor, pero este mtodo se comporta de distinto modo al mtodo Execute, al lanzar este mtodo se pasa la ejecucin a la nueva pgina, pero una vez que finaliza la ejecucin de la misma no se vuelve a la pgina inicial, como ocurra con el mtodo Execute. El mtodo Transfer es bastante ms parecido al mtodo Redirect que lo era el mtodo Execute, ya que con Transfer al igual que con Redirect no se regresa a la pgina original. Con el mtodo Transfer se sigue manteniendo el contexto de la pgina inicial entre las distintas pginas. La nica diferencia es que la ejecucin finaliza cuando termina la ejecucin de la segunda pgina, y no se vuelve a la inicial. Mediante el uso del mtodo GetLastError podemos tener acceso a toda la informacin referente al ltimo error que se ha producido en la pgina ASP actual. Pero es necesario aclarar que su utilizacin no es similar al tratamiento de errores que realizbamos con la sentencia On Error Resume Next y el objeto Err de VBScritp, que preguntbamos por la propiedad Number del objeto Err para averiguar si se haba producido algn error. El mtodo GetLastError se puede utilizar nicamente dentro de una pgina 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 pginas de error personalizadas y es en estas pginas dnde podemos hacer uso de este mtodo. El mtodo 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 informacin referente al error que se ha producido.
El objeto ObjectContext
Este objeto integrado se incluy en la versin 2.0 de las pginas ASP. Este objeto se ofrece gracias a la integracin 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 travs del objeto integrado ObjectConext podremos tratar y gestionar las transacciones que se realicen en nuestras pginas ASP, pudiendo construir, por tanto, pginas ASP transaccionales.
64
Grupo EIDOS
Esta integracin entre el servidor Web y el servidor de transacciones sigue existiendo, pero ahora el servidor Web se encuentra en su nueva versin 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 bsica para la creacin de aplicaciones Web y para coordinar el proceso de transacciones para las aplicaciones ASP transaccionales. A travs del objeto ObjectConext podremos deshacer o llevar a cabo las transacciones gestionadas por los Servicios de componentes. Recordemos que una transaccin es una operacin que se debe realizar de forma completa, es decir, si falla una parte de la transaccin se deben deshacer todos los cambios. Un ejemplo tpico de una transaccin es la transferencia de una cuenta bancaria a otra, las operaciones de que implican restar el capital de una cuenta y aadirlo a otra se deben ejecutar dentro de una transaccin, si falla alguna de las dos se debe devolver al sistema a su estado inicial. Las transacciones ofrecen una serie de caractersticas comunes conocidas como propiedades ACID (Atomicity, Consistency, Isolation, Durability). Para indicar la naturaleza transaccional de una pgina ASP debemos incluir, como primera lnea de la pgina, la directiva de procesamiento TRANSACTION, como en el Cdigo fuente 45.
Donde el argumento valor define el comportamiento transaccional de la pgina ASP actual y puede tomar uno de los siguientes valores: Requires_New: se requiere una nueva transaccin, por lo que siempre se iniciar una nueva transaccin para las pginas ASP con este valor. Esta configuracin es recomendable para pginas que debe realizar transacciones pero que siempre deben estar separadas del resto. Required: se requiere una transaccin, si no hay una iniciada, se iniciar una nueva. La pgina ASP siempre se ejecutar en una transaccin ya sea iniciada por ella misma o bien aprovechando una transaccin ya existente. Supported: soporta transacciones, pero no iniciar ninguna en el caso de que no exista. En algunos casos la pgina ASP se ejecutar en una transaccin y en otros no, ya que slo utiliza transacciones existentes. Not_Supported: no soporta transacciones, es el valor por defecto. La pgina ASP nunca participar en ningn tipo de transaccin. Disabled: se ignorarn los requerimientos transaccionales de la pgina ASP. La diferencia con el caso anterior, es que con Not_Supported la pgina ASP siempre se ejecutar en un nuevo contexto, y con Disabled, si existe un contexto se utilizar el mismo.
A travs del objeto ObjectContext podremos construir pginas ASP transaccionales, pero evidentemente, cuando se realicen operaciones que puedan tener una naturaleza transaccional, como puede ser el acceso a bases de datos. Adems, una transaccin no puede abarcar varias pginas ASP, a no ser que hagamos uso de los mtodos Transfer o Execute del objeto Server, ya comentamos que con
65
Grupo EIDOS
estos mtodos de ejecucin entre pginas se conserva el contexto de la pgina inicial, en este contexto se encuentra incluido las transacciones. Hay que tener en cuenta, adems, que la mayora de las aplicaciones ASP slo requieren hacer uso de un contexto transaccional en determinadas operaciones. As por ejemplo, una aplicacin de una Lnea de Autobuses podra hacer uso de pginas ASP transaccionales para la venta de billetes y la reserva de asientos, dejando el resto de tareas fuera del contexto transaccional.
En el caso de que finalice el procesamiento de la pgina ASP y no se haya realizado ninguna llamada a alguno de los dos mtodos anteriores, se considerar que no se ha producido ningn problema en el procesamiento de la pgina y, por lo tanto, se llamar automticamente al mtodo SetComplete.
El uso de estos dos eventos, nos permitir realizar diferentes tratamientos segn se haya finalizado la transaccin, es decir, si se ha producido con xito , o por el contrario se han producido errores y se ha tenido que deshacer.
66
Grupo EIDOS
El objeto ASPError
Este objeto es le nuevo objeto integrado que aparece en ASP 3.0. La funcin del objeto ASPError es la de ofrecer de forma detallada toda la informacin relativa al ltimo error que se ha producido dentro de una aplicacin ASP, describe el error que se ha producido, la naturaleza y fuente del mismo, y si es posible el cdigo fuente que caus el error. Para ello el objeto ASPError consta de nueve propiedades de slo lectura, y no ofrece ningn mtodo. Una referencia al objeto ASPError la obtenemos a travs de un nuevo mtodo del objeto Server, el mtodo GetLastError que ya comentamos en el captulo correspondiente, la sintaxis de este mtodo es la del Cdigo fuente 46.
Ahora bien, el mtodo GetLastError del objeto Server no se puede utilizar de forma indiscriminada en cualquier lugar de nuestro cdigo para consultar si se ha producido un error, nicamente se puede utilizar de forma satisfactoria dentro de una pgina 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 mtodo GetLastError para obtener una referencia al objeto ASPError, esta llamada fallar y el mtodo no podr acceder a los detalles del error que se ha producido.
Grupo EIDOS
Line: entero que se corresponde con el nmero de lnea del archivo ASP que gener el error. Number: entero que representa un cdigo de error estndar de COM. Tiene el mismo significado que la propiedad Number del objeto Err. Source: cadena que contiene el cdigo fuente real, si est disponible, de la lnea que caus el error.
Como se puede observar podemos obtener una informacin bastante ms precisa que con el objeto Err de VBScript.
68
Componentes de Servidor
Introduccin
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 estn diseados para ejecutarse en el servidor Web como parte de una aplicacin basada en ASP. Estos componentes se denominan componentes ActiveX Server o componentes de servidor, y anteriormente eran conocidos como servidores de automatizacin. Los componentes ActiveX Server se invocan desde pginas ASP (en nuestro caso), pero tambin pueden ser llamados desde otros orgenes, 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 pginas ASP y el servidor Web Internet Information Server. Los componentes ActiveX Server que se encuentran incluidos dentro de ASP en su versin 3.0 y que se van a comentar en este tema son: Componente de acceso a bases de datos, ADO (ActiveX Data Objects). A travs de la utilizacin de este componente se puede ofrecer acceso a bases de datos desde una pgina 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.
Grupo EIDOS
Componente Ad Rotator. Este componente permite mostrar una serie de imgenes alternativas con un vnculo a otra direccin desde la imagen presentada. Este componente se suele utilizar para mostrar diferentes anuncios de forma alternativa dentro de una pgina ASP. Componente Funciones del explorador. A travs de este componentes podemos recuperar datos acerca del tipo de navegador del cliente y que capacidades o funciones tiene. Componente vnculo de contenidos. Facilita el desplazamiento lgico entre las diferentes pginas ASP de una aplicacin ASP. Componente Content Rotator (rotador de contenidos). Este componente permite hacer rotaciones de cadenas de contenido HTML en una pgina. Componente Page Counter (contador de pginas). Permite llevar una cuenta del nmero de veces que se ha accedido a una pgina determinada dentro de nuestro sitio Web. Componente Counters. A travs de este componente podremos almacenar, crear, incrementar y consultar cualquier contador. Componente MyInfo. Nos permite almacenar informacin 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 generacin de nmeros aleatorios o la comprobacin de la existencia de un fichero en el servidor. Componente Permission Checker. A travs 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 extrao pero es as. Nos ofrece una informacin variada acerca del estado del servidor Web. Componente de registro de IIS. Mediante este componente tenemos acceso a la informacin y manipulacin de los ficheros de registro (log) generados por el servidor Web IIS 5.0.
Para poder utilizar un componente de servidor dentro de una pgina ASP debemos instanciarlo, para ello deberemos utilizar el mtodo CreateObject del objeto Server de la misma forma que lo hacamos con los componentes de VBScript. Tambin se puede crear una instancia de un componente de servidor a travs 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 mtodo 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 slo se crear en el momento que lo vayamos a utilizar por primera vez. A lo largo de los siguientes apartados del presente captulo vamos a ir comentando los distintos componentes de servidor que se ofrecen junto con la instalacin de ASP.
70
Grupo EIDOS
4. Componentes de Servidor
Componente AdRotator
Este componente de servidor se encarga de rotar una serie de anuncios (imgenes) dentro de una pgina ASP. Cada vez que un usuario vuelva a cargar la pgina el componente AdRotator mostrar una imagen con una URL asociada, atendiendo a un fichero especial denominado fichero de planificacin. Una de las caractersticas de HTML es que permite la creacin de imgenes con vnculos. La etiqueta HTML que permite visualizar una imagen en una pgina es la etiqueta <IMG>. El componente AdRotator genera una etiqueta <IMG> a la que le asigna tambin 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 planificacin. El fichero de redireccionamiento es una pgina 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 direccin URL asociada con el anuncio sobre el que se ha pulsado. En el Cdigo fuente 47,el fichero de redireccin simplemente redirige al usuario a la pgina del anunciante.
Dentro de la coleccin 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 haba comentado con anterioridad, dentro del fichero de redireccionamiento tambin podemos realizar otras tareas adems de redireccionar al navegador a una direccin determinada. Con el Cdigo fuente 48 que se muestra a continuacin se consigue saber el nmero de usuarios que pulsan sobre un anuncio determinado. En este cdigo 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 nmero de usuarios que han pulsado sobre el anuncio nmero dos.
<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\scrrun.dll"--> <%'Cuenta el nmero de usuarios que han pulsado sobre un anuncio determinado 'el fichero de pulsaciones est en este caso en el mismo directorio 'que la pgina ASP de redireccin nombreFichero=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 lectura Set objTextStream=objFSO.OpenTextFile(nombreFichero) pulsaciones=CInt(objTextStream.ReadLine) pulsaciones=pulsaciones+1 objTextStream.Close Else pulsaciones=1 End If Set objTextStream=objFSO.OpenTextFile(nombreFichero,ForWriting,True) objTextStream.WriteLine pulsaciones objTextStream.Close Set objFSO=Nothing
71
Grupo EIDOS
En la sentencia if...Then... se consulta la variable image de la coleccin QueryString del objeto Request, para comprobar si contiene el nombre del fichero de imagen del segundo anuncio. Si es el anuncio nmero dos, se lee del fichero el nmero actual de usuarios que lo han pulsado y se actualiza este nmero incrementndolo en uno. Este es un ejemplo muy bsico, por que si dos usuarios pulsan a la vez sobre el anuncio nmero dos uno de ellos no se contar. Para evitar este problema se debera 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 mtodos Lock y UnLock. El fichero de planificacin contiene informacin utilizada por el componente AdRotator para administrar y mostrar las diversas imgenes de los anuncios. En l se especifican los detalles de los anuncios como puede ser tamao, imagen a utilizar, URL asociada, frecuencia de aparicin de cada imagen. Este fichero tiene un formato determinado que se pasa a comentar a continuacin. Se encuentra dividido en dos secciones mediante un asterisco (*). La primera seccin establece los parmetros aplicables a todas la imgenes de los anuncios existentes, y la segunda seccin especifica la informacin de cada imagen individual y el porcentaje de tiempo de presentacin de cada anuncio. En la primera seccin hay cuatro parmetros opcionales y globales, si no se especifica ninguno de estos parmetros la primera lnea del archivo debera empezar por un asterisco. El formato general del fichero de planificacin es el siguiente: REDIRECT url WIDTH ancho HEIGHT alto BORDER borde * Fichero que contiene la imagen Url asociada Texto alternativo Nmero de impactos La primera lnea, REDIRECT url, indica el fichero (pgina ASP) que implementa el redireccionamiento, es decir, indica cual es el fichero de redireccionamiento. Las tres lneas siguientes, pertenecientes a la primera seccin del fichero de planificacin, hacen referencia al aspecto de la imagen: dimensiones y borde. En la segunda seccin tenemos la ubicacin del fichero grfico que representa la imagen a mostrar, a continuacin est la URL a la que ser enviado el navegador cuando el usuario pulse sobre la imagen, esta URL ser la direccin del anunciante, por ejemplo; si el anuncio no tiene ningn vinculo asociado se deber escribir un guin (-). La siguiente lnea contiene el texto alternativo que aparecer cuando el navegador no est habilitado para cargar imgenes o bien el texto que aparecer cuando el cursor del ratn se site sobre la imagen, el equivalente a la propiedad ALT de la etiqueta <IMG>. Por ltimo se debe indicar el nmero relativo de apariciones del anuncio.
72
Grupo EIDOS
4. Componentes de Servidor
En el Cdigo fuente 49 se va a mostrar y comentar un ejemplo de un fichero de planificacin para un componente Ad Rotator.
Redirect redirecciona.asp BORDER 0 * /cursoASP30/images/Anuncio1.gif http://www.almagesto.com Campus Virtual Almagesto 40 /cursoASP30/images/Anuncio2.gif http://www.eidos.es Sitio Web del Grupo EIDOS 30 /cursoASP30/images/Anuncio3.gif http://www.eidos.es/algoritmo Revista Algoritmo 30 Cdigo fuente 49
En este ejemplo el fichero encargado de redireccionar al navegador a la direccin asociada a la imagen que se ha pulsado es la pgina ASP redirecciona.asp. Al no especificarse las dimensiones de la imagen, se tomarn los valores por defecto: WIDTH=440 y HEIGHT=60. Se han utilizado tres imgenes, cuya frecuencia de aparicin ser: para la primera un 40% de las veces que se cargue la pgina, para la segunda un 30% y para la tercera otro 30%. El componente AdRotator adems de estos dos ficheros especiales que ya se han comentado, posee tambin tres propiedades y un mtodo. Sus propiedades son las siguientes: Border: indica el tamao del borde que rodea a la imagen del anuncio, cumple la misma funcin que la lnea BORDER del fichero de planificacin. Clickable: indica si el anuncio es un hipervnculo o no, tendr los valores True o False, respectivamente. TargetFrame: esta propiedad especifica el marco de destino en el que se debe cargar el vnculo. Esta propiedad realiza la misma funcin que el parmetro TARGET de una instruccin HTML de creacin de vnculos.
El nico mtodo que posee este componente ActiveX de servidor es el mtodo GetAdvertisement. A este mtodo se le debe pasar como parmetro el nombre del fichero de planificacin, y la funcin de este mtodo es la de obtener las especificaciones, a partir del fichero de planificacin, para el siguiente anuncio y le da formato de cdigo HTML. Para crear un componente AdRotator cuyo fichero de planificacin se llama planificacion.txt se deber escribir el Cdigo fuente 50.
73
Grupo EIDOS
Con el mtodo GetAdvertisement siempre debemos utilizar los delimitadores <%=%> o bien Response.Write, para enviar al navegador el cdigo HTML encargado de mostrar la imagen correspondiente con su vnculo asociado. Si tenemos en cuenta el cdigo anterior y su fichero de planificacin, una posible generacin de cdigo HTML por parte del mtodo GetAdvertisement, podra ser la que se muestra en el Cdigo 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> Cdigo fuente 51
En la Figura 11 se puede observar como se relaciona el componente AdRotator con todos los ficheros que utiliza.
Figura 11
74
Grupo EIDOS
4. Componentes de Servidor
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 librera 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, tambin se pueden establecer valores predeterminados para utilizarlos si el navegador no pertenece a ninguna de las definiciones existentes. Para cada definicin 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 = DefinicinExplorador propiedad1 = valor1 propiedadN = valorN [Default Browser Capability Settings] PropiedadPredeterminada1 = ValorPredeterminado1 PropiedadPredeterminadaN = ValorPredeterminadoN Dentro de este fichero los comentarios se indicarn con punto y coma. El encabezado User Agent puede contener comodines utilizando el carcter * para reemplazar cero o ms caracteres. Por ejemplo si escribimos el siguiente valor para el encabezado User Agent: [Mozilla/2.0 (compatible; MSIE 3.0;* Windows 95)] Coincidira con los siguientes encabezados User Agent: [Mozilla/2.0 [Mozilla/2.0 [Mozilla/2.0 [Mozilla/2.0 (compatible; (compatible; (compatible; (compatible; MSIE MSIE MSIE MSIE 3.0; 3.0; 3.0; 3.0; Windows 95)] AK; Windows 95)] SK; Windows 95)] AOL; Windows 95)]
Si se dan varias coincidencias, el componente devolver las propiedades de la primera definicin coincidente. Mediante la propiedad parent, podemos utilizar dentro de una definicin de un navegador todos los valores de las propiedades de otro navegador cuyo nombre se indica en DefinicionExplorador. La
75
Grupo EIDOS
definicin del navegador actual heredar todas las propiedades declaradas en la definicin del navegador principal. Esto es til para definir propiedades de una nueva versin de un navegador, ya que las nuevas versiones suelen conservar la mayora de las propiedades de la versin anterior. Estos valores de propiedades heredados se pueden sobreescribir estableciendo un nuevo valor para esa propiedad. El nmero de propiedades a definir puede ser cualquiera, las nicas restricciones es que el nombre de la propiedad debe comenzar por un carcter alfabtico y no puede tener ms de 255 caracteres. Normalmente para cada tipo de navegador solamente se definirn 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 nmero (#) 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 versin de este fichero: http://www.cyscape.com/browscap y http://www.asptracker.com. En el Cdigo fuente 53 se crea un componente defunciones del navegador y se muestran por pantalla algunas de las caractersticas del navegador del cliente. Si en el servidor Web tenemos el fichero BROWSCAP.INI como se ve en el Cdigo 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>")%> Cdigo fuente 53
;Internet Explorer 4.0 [IE 4.0] browser=IE Version=4.0 cookies=TRUE vbscript=TRUE javascript=TRUE javaapplets=TRUE ActiveXControls=TRUE Win16=False beta=False [Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)] parent=IE 4.0 Version=4.01 platform=Win95 Cdigo fuente 54
76
Grupo EIDOS
4. Componentes de Servidor
Si el navegador que se conecta es el Internet Explorer y enva la cabecera User Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 95), el resultado de la ejecucin del Cdigo fuente 53 sera: La Cabecera USER_AGENT enviada por el navegador es: Mozilla/4.0 (compatible; MSIE 4.01; Windows 95) Soporta VBScript Soporta Cookies No es una beta Soporta Java Plataforma: Win95 Navegador: IE4.01 Pero si el navegador que se conecta enva otra cabecera diferente, el navegador no ser reconocido y por lo tanto todas las propiedades se establecern como UNKNOWN, y la salida que devolver la ejecucin del ejemplo anterior sera: La Cabecera USER_AGENT enviada por el navegador es: Mozilla/4.03 [es] (Win95; I) Plataforma: Unknown Navegador: UnknownUnknown
Componente Nextlink
Este componente llamado tambin componente de vinculacin de contenido, tiene como misin gestionar un conjunto de direcciones URL para poder utilizarlas dentro de pginas ASP de forma sencilla, permite tratar las pginas como las de un libro, es decir, ofrece la gestin de una navegacin entre las diferentes pginas ASP de una forma sencilla. Se debe tener en cuenta que el componente de Vinculacin de Contenido trata un sitio Web como si fuera un libro que debe ser ledo desde el principio al final. Sin embargo este no es el comportamiento natural de un sitio Web, ya que su distribucin no es lineal, por lo tanto esta herramienta puede ser necesaria para guiar al usuario a travs 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 vnculos, este fichero contiene una lista de las direcciones de las pginas vinculadas, este fichero se debe encontrar en el servidor Web. El fichero de lista de vnculos contiene una lnea de texto por cada direccin URL de la lista. Cada lnea termina con un retorno de carro y cada elemento de una lnea se separa mediante un tabulador. Los vnculos a las pginas 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-Pgina-Web descripcin
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 nmero de las pginas de contenido, slo es necesario actualizar la lista de URLs que se encuentra dentro del fichero lista de vnculos y no se tiene que actualizar los vnculos de exploracin de cada pgina. Una ejemplo de un fichero de lista de vnculos podra ser el siguiente:
77
Grupo EIDOS
Para tener acceso a las URLs que aparecen especificadas dentro del fichero lista de vnculos, el objeto Nextlink ofrece una serie de mtodos: GetListCount(fichero): devuelve el nmero de vnculos del fichero lista de vnculos. GetNextURL(fichero): obtiene la siguiente URL teniendo en cuenta la pgina actual. Si la pgina actual no est especificada en dicho fichero, GetNextURL devuelve la direccin URL de la ltima pgina de la lista. GetPreviousDescription(fichero): este mtodo devuelve la descripcin del elemento anterior del fichero lista de vnculos, atendiendo a la pgina actual. Si la pgina actual no est en el fichero, se devolver la descripcin del primer elemento de la lista. GetListIndex: devuelve el ndice que corresponde a la pgina actual dentro del fichero lista de vnculos. La primera pgina tendr el ndice 1. Si la pgina actual no existe dentro de la lista de vnculos se devolver 0. GetNthDescription(fichero, indice): devuelve la descripcin correspondiente al elemento de la lista de vnculos cuyo ndice coincide con el ndice que se le pasa como parmetro a este mtodo. GetPreviousURL(fichero): obtiene la URL anterior teniendo en cuenta ja pgina actual. Si la pgina actual no est especificada en dicho fichero, GetPreviousURL devuelve la direccin URL de la primera pgina de la lista de vnculos. GetNextDescription(fichero): este mtodo devuelve la descripcin del siguiente elemento del fichero lista de vnculos, atendiendo a la pgina actual. Si la pgina actual no est en el fichero, se devolver la descripcin del ltimo elemento de la lista de vnculos. GetNthUTL(fichero, indice): devuelve la direccin URL correspondiente al elemento de la lista de vnculos cuyo ndice coincide con el ndice que se le pasa como parmetro a este mtodo.
Todos estos mtodos poseen un parmetro comn que indica la ubicacin del fichero lista de vnculos con el que debe trabajar un componente de vinculacin de contenido. En el Cdigo fuente 55 se muestra como se utilizara este componente para indicar en un pgina un enlace a la pgina siguiente, anterior y para volver a la primera pgina:
<div align="center"> <hr> <%Set vinculos=Server.CreateObject("MSWC.NextLink") listaVinculos="vinculos.txt" If (vinculos.GetListIndex(listaVinculos) > 1) Then %> <a href="<%=vinculos.GetPreviousURL(listaVinculos)%>">Pgina anterior</a> <%End If%> <%If (vinculos.GetListIndex(listaVinculos)<vinculos.GetListCount(listaVinculos)) Then%> <a href="<%=vinculos.GetNextURL(listaVinculos)%>">Pgina siguiente</a>
78
Grupo EIDOS
4. Componentes de Servidor
Para comprobar si es necesario crear un enlace a la pgina anterior se verifica que la pgina actual no es la primera, esta comprobacin se realiza en el primer If...Then..., y en el segundo If se comprueba si es necesario crear un enlace a la pgina siguiente, para ello se comprueba si la pgina actual es la ltima o no comparando el valor devuelto por el mtodo GetListIndex con el devuelto por GetListCount. Para realizar el enlace a la pgina anterior se utilizar el mtodo GetPreviousURL, para crear el enlace a la pgina siguiente se utiliza GetNextURL y para el enlace de la pgina de inicio se utiliza el mtodo GetNthURL pasndole como parmetro el ndice con valor 1. Este cdigo lo podemos escribir en una pgina llamada pie.asp y realizar un INCLUDE en las pginas correspondientes para que muestren en la parte inferior esta sencilla barra de navegacin. El aspecto sera el de la Figura 12.
Figura 12
En el captulo de introduccin de la lista de vnculos del ejemplo nos puede interesar mostrar un ndice de todo el curso. En el Cdigo fuente 56 se muestra como se creara una tabla de contenidos a partir del fichero lista de vnculos 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>
79
Grupo EIDOS
Para recorrer el fichero lista de vnculos es necesario obtener el nmero de URLs que existen en el fichero, es decir, el nmero de enlaces, para ello utilizamos el mtodo GetListCount, para acceder a cada elemento del fichero deberemos utilizar un bucle While. Dentro de este bucle se lanza el mtodo GetNthURL, para obtener la URL cuyo ndice se corresponde con el valor del contador del bucle, tambin se lanza el mtodo GetNthDescription para obtener la descripcin correspondiente. El aspecto que se correspondera con el ejemplo de fichero de vnculos anterior sera el de la Figura 13.
Figura 13
80
Grupo EIDOS
4. Componentes de Servidor
El fichero de planificacin para este componente es un fichero de texto que debe estar disponible en una ruta virtual del servidor Web y puede incluir cualquier nmero de entradas de cadenas de contenido HTML, por ello tambin se le denomina fichero de contenido. Cada entrada se compone de dos partes: una lnea que empieza por dos signos de porcentaje (%%) seguida, de manera opcional, por un nmero 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, imgenes, hipervnculos...). La sintaxis de estas entradas sera: %% [#Peso] [//Comentarios] CadenaContenido En el Cdigo fuente 57 se ofrece un ejemplo de fichero de planificacin para el componente Content Rotator.
%% 2 // Esta es la primera lnea del fichero de contenidos. <A HREF = "http://www.eidos.es"><img src="images/eidosportada.jpg"></A> %% 4 // Segunda Lnea. <B>Cursos - Internet</B> <UL> <LI>Programacin de aplicaciones para Internet con ASP. <LI>Lenguaje HTML. <LI>La Especificacin CGI. <LI>JavaScript. </UL> Cdigo 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 planificacin, dispone de dos mtodos: ChooseContent(fichero): recupera una cadena de contenido HTML del archivo de contenidos y la presenta en la pgina actual. Este mtodo recuperar una nueva cadena de contenido cada vez que se cargue la pgina. GetAllContent(fichero): recupera todas las cadenas de contenido del archivo de contenidos y las escribe directamente en la pgina como una lista con una etiqueta <HR> despus de cada entrada.
81
Grupo EIDOS
En el Cdigo fuente 58 vamos a ver un ejemplo de cmo se recuperara el contenido del fichero CONTENIDO.TXT, haciendo uso del mtodo ChooseContent().
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 planificacin CONTENIDO.TXT, como se ve en la Figura 14.
Figura 14
En el Cdigo fuente 59 podemos ver otro ejemplo haciendo uso del mtodo 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")%> Cdigo fuente 59
82
Grupo EIDOS
4. Componentes de Servidor
Figura 15
Componente Pagecounter
Este componente nos permite llevar la cuenta del nmero de veces que una pgina Web ha sido abierta. El componente guarda el nmero de visitas que se han realizado en una pgina determinada y lo almacena peridicamente en un archivo de texto. Al guardarse la cuenta de visitas por pgina en un fichero de texto, si por ejemplo se resetea el servidor los datos no se perdern. 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 5 0 12 3 2 0 /cursoasp30/pagecounter.asp /cursoasp30/adrot.asp adrot.asp /cursoasp30/page/visitas.asp /cursoASP30/page/adrot.asp /cursoASP30/page/pagecounter.asp /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 aplicacin ASP correspondiente. Este componente tambin fue incluido con la versin 2.0 de ASP. El componente contador de pginas se instancia de la forma que indica el Cdigo fuente 60.
83
Grupo EIDOS
Los mtodos de los que dispone el objeto Page Counter son los que se comentan a continuacin: Hits(rutapagina): devuelve un valor LONG representado el nmero de veces que se ha abierto una pgina Web determinada. Este mtodo puede recibir como parmetro la ruta de la pgina a la que se le va a llevar la cuenta. Si se omite este parmetro el mtodo devolver el nmero de visitas de la pgina actual. PageHit(): Incrementa el nmero de visitas a la pgina actual. Sintaxis. Reset(rutapagina): Pone a 0 el nmero de visitas de la pgina cuya ruta se le pasa como parmetro. Si no se especifica ninguna pgina en el parmetro, se pondr a 0 el nmero de visitas de la pgina actual.
En el Cdigo fuente 61 un ejemplo del uso de este componente en el que nos vamos a fabricar un contador de visitas para la pgina actual. Guardaremos la pgina como CONTADOR.ASP:
<% Set Contador = Server.CreateObject("MSWC.PageCounter")%> <b>Nmero de visitas:<%=Contador.Hits%> <%Contador.PageHit 'incrementamos el contador en uno cada vez que se cargue la pgina%> Cdigo fuente 61
En cualquier momento, desde otra pgina podremos conocer el nmero de visitas de la pgina anterior. Suponiendo que dicha pgina se encuentra en la ruta virtual "/CursoASP30/pagecounter.asp", visualizaramos su nmero de visitas como se indica en el Cdigo fuente 62.
La ruta que se indica en los mtodos Hits() y Reset() del objeto PageCounter debe iniciarse siempre con /, es decir, debe partir desde la raz del sitio Web. Si queremos registrar las visitas realizadas a todas las pginas ASP mediante este componente, podemos construirnos la pgina ASP que se muestra en el Cdigo fuente 63, que se utilizara como un INCLUDE en todas las pginas.
84
Grupo EIDOS
4. Componentes de Servidor
Siguiendo este ejemplo vemos que sera muy fcil realizar una pgina ASP que contenga una tabla informativa de las visitas que han recibido todas las pginas del Web con contadores de un sitio Web determinado. En este nuevo ejemplo del objeto Page Counter vamos a mostrar el nmero de visitas que han tenido las pginas 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 Cdigo fuente 64 de este pgina.
<%strDirectorio="/cursoASP30/page" 'creamos un objeto PageCounter Set Contador = Server.CreateObject("MSWC.PageCounter") 'en esta mismo pgina tambin se registran sus visitas Contador.PageHit Set objFSO=Server.CreateObject("Scripting.FileSystemObject") 'obtnemos una refencia a la carpeta dnde estn las pginas Set objFolder=objFSO.GetFolder(Server.MapPath(strDirectorio)) 'obtenemos los ficheros de la carpeta Set colFiles=objFolder.Files 'se recorren los ficheros For each objFile in colFiles 'se recupera el nombre para obtener despus el n de visitas strNombreFichero=objFile.Name Response.Write strNombreFichero&" --nmero de visitas: "&_ Contador.Hits(strdirectorio&"/"&strNombreFichero)&"<br>" Next%> Cdigo fuente 64
Se supone que todas las pginas mostradas deben registrar mediante el mtodo PageHit() que un usuario a cargado la pgina, sino parecer siempre cero en su nmero de visitas. En la Figura 16 se puede observar la ejecucin del cdigo anterior.
Figura 16
85
Grupo EIDOS
Componente Counters
Este componente nos permite crear, manipular y almacenar cualquier nmero de contadores individuales a travs de una instancia del mismo. Slo necesitamos crear un nico objeto Counters en el sitio Web, a travs del cual podremos crear los contadores individuales que queramos. Para ello debemos crear el objeto Counters en el archivo especial de aplicacin ASP llamado GLOBAL.ASA, como se ve en el Cdigo fuente 65, y guardarlo en una variable de aplicacin. Con lo cual dicho objeto persistir durante toda la vida de la aplicacin.
Sub Application_OnStart Set ObjContador = Server.CreateObject("MSWC.Counters") Set Application("Contador") = ObjContador End Sub Cdigo fuente 65
Tambin podemos crearlo con la etiqueta OBJECT, segn puede verse en el Cdigo fuente 66.
Los contadores que creemos a partir de este objeto Counters no se incrementan automticamente al cargar la pgina asp en la que han sido incluidos, sino que debemos hacerlo con el mtodo 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:16 contadorDos:0 Contador1:31 Contador2:1 Podremos manipular los contadores con los siguientes mtodos que ofrece el objeto Counters: Get: Devuelve el valor actual del contador cuyo nombre se le pasa como parmetro. Si el contador no existe, el mtodo lo crea y lo pone a 0. Increment: Incrementa en un 1 el valor actual del contador cuyo nombre se le pasa como parmetro, y devuelve el nuevo valor del contador. Si el contador no existe, el mtodo lo crea y lo pone a 1. Set: Recibe dos parmetros, el nombre del contador y un entero, asignando al contador el valor entero y devolviendo el nuevo valor. Si el contador no existe, el mtodo lo crea y le asigna el valor entero.
86
Grupo EIDOS
4. Componentes de Servidor
Remove: Elimina de la coleccin Counters y el contador cuyo nombre se le pasa como parmetro.
Veamos un ejemplo del uso de este componente en el que vamos a crear dos contadores "Contador1" y "Contador2" a partir del objeto de aplicacin Counters que anteriormente hemos creado en el archivo GLOBAL.ASA mediante la etiqueta <OBJECT>. Ambos contadores se incrementarn cada vez que se actualice la pgina. En el momento que el segundo contador alcance el valor 10 lo volvemos a poner a 0. Todo esto puede verse en el Cdigo fuente 67.
<b>"Contador1": <%= objCounter.Increment("Contador1") %> <br><b>"Contador2":<%=objCounter.Increment("Contador2")%> <%If CInt(objCounter.Get("Contador2"))=10 Then objCounter.Set "Contador2",0 End If%> Cdigo fuente 67
En cualquier momento, desde otra pgina ASP podremos conocer el valor de ambos contadores como puede verse en el Cdigo fuente 68.
<b>Valor del "Contador1": <%=objCounter.Get("Contador1") %> <br><b>Valor del "Contador2":<%=objCounter.Get("Contador2")%> Cdigo fuente 68
Componente MyInfo
Este componente, que tambin fue novedad en la versin 2.0 de ASP, nos permite almacenar informacin personal que ser ofrecida por el administrador del sitio Web. Esta informacin se cargar en las propiedades correspondientes del objeto MyInfo y podr ser recogida a travs 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 ocurra con Counters, nicamente se suele crear una instancia a nivel de aplicacin en el fichero GLOBAL.ASA, como vemos en el Cdigo fuente 69, o tambin como en el Cdigo fuente 70.
Sub Application_OnStart Set objMyInfo=Server.CreateObject("MSWC.MyInfo") Set Application("objMyInfo")=objMyInfo End Sub Cdigo fuente 69
87
Grupo EIDOS
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, podramos utilizar el Cdigo fuente 71.
<%objMyInfo.Nombre = "Angel" objMyInfo.Apellidos = "Esteban Nez" objMyInfo.Correo = "aesteban@eidos.es"%> Nombre: <%=objMyInfo.Nombre%><br> Apellidos: <%=objMyInfo.Apellidos%><br> Correo: <%=objMyInfo.Correo%> Cdigo fuente 71
Las tres nuevas propiedades que acabamos de crear se almacenarn de forma persistente junto con las dems 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 mtodos, y las propiedades son las que le indiquemos nosotros. La informacin 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 podra ser el Cdigo fuente 72.
Componente Tools
Este componente, componente de herramientas, proporciona una serie de utilidades a travs de sus mtodos. Estos mtodos son: FileExists, ProcessForm, Random, Owner y PluginExists. Hay que tener en cuenta que los dos ltimos mtodos (Owner y PluginExists) nicamente han sido implementados en Personal Web Server para Macintosh. Este componente, tambin fue novedad en la versin 2.0 de ASP. Vamos a describir los mtodos del componente Tools: FileExists: Este mtodo permite comprobar si el archivo cuya URL se le pasa como parmetro est publicado en el sitio Web. Por tanto, las URLs que recibe como parmetro son relativas y no absolutas. Si la URL existe dentro del directorio de publicacin devolver True, en caso contrario devolver False. ProcessForm: Este mtodo es el ms complejo del objeto Tools y procesa el contenido de un formulario enviado por un visitante del sitio Web. Su sintaxis es:
88
Grupo EIDOS
4. Componentes de Servidor
ObjetoTools.ProcessForm(URL_Archivo_Resultados, URL_Archivo_Plantilla, [PuntoInsercin]) 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 PuntoInsercin: es un parmetro opcional que indicar en qu lugar del archivo del resultados se han de insertar los datos procesados. El fichero de salida puede ser una pgina ASP que se ejecutar en un navegador, el fichero de plantilla puede ser tambin un pgina ASP pero no se ejecutar, sino que es copiado su cdigo ASP al fichero de salida, pero si utilizamos la sintaxis <%% %%>, al realizar la copia al fichero se salida si se ejecutar el cdigo ASP correspondiente. Random: Este mtodo devuelve un nmero entero aleatorio entre -32768 y 32767. Owner: Este mtodo devuelve True si el nombre y la contrasea enviados en el encabezado de la peticin 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 mtodo 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 mtodo anterior, slo ha sido implementado en Personal Web Server para Macintosh.
Los mtodos Random() y FileExists() son muy sencillos y los podemos observar en el Cdigo fuente 73.
El mtodo ProcessForm es algo ms complicado, si tenemos el fichero de plantilla mostrado en el Cdigo fuente 74.
Nombre: <%%=Request.Form("nombre")%%><br> Apellidos: <%%=Request.Form("apellidos")%%><br> Edad: <%%=Request.Form("edad")%%><br> Generado en: <%%=Now%%> Cdigo fuente 74
Al pasarle los datos de un formulario generar este otro fichero de salida: Nombre: Angel<br> Apellidos: Esteban Nez<br> Edad: 25<br> Generado en: 05/06/2000 17:18:01 Vemoslo con un sencillo ejemplo. Al pulsar el botn del formulario se ejecutar el mtodo ProcessForm y escribir los datos en el fichero de salida atendiendo al fichero que funciona como
89
Grupo EIDOS
plantilla. Adems, en esta pgina a travs de un objeto TextStream se muestra el contenido del fichero de salida una vez ejecutado el mtodo ProcessForm. Ver el Cdigo 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> Cdigo fuente 75
Figura 17
90
Grupo EIDOS
4. Componentes de Servidor
Si especificamos el parmetro punto de insercin se buscar la cadena especificada en el fichero de plantilla y aadir 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 autenticacin de usuario de IIS, es decir, usuario annimo, autenticacin bsica y autenticacin desafo/respuesta de Windows NT. En el caso de que se encuentre activada la autenticacin annima, todos los usuarios iniciarn sus sesiones con la cuenta de usuario annimo 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 desactivacin de la autenticacin annima para que PermissionChecker pueda identificar a cada usuario de forma individual. Para denegar el acceso annimo a una pgina Web, podemos usar uno de estos tres mtodos: En la lista de control de acceso al archivo, excluir la cuenta del usuario annimo 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 annimo. En el captulo siguiente veremos en detenimiento la configuracin y administracin del servidor Web Internet Information Server. Mediante un script se servidor similar al del Cdigo fuente 76.
En este script comprobamos si la variable del servidor LOGON_USER de la coleccin ServerVariables est vaca, en tal caso se tratar de la cuenta de usuario annimo y le redireccionamos a una pgina 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 autenticacin annima y al menos uno de los dos mtodos de autenticacin por contrasea, autenticacin bsica o autenticacin desafo/respuesta de Windows NT. De esta forma, si se deniega a un usuario el acceso annimo a una pgina, el servidor intentar autenticar al usuario mediante alguno de dos mtodos antes comentados. A travs de este componente podremos, incluso, controlar la navegacin entre pginas. Es decir, para un hiperenlace determinado podramos comprobar si el usuario tiene permisos de acceso a la pgina direccionada, y en caso negativo desactivar el hiperenlace. La sintaxis de creacin de este componente es:
91
Grupo EIDOS
Set Objeto = Server.CreateObject("MSWC.PermissionChecker") Este componente dispone de un solo mtodo, llamado HasAccess, a travs 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 fsica 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 Cdigo fuente 77 un ejemplo de utilizacin 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%> Cdigo fuente 77
Si el usuario no se ha autenticado para acceder a la pgina ASP del ejemplo, nunca tendr acceso al enlace, aunque el usuario annimo de Internet est autorizado el mtodo HasAccess() devolver False.
92
Grupo EIDOS
Figura 18
OLE DB puede ser utilizado para extender la funcionalidad de proveedores de datos sencillos. Estos objetos ms especializados y sofisticados se denominan proveedores de servicio, permiten abstraer al consumidor de datos del tipo de datos al que se accede y su localizacin. 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 aplicacin cliente para que construya su salida en HTML, este ejemplo sera nuestro caso, es decir una pgina ASP que usa ADO. Debemos tener en cuenta que OLE DB es una especificacin de bajo nivel. ADO encapsula el API de OLE DB en un API de ms alto nivel que proporciona dentro de su tecnologa de componentes un lenguaje neutral, que permite aprovechar todas las ventajas y caractersticas de OLE DB sin realizar una programacin 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 ms 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 dnde 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 ms 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 travs 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.
94
Grupo EIDOS
Figura 19
Una ventaja de ADO es que si ya lo hemos utilizado en Visual Basic 6, veremos que ser prcticamente igual utilizarlo en ASP, aunque eso s, teniendo siempre en cuenta el entorno tan particular en el que nos encontramos. Las caractersticas 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 jerarqua o modelo de objetos. No es necesario navegar a travs de una jerarqua para crear un objeto, la mayora 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 parmetros de entrada/salida. Diferentes tipos de cursores. Soporta resultados mltiples devueltos desde procedimientos almacenados.
Se debe tener en cuenta que aunque ADO aporte todas estas caractersticas, los proveedores y drivers a los que llama ADO pueden no contemplar estas caractersticas. Por lo tanto antes debemos consultar la documentacin de los proveedores OLE DB que vamos a utilizar para informarnos de las caractersticas que ofrecen. ADO utiliza la caracterstica pooling de conexiones de ODBC 3.0 para efectuar el acceso a las bases de datos de forma ms eficiente. Esta caracterstica consiste en mantener abiertas conexiones de bases de datos y administrar la comparticin de conexiones entre diferentes solicitudes de usuarios para mantener el rendimiento y reducir el nmero de conexiones inactivas. En cada solicitud de conexin se determina si del grupo de conexiones hay una conexin inactiva, si la hay, el grupo de conexiones devuelve esa conexin en lugar de efectuar una nueva conexin a la base de datos. Por defecto el pooling de conexiones est activado en ASP. Para desactivar esta caracterstica se debe establecer a cero la entrada de registro llamada StartConnectionPool.
95
Grupo EIDOS
Esta caracterstica es bastante til para ASP debido al entorno en el que nos encontramos. Las aplicaciones tradicionales de bases de datos suelen crear una nica conexin con la base de datos que se utiliza durante toda la duracin de la aplicacin. Sin embargo, debido a que en el entorno Web no se puede mantener la informacin entre diferentes peticiones de pginas, una aplicacin de bases de datos en el entorno Web debe abrir y cerrar una conexin en cada pgina. Adems no es recomendable almacenar referencias a objetos de ADO a nivel de variables del objeto Session o Application.
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 jerarqua de la figura, y se pueden manejar sin tener que interactuar con un intermediario. Estos tres objetos se crearn mediante el mtodo CreateObject del objeto Server, al igual que hacamos 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 prctico el objeto Recordset es el ms 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 creacin de un objeto Recordset. ASP 3.0 incluye la ltima versin de ADO, la versin 2.5, que incluye dos nuevos objetos: el objeto Record y el objeto Stream. De todas formas ya adelantamos que desde ASP 3.0 todava no se encuentra implementada de forma satisfactoria estos dos objetos.
96
Grupo EIDOS
El objeto Connection
Un objeto Connection representa una conexin a una base de datos. Los objetos Connection se pueden crear de forma independiente sin tener en cuenta ningn objeto definido previamente. Este objeto, al igual que los objetos Command y Recordset, es creado mediante el mtodo CreateObject del objeto Server. Las actividades que se pueden realizar con un objeto Connection son: creacin de conexiones con bases de datos, obtencin de objetos Recordset sencillos y tratamiento de errores. A continuacin se van a enumerar y comentar de forma breve las diferentes propiedades, mtodos y colecciones que posee este objeto. Despus se vern con ms detalle las propiedades, mtodos y colecciones ms importantes. Lo que se ofrece a continuacin no es una descripcin detallada del objeto Connection, sino que es una referencia rpida del mismo. Las propiedades del objeto Connection son: Attributes: indica distintas caractersticas de la conexin por ejemplo de que forma se puede iniciar una nueva transaccin. ConnectionTimeout: tiempo de espera mximo para la realizacin de una conexin antes de que se produzca un error. ConnectionString: cadena de conexin que identifica la base de datos a la que nos queremos conectar. CommandTimeout: tiempo mximo de espera en la ejecucin de un comando SQL que se ejecuta de forma directa sobre la conexin. CursorLocation: indica la localizacin de los cursores que se van a crear a partir de la conexin. pueden situarse en el cliente o en el servidor. DefaultDatabase: indica la base de datos por defecto con la que realizar la conexin. IsolationLevel: propiedad de slo lectura que indica el nivel de aislamiento de la conexin. Mode: modo de acceso a la conexin. Provider: proveedor OLE DB utilizado para establecer la conexin. Version: propiedad de slo lectura, indica la versin de ADO. State: propiedad de slo lectura que indica el estado de la conexin, es decir, si se encuentra abierta o cerrada.
Los mtodos del objeto Connection no son tan numerosos y son los siguientes: BeginTrans: indica el inicio de un transaccin. CommitTrans: almacena todos los cambios y finaliza la transaccin actual, representa el commit de una transaccin.
97
Grupo EIDOS
RollbackTrans: cancela todos los cambios realizados durante la transaccin actual y finaliza la transaccin, representa el rollback de una transaccin. Close: cierra la conexin. Execute: ejecuta un comando SQL. Open: abre la conexin. Cancel: cancela la ejecucin de una operacin asncrona de ejecucin de una sentencia SQL o de una apertura de una conexin. OpenSchema: obtiene un objeto Recordset con el esquema de la base de datos.
El objeto Connection posee dos colecciones: Errors: coleccin de errores generados a travs del uso de ADO. Properties: una coleccin de objetos Property referentes al objeto Connection.
La funcin principal de un objeto Connection es la de especificar el origen de los datos, aunque tambin se puede utilizar a veces para ejecutar sentencias SQL sencillas.
Grupo EIDOS
Data Source: el nombre del servidor dnde 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 conexin. Password: contrasea del usuario. File Name: nombre del fichero que contiene la informacin del proveedor de la conexin. 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 parmetros son exactos a los que puede contener la propiedad ConnectionString del objeto Connection. Adems se puede observar que el usuario y contrasea pueden estar contenidos en esta cadena de conexin. En el parmetro opciones se puede indicar una constante de ADO que aporta informacin adicional de la conexin, esta informacin indica si la conexin va a ser sncrona o asncrona, el valor de este parmetro es adASyncConnect, que indicar que la conexin es asncrona, sino se indica nada la conexin ser sncrona. En el entorno de ASP no tiene sentido declarar una conexin como asncrona, ya que ASP no puede recibir los eventos que genera ADO, por lo tanto en nuestras pginas ASP el mtodo Open nunca llevar el parmetro 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 pginas podemos copiarlo a nuestro sitio Web y realizar una referencia al mismo mediante la directiva INCLUDE, como se puede observar en el Cdigo fuente 78.
Esta sentencia la deberemos repetir en todas las pginas en las que queramos utilizar las constantes de ADO. Una alternativa ms sencilla es hacer una referencia a la librera de tipos de ADO mediante la etiqueta METADATA dentro del fichero GLOBAL.ASA, como se ve en el Cdigo fuente 79. De esta forma las constantes se encontrarn accesibles desde cualquier pgina ASP de la aplicacin.
99
Grupo EIDOS
Aunque el nombre de la librera de tipos termine en 15, pertenece a la versin 2.5 de ADO. A continuacin se va a mostrar una serie de ejemplos que realizan conexiones de distintas formas. En este primer ejemplo se realiza una conexin con el proveedor OLE DB de SQL Server. Adems de realizar la conexin se muestra el nombre del proveedor utilizado a travs de la coleccin Properties y la versin de ADO que se se ha utilizado para establecer la conexin. El cdigo necesario es el que aparece en el Cdigo fuente 80.
<%Set Conex=Server.CreateObject("ADODB.Connection") Conex.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;User id=sa"%> <b>Versin de ADO: </b> <i><%=Conex.Version%></i><br> <b>Proveedor: </b><i><%=Conex.Properties("Provider Friendly Name")%> (<%=Conex.Properties("Provider Name")%>)</i><br> Cdigo fuente 80
Mediante esta cadena de conexin lo que se consigue es establecer una conexin 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: Versin de ADO: 2.5 Proveedor: 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 librera en la que se encuentra. Si no indicamos ningn proveedor OLE DB a la hora de establecer la conexin por defecto se utiliza el proveedor de ODBC. La conexin del ejemplo anterior la podramos haber realizado de esta otra forma, como indica el Cdigo fuente 81. Y otra forma ms aparece en el Cdigo fuente 82.
Set Conex=Server.CreateObject("ADODB.Connection") Conex.ConnectionString="Provider=SQLOLEDB;Data Source=aesteban2;"&_ "Initial Catalog=pubs;User id=sa" Conex.Open Cdigo fuente 81
Tambin podemos hacer uso de otras propiedades del objeto Connection, como se puede ver en el Cdigo fuente 83, que no es nada ms que otra versin distinta de nuestro ejemplo.
Conex.Provider="SQLOLEDB"
100
Grupo EIDOS
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 conexin. Como se puede comprobar, a la vista de las numerosas versiones de este ejemplo, el establecimiento de una conexin con ADO es muy flexible. Ahora se va a realizar una conexin 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 conexin anterior, es decir, se van a mostrar distintas formas de establecer una misma conexin. Si suponemos que tenemos una fuente de datos ODBC (DSN de ODBC) de sistema definida en el servidor Web, podemos emplear el Cdigo fuente 84 para establecer la conexin.
<%Set Conex=Server.CreateObject("ADODB.Connection") Conex.ConnectionString="DSN=FuenteCursos;User id=cursos;Password=xxx" Conex.Open%> <b>Versin de ADO: </b> <i><%=Conex.Version%></i><br> <b>Proveedor: </b><i><%=Conex.Properties("Provider Friendly Name")%> (<%=Conex.Properties("Provider Name")%>)</i><br> Cdigo fuente 84
En esta caso nos conectamos a una DSN de ODBC de sistema llamada FuenteCursos con el usuario cursos que tiene la contrasea xxx. El resultado que se obtiene ahora es el siguiente: Versin de ADO: 2.5 Proveedor: Microsoft OLE DB Provider for ODBC Drivers (MSDASQL.DLL) Tambin disponemos de diversas formas de establecer una misma conexin, vamos a ver unas cuantas en el Cdigo 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" Cdigo fuente 85
Como se puede observar podemos utilizar indistintamente el parmetro PWD o Password para indicar la contrasea, y el parmetro User id y UID para indicar el usuario. Incluso se puede establecer la conexin a travs 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 conexin con ODBC sin DSN. Vemoslo en el ejemplo del Cdigo fuente 86.
101
Grupo EIDOS
En este caso se ha establecido una conexin 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 parmetro driver para indicar el driver ODBC que se va a utilizar para establecer la conexin.
102
Grupo EIDOS
Evala el comando como el nombre de una tabla. Evala el comando como un procedimiento almacenado. El tipo del comando SQL es desconocido. Se evala como el nombre de una tabla Se trata como un fichero que contiene un objeto Recordset que se haba almacenado.
Por lo tanto, a travs del mtodo Execute podremos ejecutar diferentes tipo de comandos SQL, a continuacin se comentan mediante ejemplos algunos de los usos del mtodo Execute. En el Cdigo fuente 87 se muestra como se almacenara el contenido de una tabla en un objeto Recordset, indicando de forma explcita que el comando SQL es el nombre de una tabla.
Un resultado equivalente lo obtendramos mediante la ejecucin de una sentencia SQL, como se muestra en el Cdigo fuente 88.
<%Set objConexion=Server.CreateObject("ADODB.Connection") objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx" Set objRecordset=objConexion.Execute("Select * from provincias",,adCmdText)%> Cdigo fuente 88
Para ejecutar un procedimiento almacenado llamado borraDatos, haramos lo del Cdigo fuente 89.
103
Grupo EIDOS
En el Cdigo fuente 90 se borran todas las provincias cuyo cdigo empiece por '8', el nmero de provincias borradas se recoge en el parmetro 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,adCmdText Response.write("Provincias borradas:"®istrosBorrados) %> Cdigo fuente 90
Cerrar la conexin
Una vez que hayamos terminado de trabajar con la conexin la deberemos cerrar mediante el mtodo Close. La llamada a Close liberar los recursos del sistema asociados a la conexin, pero no eliminar el objeto de la memoria, para eliminarlo de la memoria se deber asignar al objeto el valor Nothing. Cerrar una conexin mientras que existe una transaccin en progreso producir un error. Al lanzar el mtodo Close sobre una conexin tambin se cerrarn todos los objetos Recordset asociados a la conexin, y tambin se vaciarn las colecciones Parameters de los objetos Command asociados a la conexin y su propiedad ActiveConnection tendr el valor Nothing.
El objeto Command
Este es el segundo objeto que se poda crear de forma independiente a la jerarqua de objetos ADO, y adems era la segunda forma de obtener un objeto Recordset. Un objeto Command permite realizar la ejecucin 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 travs de este objeto podremos pasar parmetros a los procedimientos almacenados. Pero este objeto no slo permite realizar la ejecucin de procedimientos almacenados, tambin 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 enumerarn todas su propiedades, mtodos y colecciones y luego detallaremos los ms importantes segn vayamos avanzando en la explicacin de este objeto de ADO. Las propiedades que posee este objeto son las que se enumeran a continuacin. ActiveConnection: conexin 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 mximo de espera para la finalizacin de la ejecucin de un objeto Command. Indica cuanto tiempo se esperar mientras se ejecuta un objeto Command antes de terminar su ejecucin y generar un error. Se expresa en segundos, su valor por defecto es de 30 segundos. CommandType: indica el tipo del objeto Command.
104
Grupo EIDOS
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 ejecucin del mismo. State: propiedad de slo lectura que indica la situacin 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 mtodos del objeto Command son: CreateParameter: mediante este mtodo crearemos un parmetro para el comando SQL a ejecutar. Execute: ejecuta el objeto Command. Cancel: cancela la ejecucin asncrona de un comando. No es posible utilizarlo en pginas ASP ya que no est permitida la ejecucin asncrona.
A continuacin las colecciones del objeto Command: Parameters: esta coleccin contiene objetos Parameter que son cada uno de los parmetros que va a tener el objeto Command. Properties: coleccin de propiedades, objetos Property. Tiene la misma funcin que en el objeto Connection.
<%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"%> Cdigo 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 travs de un objeto Connection ya creado y abierto o bien a travs de la cadena de conexin correspondiente. En el Cdigo fuente 92 se ofrece la creacin de un objeto Command pero que se conecta a travs del proveedor OLE DB de SQL Server.
105
Grupo EIDOS
<%Set objConexion=Server.CreateObject("ADODB.Connection") objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;User id=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" Cdigo fuente 92
Lo ms recomendable es utilizar en la propiedad ActiveConnection un objeto Connection, de esta forma distintos objetos Command pueden compartir una misma conexin. Si utilizamos una cadena de conexin en la propiedad ActiveConnection, cada objeto Command tendr su propia conexin (objeto Connection), lo que supondr una mayor carga para el servidor. Una vez que hemos indicado al objeto Command la conexin a la base de datos, le debemos indicar el comando que deseamos que contenga a travs de la propiedad CommandText, adems, podemos indicar el tipo de comando que se va a ejecutar a travs de la propiedad CommandType, los valores de esta propiedad son las constantes que ya vimos dentro del parmetro CommandText del mtodo Execute del objeto Connection. De esta forma si queremos crear un comando que ejecute una sentencia SQL INSERT deberemos escribir el Cdigo fuente 93.
<%Set objComando=Server.CreateObject("ADODB.Command") objComando.ActiveConnection="DSN=FuenteBD;UID=pepe;PWD=xxx" objComando.CommandType=adCmdText objComando.CommandText="INSERT INTO Provincias VALUES ('aa','Soria')"%> Cdigo fuente 93
El tiempo mximo que vamos a esperar a que un comando finalice su ejecucin se indica en segundos a travs de la propiedad CommandTimeout, cuando la ejecucin de un comando supera este tiempo, se abortar su ejecucin y se producir un error. El valor de CommandTimeout depender del trfico 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 podra ralentizar la primera ejecucin del objeto Command, pero una vez que el proveedor de datos a compilado el contenido del comando, el proveedor utilizar la versin 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.
106
Grupo EIDOS
La coleccin Parameters
Como se ha comentado al comienzo de este captulo, las funciones del objeto Command eran permitir la ejecucin de procedimientos almacenados y ejecucin se sentencias SQL optimizadas (precompiladas o preparadas), por lo tanto debe permitir realizar el paso de parmetros a la sentencia o procedimiento SQL que se vaya a ejecutar. Un objeto Command almacena los parmetros que va a necesitar para su ejecucin en una coleccin llamada Parameters, esta coleccin est constituida por objetos Parameter. Por lo tanto antes de ejecutar un comando deberemos crear sus parmetros y aadrselos a la coleccin Parameters. Para crear un parmetro utilizaremos el mtodo CreateParameter del objeto Command, al lanzar este mtodo obtenemos un objeto Parameter, la sintaxis general de este mtodo es la siguiente: Set parametro=objComando.CreateParameter([nombre][, tipo][, direccion][, tamao][, valor]) Donde parametro es un objeto Parameter en el que se va a almacenar el parmetro creado como resultado de lanzar este mtodo, objComando es el objeto Command al que se le ha asociado ese parmetro, los siguientes argumentos son todos opcionales: nombre es una cadena que va a representar el nombre del parmetro (a travs de este nombre se podr hacer referencia al parmetro dentro de la coleccin Parameters), tipo indica el tipo de dato del parmetro, direccion indica si el parmetro es de entrada o de salida, tamao indica el tamao mximo del parmetro 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 mtodo CreateParameter, pero tambin podremos lanzar el mtodo CreateParameter sin especificar ninguna de estas propiedades (se debe recordar que todos los argumentos del mtodo 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 parmetro dentro de la coleccin Parameters. Este nombre no tiene porque coincidir con el nombre del parmetro correspondiente en el procedimiento almacenado de la base de datos. Type: tipo de dato del parmetro. Direction: indica la naturaleza (direccin) del parmetro. Size: es el tamao del parmetro. Value: valor que se asigna al parmetro. NumericScale: indica el nmero de decimales soportado por el parmetro. Precision: nmero mximo de dgitos del parmetro. Attributes: es una combinacin de ciertas constantes que indican otras caractersticas del parmetro. Estas constantes son adParamNullable (el parmetro acepta valores nulos), adParamSigned (el parmetro acepta valores con signo) y adParamLong (el parmetro acepta valores de datos grandes).
107
Grupo EIDOS
En el Cdigo fuente 94 se muestran las dos posibilidades, es decir, se indican las caractersticas del parmetro a travs del mtodo CreateParameter y por otro lado se utilizan las propiedades del objeto Parameter para asignarles los valores correspondientes. En el ejemplo se pretende crear un parmetro de entrada llamado nombre de tipo char, de tamao mximo 20 y cuyo valor es "Pepe".
<%Set objComando=Server.CreateObject("ADODB.Command") objComando.ActiveConnection="DSN=FuenteBD;UID=jose;PWD=xxx" objComando.CommandType=adCmdText objComando.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=adCmdText objComando.CommandText="INSERT INTO Usuarios VALUES (?)" Set parametro=objComando.CreateParameter parametro.Name="nombre" parametro.Type=adChar parametro.Direction=adParamInput parametro.Size=20 parametro.Value="Pepe" %> Cdigo fuente 94
Como se puede observar la primera forma de crear un parmetro y establecer sus propiedades es mucho ms cmoda. Tambin podemos apreciar que en la sentencia SQL que contiene el objeto Command, el parmetro se corresponde con el signo de interrogacin (?), este es el caracter especial que indica en que lugar se va a situar el parmetro. Una vez creado el parmetro y establecidas sus propiedades lo deberemos aadir a la coleccin Parameters del objeto Command correspondiente, para ello esta coleccin ofrece el mtodo Append. El orden en que se aaden los objeto Parameter a la coleccin Parameters es significativo, se irn sustituyendo los signos de interrogacin (?) de la sentencia o los parmetros del procedimiento almacenado segn se vayan aadiendo los parmetros a la coleccin. La sintaxis del mtodo Append es: objCommand.Parameters.Append objParametro La coleccin Parameters, adems del mtodo Append ofrece dos mtodos ms: Delete y Refresh. El mtodo Delete elimina el objeto Parameter de la coleccin Parameters, cuyo ndice o nombre se pasa como argumento, la sintaxis de este mtodo es: objCommand.Parameters.Delete {ndice|nombre} El mtodo Delete se suele utilizar para una vez ejecutado un objeto Command, eliminar sus parmetros para volver a utilizarlo con otros valores. El mtodo Refresh realiza una llamada al origen de los datos para obtener todos los datos correspondientes a los parmetros que necesita un objeto Command determinado. El mtodo Refresh obtiene los nombres, tipos de datos, naturaleza y longitud de los parmetros y con esta informacin rellena la coleccin Parameters por nosotros, nicamente deberemos indicar los valores de los parmetros, no deberemos utilizar el mtodo Append. Sin embargo es recomendable construir la coleccin Parameters de forma manual, sin realizar la llamada al mtodo Refesh, ya que esto ltimo resulta ms costoso para el origen de los datos.
108
Grupo EIDOS
La coleccin Parameters posee dos propiedades: Count: devuelve el nmero de objetos Parameters presentes en la coleccin Parameters. Item: es la propiedad por defecto de la coleccin 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 parmetros ya estaremos en disposicin de ejecutar el comando mediante el mtodo Execute. Una vez ejecutado el objeto Command, si deseamos volver a utilizarlo con otros parmetros ser necesario eliminar los parmetros existentes dentro de la coleccin Parameters, para ello se utiliza el mtodo Delete (como ya comentamos en el apartado anterior). Como se ha dicho con anterioridad para ejecutar un objeto Command se utiliza el mtodo Execute, que presenta la siguiente sintaxis: Set objRecordset=objComando.Execute(RegistrosAfectados, Parmetros, Opciones) objComando.Execute RegistrosAfectados, Parmetros, Opciones En el caso de que la ejecucin 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 informacin. Como ya se coment anteriormente, el objeto Command ofreca el segundo mecanismo (el primer mecanismo lo ofreca el objeto Connection) para obtener un objeto Recordset. Los argumentos son todos opcionales, RegistrosAfectados es un entero que se devuelve y que indicar el nmero de registros que se han visto afectados por la ejecucin del comando, Parametros es un array de con los valores de los parmetros, se utiliza en el caso de que no hayamos aadido a la coleccin Parameters los parmetros 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, adems este parmetro si se especifica sobreescribe al valor indicado en la propiedad CommandType. En el Cdigo fuente 95 se muestra como se ejecutara una sentencia SQL que realiza una actualizacin sobre una tabla a partir de los parmetros 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=adCmdText objComando.CommandText="UPDATE Provincias SET Provincia=?"&_ "WHERE IDProvin=?" Set parametro1=objComando.CreateParameter("nombre",adChar,adParamInput,20,"Cceres") Set parametro2=objComando.CreateParameter("clave",adChar,adParamInput,2,"10") objComando.Parameters.Append parametro1 objComando.Parameters.Append parametro2 objComando.Execute %> Cdigo fuente 95
109
Grupo EIDOS
En el Cdigo 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=adCmdStoredProc objComando.CommandText="altaProvincia" Set parametro1=objComando.CreateParameter("clave",adChar,adParamInput,2,"90") Set parametro2=objComando.CreateParameter("nombre",adChar,adParamInput,20,"Santander") objComando.Parameters.Append parametro1 objComando.Parameters.Append parametro2 objComando.Execute %> Cdigo fuente 96
Como se puede apreciar, en el caso de realizar la ejecucin de un procedimiento almacenado, no se indican los parmetros con signos de interrogacin, nicamente se debe proporcionar el nombre del procedimiento almacenado que queremos utilizar, y los parmetros se situarn segn est definido el procedimiento en la base de datos. Es responsabilidad del programador conocer la definicin del procedimiento almacenado y por lo tanto proporcionar los parmetros de forma adecuada. La forma de obtener un objeto Recordset a partir de la ejecucin de un objeto Command es muy sencilla. A la hora de ejecutar el objeto Command con el mtodo Execute podremos guardar su resultado en un objeto Recordset, de la misma forma que ocurra al ejecutar un sentencia SQL sobre un objeto Connection. El Cdigo fuente 97 trata de una pgina ASP que realiza una SELECT sobre la tabla de provincias y guarda el resultado en un objeto Recordset para su futura inspeccin.
<%Set objConexion=Server.CreateObject("ADODB.Connection") objConexion.Open "DSN=FuenteBD;UID=pepe;PWD=xxx" Set objComando=Server.CreateObject("ADODB.Command") objComando.ActiveConnection=objConexion objComando.CommandType=adCmdText objComando.CommandText="SELECT * FROM Usuarios" Set objRecordset=objComando.Execute%> Cdigo fuente 97
En el Cdigo fuente 98 se crea un Recordset con la informacin devuelta por un procedimiento almacenado, en este caso, el procedimiento devuelveDomicilio devuelve una relacin de los nombres de usuario junto con su domicilio.
110
Grupo EIDOS
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 automtica a partir de la ejecucin de un objeto Connection o un objeto Command. Pero el objeto Recordset que se obtiene es muy sencillo y limitado, representa un cursor de slo lectura y que nicamente permite un desplazamiento hacia delante. Un objeto Recordset se puede crear de forma independiente, es decir, sin depender de ningn 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 representacin 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 navegacin y la conexin con los datos. Un cursor determina el comportamiento de un objeto Recordset. Por lo tanto, si queremos disponer de un cursor ms potente, deberemos crear un objeto Recordset. al igual que crebamos un objeto Connection o Command, y a travs de sus propiedades definir exactamente las caractersticas del Recorset. A continuacin se pasa a mostrar de forma resumida todas las propiedades, mtodos y colecciones que posee este objeto. El objeto Recordset posee un gran nmero de propiedades: PageSize: nmero de registros del Recordset que se van a encontrar dentro de una pgina lgica. AbsolutePage: nmero de pgina del registro actual. Para movernos a una pgina determinada le asignaremos a esta propiedad el nmero de pgina correspondiente. AbsolutePosition: especifica la posicin ordinal del registro actual dentro de un Recordset. PageCount: indica el nmero de pginas lgicas que posee un objeto Recordset. ActiveConnection: indica la conexin a la que esta asociado el objeto Recordset. Esta propiedad es slo de lectura en el caso de que la propiedad Source tenga un valor vlido. 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 slo 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 direccin de Internet, etc. Esta propiedad es de lectura/escritura si el Recordset est cerrado, y slo 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.
111
Grupo EIDOS
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 localizacin 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 posicin 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 nmero de registros que se encuentran en la memoria. EditMode: indica el proceso de edicin del registro actual. Es de slo lectura. MaxRecords: indica el nmero mximo de registros que debe contener un Recordset como resultado de una consulta. Se utiliza esta propiedad para limitar el nmero de registros devueltos por el proveedor desde una fuente de datos. RecordCount: devuelve el nmero de registros de un objeto Recordset. BOF: indica si la posicin actual se encuentra antes del primer registro de un Recordset. EOF: indica si la posicin actual se encuentra despus del ltimo registro de un Recordset.
Los mtodos de estos objeto tambin son numerosos, y son los que aparecen a continuacin:
112
Open: este mtodo abre un cursor que va a representar los registros resultantes de la realizacin de un comando SQL. Close: cierra el cursor, perdiendo todos los datos asociados. CompareBookmarks: compara dos Bookmark y devuelve el resultado de la comparacin. Move: la posicin actual se desplaza a la posicin indicada. GetString: devuelve el Recordset completo dentro de una cadena.
Grupo EIDOS
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 todava no se ha lanzado el mtodo 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 funcin 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 especfica que se le pasa como argumento a este mtodo.
El objeto Recordset posee dos colecciones: Fields: esta coleccin est formada por objetos Field. Cada objeto Field representa una columna del Recordset, es decir, un campo. Properties: esta coleccin es como la que posean los objetos Connection y Command.
113
Grupo EIDOS
<HTML> <HEAD> <TITLE>Ejemplo objeto Recordset</TITLE> </HEAD> <BODY> <%Set objRecordset=Server.CreateObject("ADODB.Recordset") objRecordset.Source="SELECT * FROM Usuarios" objRecordset.CursorType=adOpenStatic objRecordset.ActiveConnection="DSN=FuenteBD;UID=pepe;PWD=xxx" objRecordset.Open%> <center><strong> Nmero de registros: <%=objRecordset.RecordCount%><br><br> </strong></center> <table border="1" align="center"> <tr> <th>DNI</th> <th>Nombre</th> <th>Domicilio</th> <th>Cdigo 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 Wend objRecordset.Close Set objRecordset=Nothing%> </table> </body> </html> Cdigo 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 caractersticas del Recordset. En este caso se ha utilizado la propiedad RecordCount que devuelve el nmero de registros que existen dentro un Recordset, adems, 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 vlido, como puede ser el nombre de una tabla, una sentencia SQL o el nombre de un procedimiento almacenado, tambin 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 conexin a la que se encuentra asociado. A esta propiedad se le puede pasar un objeto Connection ya creado, o bien, una cadena de
114
Grupo EIDOS
conexin, 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 ocurra 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 mtodo Open. Al lanzar este mtodo el Recordset pasar a contener los datos indicados por la propiedad Source. En este caso el mtodo Open se ha utilizado sin parmetros, ya que las caractersticas del objeto Recordset ya las hemos definido a travs de sus propiedades. La sintaxis general del mtodo Open es la siguiente: ObjetoRecordset.Open OrigenDatos, Conexion, TipoCursor, TipoBloqueo, Opciones Todos los parmetros son opcionales y se debern especificar si no hemos dado algn valor a alguna de las propiedades del Recordset que representa cada uno de ellos. De esta forma, OrigenDatos es el valor que se le asignara 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 continuacin 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 ejecucin directa sobre un objeto Connection, como se ve en el Cdigo fuente 100.
<%Set objConexion=Server.CreateObject("ADODB.Connection") objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;User id=sa" Set objRecordSet=objConexion.Execute("Select * from authors",,adCmdText)%> Cdigo fuente 100
Tambin a partir de la ejecucin directa de un objeto Command, como en el Cdigo fuente 101.
<%Set objConexion=Server.CreateObject("ADODB.Connection") objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;User id=sa" Set objComando=Server.CreateObject("ADODB.Command") objComando.ActiveConnection=objConexion objComando.CommandText="devuelveAutores" Set objRecordSet=objComando.Execute(,,adCmdStoredProc)%> Cdigo fuente 101
De momento no hemos utilizado el mtodo Open, pero en el Cdigo 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.
115
Grupo EIDOS
<%Set objConexion=Server.CreateObject("ADODB.Connection") objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;User id=sa" Set objComando=Server.CreateObject("ADODB.Command") objComando.ActiveConnection=objConexion objComando.CommandText="devuelveAutores" Set objRecordSet=Server.CreateObject("ADODB.Recordset") objRecordSet.Open objComando ,,adOpenForwardOnly,adLockReadOnly,adCmdStoredProc%> Cdigo fuente 102
Como se puede observar en el parmetro del mtodo Open correspondiente a la propiedad ActiveConnection del objeto Recordset no hemos indicado ninguna conexin, ya que se toma la conexin que se ha especificado para el objeto Command que utilizamos como origen de datos del objeto Recordset. Tambin podemos utilizar el mtodo Open especificando la tabla, como en el Cdigo fuente 103.
<%Set objConexion=Server.CreateObject("ADODB.Connection") objConexion.Open "Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;User id=sa" Set objComando=Server.CreateObject("ADODB.Command") objComando.ActiveConnection=objConexion objComando.CommandText="devuelveAutores" Set objRecordSet=Server.CreateObject("ADODB.Recordset") objRecordSet.Open "authors",objConexion,adOpenForwardOnly,adLockReadOnly,adCmdTable%> Cdigo fuente 103
Y por ltimo podemos tener un objeto Recordset completamente independiente, que posea su propia conexin y recupere la informacin de la tabla a travs de una sentencia SQL. Ver el Cdigo fuente 104.
<%strConexion="Provider=SQLOLEDB;Data Source=aesteban2;Initial Catalog=pubs;User id=sa" strConsulta="select * from authors" Set objRecordSet=Server.CreateObject("ADODB.Recordset") objRecordSet.Open strConsulta,strConexion,adOpenForwardOnly,adLockReadOnly,adCmdText%> Cdigo fuente 104
Al igual que abrimos un Recordset, debmos cerrarlo con el mtodo 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 teora, si cerramos el objeto Connection al que est asociado una serie de objetos Recordset, se cerrarn todos estos objetos Recordset dependientes de forma automtica, pero es mejor, para liberar memoria y recursos de forma ms fiable e inmediata, cerrar cada uno de los Recordset mediante estas dos sencillas lneas de cdigo, como se muestra en el Cdigo fuente 105.
116
Grupo EIDOS
117
CDONTS y ASP
Introduccin
En captulos 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 intrprete de secuencias de comandos de VBScript (Dictionary, FileSystemObject, TextStream, etc.). Componentes incluidos con la instalacin de ASP (AdRotator, MyInfo, ContentRotator, Tools, ADO, etc.).
En este captulo vamos a ver un conjunto de componentes agrupados todos ellos bajo el nombre de CDONTS (Collaboration Data Objects for NT Server). CDONTS es una librera de Microsoft que ofrece la posibilidad de utilizar sistemas de mensajera, basndose 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 captulo 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
Grupo EIDOS
Administrador de servicios de Internet y comprobar si existe el nodo llamado Servidor virtual SMTP predeterminado.
Si no se encuentra instalado este servicio acudiremos a la opcin Agregar o quitar programas del Panel de control. Dentro de esta opcin seleccionaremos Agregar o quitar componentes de Windows y de los componentes seleccionaremos Servicios de Internet Information Server (IIS). Si pulsamos el botn etiquetado como Detalles veremos los subcomponentes de IIS y seleccionaremos el componente Servicio SMTP.
120
Grupo EIDOS
6. CDONTS y ASP
A lo largo de este captulo comentaremos cuando sea necesario algunos puntos relacionados con la configuracin 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 Cdigo fuente 106 que utiliza un objeto de CDONTS llamado NewMail y que nos permite de manera muy sencilla enviar un mensaje de correo electrnico.
<%Set objMail=Server.CreateObject("CDONTS.NewMail") objMail.Send "pepe@trola.com","aesteban@mail.angel.es","Asunto","Hola que tal te va..."%> Cdigo fuente 106
Con este cdigo ya podramos enviar un mensaje de correo a travs de nuestro servicio SMTP. En siguientes apartados comentaremos detenidamente de nuevo este cdigo.
Como se puede observar todos los objetos se encuentran relacionados a excepcin del objeto NewMail que aparece desconectado del resto. A continuacin se ofrece una breve descripcin de los objetos incluidos en CDONTS. NewMail: mediante este objeto podremos enviar nuevos mensajes de correo.
121
Grupo EIDOS
Session: este objeto contiene toda la informacin necesaria para manipular mensajes y tambin 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 sesin 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 coleccin de objetos Message. AddressEntry: este objeto contiene informacin relativa al remitente de un mensaje determinado, se obtiene a partir de la propiedad Sender del objeto Message. Attachments: coleccin 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: coleccin 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 jerarqua del objeto Session nos va a permitir enviar mensajes de correo electrnico. Los mtodos que ofrece este objeto son: Send(remitente, destinatario, asunto, mensaje, importancia): mediante este mtodo enviaremos un mensaje al destinatario que indiquemos. Todos los parmetros son opcionales, pudiendo aplicar el mtodo Send() sin parmetros, ya que el objeto NewMail ofrece una serie de propiedades que permiten configurar el mensaje antes de enviarlo. En el parmetro destinatario podemos expresar distintos destinatarios separados con comas. Tanto destinatario como remitente son direcciones de correo electrnico. En el asunto especificaremos el asunto del mensaje y en mensaje el cuerpo del mensaje, es decir, el mensaje en s. Y mediante el parmetro importancia indicamos si es alta (cdoHigh), normal (cdoNormal) o baja (cdoLow), por defecto este parmetro tiene el valor cdoNormal. Todos estos parmetros se corresponden con propiedades del objeto NewMail que veremos a continuacin. AttachFile(fuente, nombreFichero, codificacin): permite adjuntar el fichero especificado en el parmetro fuente a un mensaje de correo, se debe indicar una ruta fsica completa, el resto de los parmetros son opcionales. En nombreFichero indicamos el nombre con el que aparece el fichero adjunto en el cliente de correo, y en codificacin indicamos el mtodo de
122
Grupo EIDOS
6. CDONTS y ASP
codificacin empleado para enviar el fichero adjunto, esta parmetro tiene dos posibles valores cdoEncodingUUencode y cdoEncodingBase64, por defecto presenta el primero de ellos. En el ejemplo del Cdigo fuente 107 se trata de enviar un correo a aesteban@mail.angel.es, 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 "pepe@trola.com","aesteban@mail.angel.es"_ ,"Asunto","Hola que tal te va...",cdoLow%> Cdigo fuente 107
Como se puede observar se ha realizado una referencia a la librera 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.
123
Grupo EIDOS
Las propiedades que posee el objeto NewMail son las siguientes, y como ya hemos dicho algunas de ellas se corresponden con los parmetros del mtodo Send(): From: en esta propiedad indicamos el remitente del mensaje de correo. Se asigna una cadena que representa una direccin 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 funcin 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, indicndolo 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 ms elaborados en nuestros mensajes de correo. Version: esta propiedad de slo lectura devuelve la versin de la librera CDONTS que estamos utilizando, la versin 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 sera equivalente a asignar a la propiedad ContentBase el valor "http://www.almagesto.com/images/".
Veamos un ejemplo que muestra la utilizacin de las propiedades del objeto NewMail. En este caso se definen algunas de las propiedades y luego se enva el correo mediante el mtodo Send() sin parmetros.
124
Grupo EIDOS
6. CDONTS y ASP
<%Set objMail=Server.CreateObject("CDONTS.NewMail") objMail.From="pepe@trola.com" objMail.To="aesteban@mail.angel.es" objMail.Importance=cdoLow objMail.MailFormat=cdoMailFormatMIME objMail.Subject="Asunto" objMail.BodyFormat=cdoBodyFormatHTML objMail.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=strTexto objMail.Send%> Cdigo 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.
A travs del objeto NewMail tambin podemos tener acceso y manipular las cabeceras del mensaje de correo, que normalmente en los clientes de correo permanecen ocultas. Parte de la informacin 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 automtica 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 opcin Archivo|Propiedades, y luego elegimos la pestaa Detalles. Mediante la coleccin Value del objeto NewMail podemos aadir nuevas cabeceras a los mensajes o modificar las existentes. En el Cdigo fuente 109 se aade una nueva cabecera y se modifica la cabecera Subject.
125
Grupo EIDOS
<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\cdonts.dll"--> <%Set objMail=Server.CreateObject("CDONTS.NewMail") objMail.From="pepe@trola.com" objMail.To="aesteban@mail.angel.es" objMail.Importance=cdoLow objMail.MailFormat=cdoMailFormatMIME objMail.Subject="Asunto" objMail.BodyFormat=cdoBodyFormatHTML objMail.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=strTexto objMail.Value("Subject")="Modifico el asunto" objMail.Value("NuevaCabecera")="Nuevo valor" objMail.Send%> Cdigo fuente 109
Los detalles del mensaje en Outlook Express tienen el aspecto que nos muestra la
Hemos visto lo sencillo que resulta enviar un mensaje mediante el objeto NewMail de la librea CDONTS, ahora vamos a seguir viendo los distintos objetos que proporciona esta librera. Los siguientes objetos permiten acceder a los mensajes que se encuentran almacenados en el servidor de correo.
126
Grupo EIDOS
6. CDONTS y ASP
El objeto Session
Del objeto Session dependen el resto de los objetos de la librera CDONTS, a travs del objeto Session iniciamos una sesin con el servidor de correo mediante un usuario determinado. El servidor con el que iniciamos la sesin ser el servidor de correo que se encuentre instalado en el servidor Web en el que se ejecutan las pginas 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 direccin 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 botn derecho del ratn seleccionamos la opcin Nuevo|Dominio, en ese momento se lanza el asistente para la creacin de nuevos dominios. Dentro del asistente seleccionamos la opcin de Alias y pulsamos el botn Siguiente. A continuacin 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 botn Finalizar. Si todo ha sido correcto veremos una pantalla similar a la de la Figura 27.
Despus de este pequeo comentario acerca de la creacin de dominios, volvamos al tema principal que nos ocupa dentro de este apartado. El objeto Session presenta los siguientes mtodos: LogonSMTP(nombre, direccion): mediante este mtodo se inicia una sesin con el servidor de correo. En el parmetro nombre se indica el nombre que se desea que se muestre al usuario, y en direccin la direccin completa del usuario que se desea conectar al servidor de correo. Este mtodo no realiza ningn tipo de validacin, si la conexin no se ha podido establecer no recibimos ningn mensaje de error. Cada usuario conectado tendr acceso a su propio buzn, pudiendo leer el correo de su "bandeja de entrada" (inbox) y enviar correo a travs de su "bandeja de salida" (outbox).
127
Grupo EIDOS
LogOff(): este mtodo finalizar la sesin actual con el servidor de correo. Podremos reutilizar el objeto Session si deseamos realizar una nueva sesin llamando de nuevo al mtodo LogonSMTP. GetDefaultFolder(tipoCarpeta): mediante este mtodo se obtiene un objeto Folder que representa la bandeja o carpeta de entrada o la de salida del usuario conectado. El parmetro de este mtodo 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 mtodo permite establecer un cdigo de localizacin que afectar al entorno del lenguaje, formatos horarios, fechas, valores monetarios, etc. El parametro tiene los mismos valores que vimos para la propiedad LCID del objeto integrado Session de ASP. Este mtodo si se utiliza se debe lanzar antes de establecer la sesin con el servidor de correo mediante el mtodo LogonSMTP().
Ahora vamos a pasar a comentar las propiedades del objeto Session: Inbox: propiedad de slo lectura que devuelve un objeto Folder que representa la bandeja de entrada de la sesin actual. Outbox: propiedad de slo lectura que devuelve un objeto Folder que representa la bandeja de salida de la sesin actual. MessageFormat: propiedad de lectura y escritura que permite obtener e indicar el formato de codificacin de los mensajes. Tiene dos valores posibles CDOMime, para mensajes de tipo MIME, y CDOText para mensajes de tipo texto plano. Name: propiedad de slo lectura que contiene el nombre del usuario conectado y que se ha especificado en el mtodo LogonSMTP(). Version: propiedad de slo lectura que indica la versin de la librera CDONTS.
El objeto Session adems de estas propiedades ofrece otras tres que son comunes a todos los objetos de su jerarqua, y son las siguientes: Session: esta propiedad devuelve el objeto Session que representa la raz de la jerarqua 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 mtodos 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 conexin con el servidor SMTP se muestran algunos de los valores de las propiedades de la sesin actual. Tambin existe la posibilidad de desconectarnos para
128
Grupo EIDOS
6. CDONTS y ASP
iniciar una nueva sesin, la sesin se debe almacenar en una variable a nivel de sesin, ya que ms tarde deberemos utilizarla para realizar la desconexin. Veamos el Cdigo fuente 110. Y en la Figura 28 se puede ver un ejemplo de la ejecucin del cdigo 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 desconexin Set objSession=Session("oSession") objSession.LogOff End if If 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 conexin Set 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> Versin 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> Cdigo fuente 110
129
Grupo EIDOS
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 sesin actual. Un objeto Folder lo obtenemos a partir de la propiedades Inbox y Outbox de un objeto Session que representa una sesin ya establecida con el servicio SMTP. Tambin lo podemos obtener a travs del mtodo GetDefaultFolder(). El objeto Folder suele representar las siguientes carpetas estndar: Bandeja de entrada (inbox): es la localizacin que tiene el correo recibido. Bandeja de salida (outbox): es la localizacin temporal que tiene el correo antes de proceder a su envo.
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 aclaracin acerca del servidor SMTP de IIS y los objetos de la librera 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 localizacin 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 sesin con el servidor SMTP, a travs 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 ms claro. Hecha esta aclaracin volvemos a tratar el objeto Folder, empezando ahora a comentar las propiedades que nos ofrece. Name: propiedad de slo 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 coleccin de objetos Message, que representar los mensajes presentes en la carpeta.
Veamos el tratamiento que tiene la coleccin Messages. La coleccin Messages posee las siguientes propiedades: Count: nmero de objetos Message contenidos en la misma. Item(indice): devuelve un objeto Message de la coleccin cuyo ndice coincide con el parmetro indicado. El primer ndice es 1.
130
Grupo EIDOS
6. CDONTS y ASP
Y los siguientes mtodos: Add(asunto, texto, importancia): permite aadir un nuevo mensaje a la coleccin. Todos los parmetros son opcionales, y cuando se ejecuta este mtodo se devuelve un objeto Message para poder manipularlo. Este mtodo nicamente se puede aplicar a una coleccin Messages que pertenece a la bandeja de salida. Delete(): elimina todos lo mensajes de la coleccin. Para borrar un mensaje en concreto debemos utilizar el mtodo Delete del objeto Message, pero eso lo veremos en el siguiente apartado. GetFirst(): mtodo que devuelve el primer objeto Message de la coleccin Messages. Si el objeto no existe devuelve Nothing. GetLast(): mtodo que devuelve el ltimo objeto Message de la coleccin Messages. Si el objeto no existe devuelve Nothing. GetNext(): mtodo que devuelve el siguiente objeto Message de la coleccin Messages. Si el objeto no existe devuelve Nothing. GetPrevious(): mtodo que devuelve el anterior objeto Message de la coleccin 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 conexin, para mostrar la utilizacin prctica del objeto Folder. En este nuevo ejemplo vamos a establecer la sesin con el servicio SMTP con el mismo formulario y vamos a indicar el nmero de mensajes que posee el usuario conectado en ese momento en cada una de sus bandejas. Tambin aparece un nuevo botn que permite eliminar al usuario todos los mensajes de su bandeja de entrada. El Cdigo 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 desconexin Set objSession=Session("oSession") objSession.LogOff Session("oSession")="" Elseif Request.Form("EliminarInbox")<>"" Then 'se eliminan todos los mensajes de Inbox Set objSession=Session("oSession") Set objFolderInbox=objSession.Inbox objFolderInbox.Messages.Delete End if If 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>
131
Grupo EIDOS
<%Elseif Request.Form("Conectar")<>"" Then 'se realiza la conexin Set objSession=Server.CreateObject("CDONTS.Session") objSession.LogonSMTP Request.Form("nombre"),Request.Form("cuenta") 'se guarda a nivel se sesin la referencia a la sesin establecida 'con el servicio SMTP Set Session("oSession")=objSession End if If Session("oSession")<>"" Then 'se recupera la sesin con SMTP Set 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 nmero de mensajes en <%=objFolderInbox.Name%> es <%=objFolderInbox.Messages.Count%><br> <%Set objFolderOutbox=objSession.Outbox%> El nmero de mensajes en <%=objFolderOutbox.Name%> es <%=objFolderOutbox.Messages.Count%> <%End if%> </BODY> </HTML> Cdigo fuente 111
En el siguiente apartado veremos como mostrar los datos de los mensajes contenidos en las bandejas y tambin como eliminar mensajes determinados y enviar nuevos.
132
Grupo EIDOS
6. CDONTS y ASP
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 travs de la coleccin Messages del objeto Folder correspondiente. En este apartado adems de comentar el objeto Message vamos a tratar las dos colecciones que contiene: Recipients y Attachments, y tambin 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 coleccin 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 codificacin del mensaje. Recipients: coleccin 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: tamao en bytes del mensaje. Subject: asunto del mensaje. Text: cuerpo del mensaje en formato de texto plano. TimeReceived: fecha y hora de recepcin del mensaje. TimeSent: fecha y hora de envo del mensaje.
Muchas de estas propiedades son comunes a las del objeto NewMail. El objeto Message ofrece los siguientes mtodos: Send(): este mtodo enva 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 utilizacin del objeto Message. En este caso se trata de mostrar el contenido de la bandeja de entrada
133
Grupo EIDOS
del usuario que se ha conectado. La informacin que se va a mostrar de cada mensaje es la prioridad, remitente, asunto y fecha de recepcin. Para mostrar el contenido de la bandeja de entrada simplemente recorreremos la coleccin Messages de objeto Folder que se corresponde con inbox. Y utilizaremos las propiedades correspondientes de cada objeto Message para mostrar la informacin deseada. El cdigo que se debe aadir al ejemplo anterior, despus de haber obtenido una referencia a la carpeta Inbox, es el Cdigo 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%> Cdigo fuente 112
Se utiliza una funcin llamada Prioridad, cuya funcin es la de devolver una cadena con el texto que representa a la prioridad correspondiente, su cdigo es el Cdigo fuente 113.
<%Function Prioridad(prio) Select Case prio Case cdoLow: Prioridad="Baja" Case cdoNormal: Prioridad="Normal" Case cdoHigh: Prioridad="Alta" End Select End Function%> Cdigo fuente 113
Y un ejemplo de la ejecucin del Cdigo fuente 113 lo tenemos en la Figura 30. Como ya hemos comentado al principio el objeto Message ofrece dos colecciones a travs de de sus propiedades Recipients y Attachments. La coleccin Recipients contiene objetos Recipient que representan a cada uno de los destinatarios de un mensaje. Para aadir un nuevo destinatario utilizamos el mtodo Add() sobre la coleccin Recipients, que adems nos devolver un objeto Recipient por si deseamos manipularlo. La sintaxis del mtodo Add() es la siguiente: Set objRecipient=colRecipients.Add(nombre, direccin, tipo)
134
Grupo EIDOS
6. CDONTS y ASP
Todos los parmetros de este mtodo son opcionales. En nombre indicamos el nombre del destinatario que se va a mostrar, en direccin se indica la direccin 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 enva copia) o CdoBCC (se le enva copia pero no aparece en la lista de los dems destinatarios. Los mensajes contenidos en la bandeja de entra no se pueden modificar, slo son de lectura, por lo tanto si lanzamos el mtodo Add() sobre una coleccin Recipients de un objeto Message que pertenezca al objeto Folder Inbox, se producir un error. El mtodo Delete de la coleccin Recipients elimina todos los objetos Recipient de la coleccin. Los parmetros que aparecan en el mtodo Add() de la coleccin 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: direccin de correo del destinatario. Type: tipo de destinatario, puede tener uno de los siguientes valores: CdoTO, CdoCC, CdoBCC.
La otra coleccin que podemos encontrar en el objeto Message es la coleccin Attachments que se encuentra formada por objetos Attachment y que representa los ficheros adjuntos de un mensaje determinado. Mediante el mtodo Delete() de la coleccin Attachments eliminamos todos los ficheros adjuntos de un mensaje, y mediante el mtodo Add() se aade un nuevo fichero adjunto.
135
Grupo EIDOS
Al igual que ocurra con la coleccin Recipients, al mtodo Add() devuelve un objeto Attachment para poder manipularlo, la sintaxis de este mtodo es: Set objAttachment=colAttachments.Add(nombre, tipo, fuente, localizacin, base) Todos los parmetros de este mtodo son opcionales. El parmetro 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. Localizacin y base son dos parmetros que especifican cabeceras para ficheros adjuntos de tipo MIME. El mtodo 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 parmetros del mtodo Add() de la coleccin Attachments, y son las siguientes: ContentBase: cabecera para un adjunto MIME que especifica la direccin 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 localizacin del adjunto. Type: tipo de adjunto, puede presentar las siguientes constantes cdoFileData o cdoEmbeddedMessage.
Adems el objeto Attachment ofrece los siguientes mtodos: Delete(): para eliminar un adjunto determinado. ReadFromFile(nombreFichero): carga el adjunto desde el fichero indicado por parmetro. Se debe indicar la ruta completa del fichero. WriteToFile(nombreFichero): escribe en el fichero indicado el contenido del adjunto.
Relacionado con el objeto Message tambin encontramos el objeto AddressEntry. El objeto AddressEntry se obtiene a travs 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: direccin de correo electrnico del remitente. Type: tipo de direccin. 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 operacin, es decir,
136
Grupo EIDOS
6. CDONTS y ASP
enviar un correo nuevo, pero utilizando algunos de los objetos vistos hasta ahora que dependen del objeto Session inicial de la librera CDONTS.
<!--METADATA TYPE="typelib" FILE="C:\Winnt\system32\cdonts.dll"--> <%'se realiza la conexin Set objSession=Server.CreateObject("CDONTS.Session") objSession.LogonSMTP "Angel","aesteban@mail.angel.es" 'se obtiene la bandeja de salida Set objFolderOutbox=objSession.Outbox 'se obtiene la coleccin de mensajes Set colMensajes=objFolderOutbox.Messages strTexto="Mensaje enviado con los objetos de CDONTS" 'se aade un mensaje nuevo y se obtiene la referencia al mismo Set objMensaje=colMensajes.Add("Prueba de CDONTS",strTexto,cdoNormal) 'aadimos un adjunto al mensaje objMensaje.Attachments.Add "Fichero Adjunto",cdoFileData,"c:\tmp\imagen.png" 'aadimos un destinatario al mensaje objMensaje.Recipients.Add "Jose Mara","chema@mail.angel.es",cdoTO 'aadimos un destinatario al que se enva una copia objMensaje.Recipients.Add "Pepe","pepe@mail.angel.es",cdoCC 'se enva el mensaje objMensaje.Send%> Cdigo fuente 114
Como podemos comprobar es mucho ms 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 sesin actual, en este caso aesteban@mail.angel.es. 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.
137
Grupo EIDOS
Antes de terminar este tema vamos aadir una mayor funcionalidad al ejemplo en el que mostrbamos el contenido de la bandeja de entrada de un usuario conectado a una sesin 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 pgina de lectura del mensaje adems vamos a permitir la opcin de borrar el mensaje que estamos leyendo. Veamos el Cdigo fuente 115 que debemos modificar en la pgina que muestra el contenido de la bandeja de entrada. Se debe aadir la creacin de los enlaces para cada asunto en el bucle For Each que recorre todos los mensajes.
138
Grupo EIDOS
6. CDONTS y ASP
Como se puede comprobar en los enlaces se hace referencia a una pgina llamada LeerMensaje.asp, es en esta pgina dnde se encuentra el cdigo necesario para mostrar el contenido del mensaje solicidado. La pgina de lectura de mensajes va a tener un rea de texto para mostrar el contenido del mensaje, y tambin dos botones: uno para volver a la pgina anterior, y otro para eliminar el mensaje que estamos leyendo. La pgina encargada de borrar el mensaje no es la de lectura de los mimos, sino que el mensaje ser borrado en la pgina que muestra el contenido de al bandeja de entrada. Antes de nada veamos el Cdigo fuente 116 de la pgina de lectura de mensajes.
<%'recuperamos la sesin con el servidor SMTP Set objSession=Session("oSession") Set colMensajes=objSession.Inbox.Messages 'recuperamos el identificador del mensaje idmensaje=Request.QueryString("idmensaje") 'se recupera el mensaje correspondiente de la coleccin Set objMensaje=colMensajes.Item(idmensaje)%> <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> </HEAD> <BODY> <%'se obtiene el objeto que representa al remitente Set 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 mismos If 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> Cdigo fuente 116
139
Grupo EIDOS
Como se puede ver tambin se crean enlaces para los adjuntos del mensaje si los tiene. Los ficheros adjuntos se graban en el servidor Web con el mtodo 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 pgina.
La pgina LISTADOMENSAJES.ASP le pasa a LEERMENSAJE.ASP a travs del QueryString un parmetro para identificar el mensaje que deseamos leer. Igualmente la pgina LEERMENSAJE.ASP le devuelve a la pgina LISTADOMENSAJES.ASP este mismo identificador de mensaje para que cuando sea demandando la pgina LISTADOMENSAJES.ASP pueda eliminar el mensaje deseado. Para que la pgina LISTADOMENSAJES.ASP pueda eliminar el mensaje solicitado, deberemos aadir el Cdigo fuente 117 justo antes de empezar a recorrer la coleccin de mensajes presentes en la bandeja de entrada..
<%If Request.Form("Eliminar")<>"" Then 'se obtiene el mensaje que se desea borrar Response.Write "paso: "& Request.Form("idmensaje")
140
Grupo EIDOS
6. CDONTS y ASP
Set objMensaje=objFolderInbox.Messages.Item(Request.Form("idmensaje")) 'se borra objMensaje.Delete End if%> Cdigo fuente 117
Simplemente se obtiene el objeto Message correspondiente de la coleccin Messages y se le lanza el mtodo Delete(). En el siguiente enlace se encuentra el cdigo completo de este ejemplo.
141
El modelo COM
Introduccin a los componentes
Los componentes de software son unidades de cdigo ejecutable que proporcionan una funcionalidad especfica para una aplicacin. A la aplicacin que utiliza cdigo de un componente, creando objetos y llamando a sus propiedades y mtodos, se denomina cliente o contenedora. Las ventajas derivadas de la utilizacin de los componentes en el desarrollo de software pueden compararse a las de la produccin industrial en cadena: en vez de ser un nico fabricante el que se encargue, por ejemplo, de la construccin 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 elctricos, chapa, caja de cambios, ...), que tienen funcionalidades diferentes. Cada uno de estos fabricantes trabaja de forma independiente a los dems, pero siguiendo unos estndares industriales para que luego las piezas encajen entre s para formar una nica unidad funcional: el coche. Del mismo modo, la utilizacin de los componentes en una aplicacin informtica permite que varias personas distintas, de la misma o distinta empresa, trabajando con distintos lenguajes de programacin, puedan crear pequeos bloques de cdigo con una funcionalidad especfica. Cada uno de estos componentes deben ajustarse a unos estndares o protocolos, para que luego puedan encajar entre s y formar una aplicacin 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 mquinas distintas puedan comunicarse a travs 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 coalicin de varios cientos de empresas,
Grupo EIDOS
el OMG (Object Management Group), y lleva varios aos de ventaja respecto al modelo COM/DCOM de Microsoft. Los pasos para el diseo 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 lgica. Decidir cmo se ejecutarn 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 mtodos y propiedades para un objeto. Un solo componente COM puede contener varias clases. En tiempo de ejecucin, se crear un objeto creando una instancia de una clase. Interfaz: Grupos de funciones que exponen la funcionalidad del componente; a travs de este interfaz, los clientes y los componentes COM se comunican. Las interfaces proporcionan acceso estandarizado a los mtodos y propiedades (funcionalidad) disponibles en los componentes. Es ms, son el contrato entre el autor del componente y los desarrolladores de clientes que aseguran un acceso fiable a la funcionalidad aportada. Componente: Coleccin 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.
Especificacin COM
Las principales caractersticas del modelo COM son: Compatibilidad binaria: El modelo COM es una especificacin 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 despus utilizados desde una aplicacin, o desde otro componente, escrito en cualquier lenguaje de programacin que soporte COM. Compatibilidad con sistemas operativos distintos: Los componentes COM deben desarrollarse para una plataforma especfica, 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. Localizacin transparente: Permite usar un componente desde un cliente sin importar si ese componente pertenece al mismo proceso, a otro proceso en la misma mquina o a otro proceso en una mquina distinta.
144
Grupo EIDOS
7. El modelo COM
Reutilizacin del cdigo: Es la mayor ventaja de COM. Los componentes COM contienen clases que exponen grupos de mtodos, conocidos como interfaces, a travs de los cuales los clientes se comunican con objetos. Dado que estos interfaces estn bien documentados, el cdigo que implementan puede reutilizarse con facilidad.
El Modelo de Objetos Componentes (COM) es una especificacin de cmo estos objetos interactan con sus clientes. Como tal especificacin, COM define una funcionalidad estndar, pero no define cmo debe implementarse, sino qu es lo que debe tener. Entre lo que especifica COM se incluye lo siguiente: Cmo se crean las instancias de los objetos COM. Cmo acceden los clientes a las caractersticas de estos objetos La responsabilidad de su auto-destruccin cuando ya no quedan instancias suyas.
Adems de lo que es meramente la especificacin, existen "bibliotecas COM", su runtime, que contienen: Una reducida API para facilitar la creacin 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 localizacin, a travs de los cuales se averigua en qu servidor se encuentra el objeto y la ubicacin dentro de ste. Indirectamente esto incluye un soporte entre el identificador de objeto y el paquete en el que se encuentra su cdigo, que normalmente se obtiene a travs del Registro de Windows. De esta manera, los clientes quedan totalmente independientes de los posibles cambios de ubicacin de los objetos COM, ya sean cambios de paquete o -incluso- cambios de mquina servidora. Servicios para la transparencia en las llamadas a procedimientos remotos, es decir, cuando un objeto est ejecutndose en un proceso aparte o en una mquina distinta desde la que se usa.
145
Grupo EIDOS
Pueden ser escritos es cualquier lenguaje, y luego utilizados en una aplicacin en otro lenguaje. Un componente escrito en C++ puedo ser usado en una aplicacin VB o, en nuestro caso, desde el script de una pgina ASP. Esto permite que el componente pueda ser desarrollado en el lenguaje en el que se encuentre ms cmodo 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. Ms rapidez de ejecucin: los componentes estn compilados, mientras que el script de una pgina ASP es interpretado. Adems, hay cierta funcionalidad que no podemos conseguir con un lenguaje de script, que no deja de tener sus limitaciones. Proteccin del cdigo: 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 pginas ASP, convirtindolas en caracteres ASCII ilegibles, pero esto no supone una solucin segura ni definitiva. Sin embargo, el cdigo de un componente compilado en una DLL es inaccesible. Los depuradores de VB y sobre todo VC++ son mejores que el script debugger de pginas ASP.
Los interfaces
Un interfaz representa un contrato entre un servidor y un cliente. Un objeto siempre implementar la funcin para un interfaz determinado y de una manera estndar. El contrato posibilita el desarrollo de objetos en cualquier lenguaje, mientras stos expongan sus interfaces acorde con el estndar COM. En virtud del contrato puede afirmarse que: El interfaz tiene un Identificador nico Global (IID). Las funciones tendrn siempre los mismos parmetros y conservarn sus tipos. Las funciones devolvern siempre el mismo tipo de valor. Las funciones se implementarn cada una siguiendo la semntica del interfaz. El interfaz tendr siempre el mismo conjunto de funciones. No se pueden aadir 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 travs de interfaces hacen de COM un sistema abierto y extensible; cualquiera puede proporcionar una implementacin 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 slo necesitar entender las especificaciones del interfaz. El diseo y utilizacin de interfaces es mucho ms importante en grandes aplicaciones. En aplicaciones empresariales minimiza las interdependencias. As, el cambiar un componente no requiere redisear todos los dems. Un sistema bien diseado y construido con interfaces COM
146
Grupo EIDOS
7. El modelo COM
permite a los usuarios de los componentes trabajar independientemente de los desarrolladores de componentes y, tambin, hacer pruebas rpidamente. La mayora de las herramientas de desarrollo que soportan COM permiten la creacin de clases, objetos y componentes. Sin embargo, hay diferencias en cmo 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 automticamente un interfaz por defecto. Este interfaz est compuesto por todos los mtodos pblicos 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 cdigo necesario para usar e implementar interfaces. Por definicin, un interfaz COM no puede cambiar una vez haya sido utilizado. Se dice que el interfaz es inmutable. Aunque ni los mtodos ni la firma puedan cambiar, la implementacin 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 podrn intercambiarse. Los componentes con enlace temprano no pueden cambiar sus interfaces; sin embargo, los que usan enlace tardo tienen la capacidad de aadir, borrar y cambiar mtodos. Cuando se actualicen estos componentes, hay que asegurarse de que no se rompe el contrato de la interfaz. Dado que las funcionalidades estn agrupadas en interfaces del modelo de programacin COM, se pueden aadir nuevas funcionalidades aadiendo nuevas interfaces y manteniendo las anteriores, aunque como veremos, desde una pgina ASP slo podemos acceder a un interfaz.
147
Grupo EIDOS
Los GUIDs pueden generarse utilizando las herramientas "guidgen" o "uuidgen", o realizando llamadas a la funcin 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 estndar. El GUID generado depende del instante en que se llam a la funcin y del nmero de su tarjeta de red (o de otra caracterstica nica en ordenadores sin tarjeta de red). Utilizar un ordenador con tarjeta de red para generar el GUID, garantiza que el nmero obtenido ser nico. Cuando se desarrollan componentes se trabaja con muchos CLSIDs. El teclear estos GUIDs directamente en el cdigo es engorroso y suelen cometerse errores. Para simplificar esta operacin, 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 estn asociadas a un CLSID en el registro de Windows. Una vez establecida la relacin entre el CLSID y el PROGID se puede utilizar ste para crear componentes. Algunos lenguajes como Visual Basic, crean automticamente 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.
Dim objCnx As Object Set objCnx = CreateObject(ADODB.Connection) objCnx.metodo Cdigo fuente 118
Una ventaja del enlace tardo es que no es necesario identificar el objeto que se quiere crear hasta el tiempo de ejecucin. Por otro lado, una desventaja es que el compilador no puede comprobar la sintaxis. Como resultado de ello, errores como el pasar un nmero incorrecto de parmetros o con tipos incorrectos no se detectarn hasta el tiempo de ejecucin. Aparte de esto, el enlace tardo es menos eficiente que el enlace temprano, ya que requiere un mayor nivel de comunicacin entre el cliente y el componente para cada operacin. Algunos entornos, tales como los motores de scripts, slo soportan el enlace tardo para llamar a los componentes. Este es el caso de las pginas ASP. Por el contrario, el enlace temprano (early binding) ocurre cuando se conoce el tipo del objeto en tiempo de compilacin. Se establece un enlace temprano cuando se declaran variables de un tipo especfico de datos. En ese caso el compilador puede contrastar todas las referencias del objeto con las
148
Grupo EIDOS
7. El modelo COM
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 especfica usada cuando se declaran variables de ese tipo de objeto. Visual C++ utiliza la clusula #import o cabeceras de interfaces para obtener la informacin de tipos de los componentes. El Cdigo fuente 119 es un ejemplo de enlace temprano a un objeto Connection de ADO en Visual Basic.
Dim objCnx As ADODB.Connection Set objCnx = New ADODB.Connection objCnx.metodo Cdigo 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 sintctico en tiempo de diseo. Los mtodos de los componentes que se llamen utilizando enlace temprano son los ms eficientes en trminos de rendimiento. Dado que se dispone de la informacin en tiempo de compilacin, el compilador puede generar un cdigo ms ptimo para las llamadas. Los entornos de programacin como Visual Basic y Visual C++ soportan la creacin de componentes que sern llamados con enlaces tempranos o tardos. No as los motores de script que utilicemos desde una pgina ASP, que slo permiten el enlace tardo.
149
Grupo EIDOS
Un componente DLL proporciona un acceso al objeto ms rpido, 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, slo al proceso en el que se encuentra el componente EXE. Es ms lento porque las llamadas del mtodo han de ser reconfiguradas entre los procesos.
El interfaz IUnknown
Por convencin, el nombre de un interfaz siempre lleva el prefijo "I". Para poder utilizar un objeto, un cliente necesita conocer qu interfaces soporta ese objeto. Segn la especificacin COM, un objeto debe poder ser consultado por un cliente para averiguar esta informacin. Esto se consigue gracias al interfaz denominado IUnknown, que deben soportar todos los objetos. Es ms, 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 mltiples clientes de diferentes procesos, e incluso de diferentes ordenadores, pueden conectarse y utilizar un objeto, cuando un cliente destruye un objeto podra 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 nmero 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 seala al objeto se sale del mbito. Se llama esta funcin cuando se asigna Nothing a una variable del objeto, o cuando la variable sobrepase el mbito de su definicin.
Adems, el interfaz IUnknown presenta la funcin 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 mtodos 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 tecnologas 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
150
Grupo EIDOS
7. El modelo COM
HTML dinmico (DHTML) Servidor IIS Pginas ASP Componentes de acceso a datos (MDAC) Servicios de componentes (antes MTS) Colas de mensajes (MSMQ) Active Directory (ADSI) Servicios de seguridad de Windows
151
Grupo EIDOS
El primero, y ms importante, es que el Visual Basic es un lenguaje conocido, al menos a un nivel bsico, por la mayora de los programadores, y no habr necesidad de dedicar tiempo y esfuerzo al aprendizaje de un lenguaje de la complejidad de Visual C++. Adems el Visual Basic, a pesar de su facilidad de uso, nos permite hacer prcticamente lo mismo que podramos 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++ tendramos 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. Tambin el Visual Basic crea automticamente el interfaz por defecto, agrupando en l todos los mtodos pblicos del componente. Ser a este interfaz por defecto al nico al que tengamos acceso desde el script de una pgina 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 estn: 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 ms 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 estn el pooling de objetos. Este concepto es parecido al del pooling de conexiones de una base de datos: cuando una aplicacin cliente ha acabado de utilizar una conexin con la base de datos, en vez de ser destruida, esta conexin se guarda en un pool (como si dijramos un almacn) de donde puede ser utilizada luego por otra aplicacin 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
Grupo EIDOS
se lleva a cabo internamente esa funcionalidad, ni siquiera en qu lenguaje de programacin 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 programacin 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, disearemos un interfaz formado por un nico mtodo, que recibe como parmetro la cantidad sobre la que queremos efectuar el clculo. Ms adelante construiremos componentes mucho ms complicados que requieran un anlisis ms completo, pero para ste no necesitamos ms que ponernos ya manos a la obra.
Figura 34
Cada mdulo de clase de Visual Basic define un tipo de objeto. Es la plantilla que define los mtodos y propiedades para un objeto. Los objetos se crean, en tiempo de ejecucin, al crear una instancia de una clase. Un componente puede contener varios mdulos de clase, y servir por tanto de plantilla para la creacin de varios tipos de objeto. Es lo que se llama un COM Server. En este caso, nuestro componente slo contendr un mdulo de clase.
155
Grupo EIDOS
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 operacin seleccionando el mdulo de clase en la ventana del Explorador de proyectos y luego modificando el nombre en la ventana de Propiedades (cambiarlo a Porcentaje).
Figura 35
En la ventana del Generador de mtodos que aparece, similar a la de la Figura 36, asignarle un nombre al mtodo. Le llamaremos calcular. En esta misma ventana, pulsar el botn que aparece etiquetado con un signo +, para definir el argumento que va a recibir este mtodo.
156
Grupo EIDOS
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 verificacin de ByVal, y seleccionar Variant de la lista desplegable Tipo de dato. Ms 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 pgina ASP; recordemos que el VBScript, como JavaScript, es un lenguaje de script dbilmente tipado, donde slo existe el tipo de dato Variant.
Figura 37
Al activar la casilla de verificacin de ByVal, estamos indicando que el parmetro se pasar por valor, es decir, el mtodo 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 sera ByRef, por referencia, que es la que se
157
Grupo EIDOS
usa si usamos explcitamente la palabra ByRef o si no indicamos absolutamente nada, ya que es el valor por defecto. Despus de pulsar Aceptar, y ya de vuelta en la ventana del Generador de mtodos, seleccionaremos Variant de la lista desplegable de Tipo de datos de retorno (es decir, estamos definiendo un mtodo que ser una funcin 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 mtodo que acabamos de declarar.
Figura 38
Es recomendable, antes de salir de la utilidad Generador de clases, seleccionar la opcin 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 edicin de cdigo que queda debajo de la del Generador de clases, que se genera el Cdigo fuente 120, necesario para implementar el mtodo recin creado.
Public Function calcular(ByVal cantidad As Variant) As Variant End Function Cdigo fuente 120
Cerremos ya la utilidad sin miedo. Ya en la ventana de edicin de cdigo, escribamos las lneas necesarias para que el mtodo tenga la funcionalidad que queremos. Esto se reduce a la lnea que aparece en el Cdigo fuente 121.
158
Grupo EIDOS
Public Function calcular(ByVal cantidad As Variant) As Variant calcular = cantidad * 1.07 End Function Cdigo fuente 121
Guardemos el mdulo de clase (PORCENTAJE.CLS) y el proyecto (COMPPORCENTAJE.VBP) en la carpeta que queramos, y ya estamos en disposicin de generar la DLL.
Figura 39
Si ahora seleccionamos la opcin Buscar del men Edicin, e introducimos como valor de bsqueda el valor del CLSID, encontraremos algo similar a laFigura 40.
159
Grupo EIDOS
Figura 40
Si quisiramos utilizar nosotros este componente en otro equipo, deberamos copiar el fichero COMPPORCENTAJE.DLL a la ubicacin del equipo destino que elijamos (normalmente se copian en la carpeta C:\WINNT\SYSTEM32, pero puede ser cualquier carpeta). A continuacin abriremos una ventana MSDOS y nos moveremos hasta esa carpeta, para escribir lo que indica el Cdigo fuente 122.
Esto registrar el componente en el equipo. Vamos a comprobar ahora que podemos usar este componente desde una pgina ASP. Iniciamos el InterDev y creamos una pgina con el Cdigo 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> Cdigo fuente 123
Como el componente est registrado en la misma mquina 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 mtodos disponibles (en este caso slo el mtodo calcular).
160
Grupo EIDOS
Public Function calcular(cantidad As Variant) As Boolean End Function Cdigo fuente 124
Vemos que ahora, dentro de los parntesis, el nombre del parmetro no est precedido de la palabra ByVal. Con esto se sobreentiende ByRef, que es el valor por defecto para Visual Basic. Podramos haber conseguido lo mismo modificando nosotros manualmente todo el cdigo, en vez de usar la utilidad Generadora de clases. Aadamos ahora el cdigo necesario a la funcin. Esta vez hacemos el clculo del porcentaje y se lo asignamos al mismo parmetro, cantidad. Devolvemos como valor de retorno de la funcin el valor True. Todo esto tal cual aparece en el Cdigo fuente 125.
Public Function calcular(cantidad As Variant) As Boolean cantidad = cantidad * 1.07 calcular = True End Function Cdigo 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 fcil arreglo: cerremos la ventana de edicin de la pgina ASP en que hemos utilizado el componente La aplicacin web est usando tambin el componente, puesto que al pedir la pgina desde el navegador se ha ejecutado la pgina y se ha cargado la dll en memoria. Si hemos tenido la
161
Grupo EIDOS
precaucin de configurar, desde la consola de administracin de los servicios IIS, las propiedades de nuestra aplicacin web, en la pestaa Directorio, como se ve en la Figura 41, de tal forma que la Proteccin de la aplicacin est en el nivel Medio (agrupado) o Alto (aislado), podremos, desde esta misma ventana de configuracin del IIS, pulsar el botn Descargar, que descarga de memoria esta aplicacin web (y todas las que estuvieran agrupadas con ella).
Figura 41
Si con lo anterior no consiguiramos 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 botn derecho del ratn y seleccionaremos la opcin Detener. Esto detiene otros servicios aparte del de publicacin web, como la publicacin FTP y el correo SMTP. Despus de detener el servicio, debemos pulsar otra vez con el botn derecho del ratn y seleccionar la opcin 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 publicacin web. Esta operacin se ve en la Figura 43. Este proceso resulta pesado pero debe bastar para descargar definitivamente la dll.
162
Grupo EIDOS
Figura 42
Figura 43
La solucin 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 ms frecuente tener que recurrir a esta solucin extrema.
Para poder utilizar el nuevo componente, tendremos que modificar la pgina ASP, que quedar como en el Cdigo fuente 126.
163
Grupo EIDOS
<HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> </HEAD> <BODY> <% Set objPorcentaje = CreateObject("CompPorcentaje.Porcentaje") cantidad = 1000 retorno = objPorcentaje.calcular(cantidad) Response.Write cantidad Set objPorcentaje = Nothing %> </BODY> </HTML> Cdigo fuente 126
Ahora creamos una variable de pgina llamada cantidad, a la que asignamos el valor 1000. Esta variable la pasamos como parmetro, y el mtodo del componente trabaja directamente con ella, con lo que al escribir despus su valor obtenemos el valor correcto de 1070. En cualquier caso, suele ser ms aconsejable pasar los parmetros a un mtodo por valor (ByVal) mejor que por referencia (ByRef). De esta forma conseguimos ms encapsulacin del cdigo del componente.
Figura 44
164
Grupo EIDOS
Nombraremos al nuevo proyecto como PruebaPorcentaje. Aadimos al formulario un campo de texto y un botn, 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 aadirle la referencia al componente anterior CompPorcentaje, desde el men Proyecto | Referencias, y seleccionado la casilla de verificacin correspondiente al componente CompPorcentaje, como se ve en la Figura 46. De este modo Visual Basic nos facilitar el IntelliSense, y adems podremos utilizar el early binding.
Figura 46
Haciendo doble click sobre el botn, podemos escribir el cdigo necesario para el evento Click del mismo, que ser el del Cdigo fuente 127.
165
Grupo EIDOS
cantidad = 1000 Set objPorcentaje = New CompPorcentaje.Porcentaje retorno = objPorcentaje.calcular(cantidad) Text1.Text = cantidad End Sub Cdigo fuente 127
Las lneas Dim objPorcentaje As CompPorcentaje.Porcentaje y Set objPorcentaje = New CompPorcentaje.Porcentaje slo 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 mdulo de clase Porcentaje incluido en el proyecto ActiveX CompPorcentaje. Adems permite usar el operador New para hacer un enlace temprano, en tiempo de compilacin, con el cdigo de ese componente. Si no hubiramos incluido la referencia a CompPorcentaje, no podramos hacer nada de lo anterior, y tendramos que dejar el cdigo como se ve en el Cdigo fuente 128. El uso del mtodo CreateObject significa que no estamos haciendo enlace temprano, sino enlace tardo.
cantidad = 1000 Set objPorcentaje = CreateObject("CompPorcentaje.Porcentaje") retorno = objPorcentaje.calcular(cantidad) Text1.Text = cantidad End Sub Cdigo fuente 128
En el Explorador de proyectos, pulsando con el botn derecho sobre el proyecto PruebaPorcentaje, debemos seleccionar la opcin Establecer como inicial, de tal forma que cuando pulsemos el icono de ejecucin de Visual Basic, sea ste el proyecto de arranque, se muestre el formulario, y podamos pulsar el botn. Esta pulsacin desencadenar la instanciacin del componente CompPorcentaje, y la invocacin al mtodo calcular, pasndole como parmetro, por referencia, la variable cantidad. A continuacin se le asigna su valor, ya actualizado por el mtodo, al campo de texto. Por supuesto que este proyecto EXE estndar podremos depurarlo desde el entorno de Visual Basic, estableciendo puntos de interrupcin con la tecla de funcin F9 y ejecutando paso a paso con F8.
166
Grupo EIDOS
Tipos de componentes
Hemos visto en los apartados anteriores que este primer componente que hemos desarrollado en Visual Basic era utilizable tanto desde una pgina ASP como desde un proyecto estndar de Visual Basic. Por supuesto que tambin podramos utilizarlo desde otra aplicacin escrita en cualquier lenguaje que soporte COM, como podra ser Visual C++. Es un componente que podramos llamar de uso universal. Podemos, sin embargo, disear componentes que sean ms restrictivos en cuanto a su aplicabilidad. Supongamos que desarrollamos un componente como el anterior, pero que permita la introduccin del nmero sobre el que vamos a calcular el porcentaje desde un campo de texto, es decir, que tenga un interfaz visual. Si creamos una pgina HTML desde cualquier editor de HTML, por ejemplo FrontPage, y seleccionamos la opcin Avanzadas del men Insertar, y a continuacin Control ActiveX, podemos marcar de la lista que aparece el control Control Calendar 9.0. El cdigo html que generar el FrontPage por nosotros quedara como el Cdigo 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> Cdigo fuente 129
167
Grupo EIDOS
Figura 47
Podramos utilizar este componente desde una pgina ASP? La respuesta en no, lgicamente, puesto que las pginas ASP se ejecutan de forma desatendida en el servidor, y no podemos generar ningn interfaz visual (recordemos que dentro de una pgina ASP no podemos ni siquiera usar funciones estndar de Visual Basic como MsgBox). Con un cdigo en un pgina ASP como el del Cdigo fuente 130, no lograremos nada; no llegar a ver el control, porque en este contexto no tienen sentido los componentes con interfaz visual.
Este sera un componente que sera utilizable en una aplicacin Visual Basic, o Visual C++, que tengan un interfaz visual, pero no dentro de una pgina ASP. Vayamos al caso opuesto. Si yo diseo un componente que acceda al modelo de objetos de ASP para escribir directamente cdigo HTML a travs del objeto Response, o para leer el valor de una variable de aplicacin (ms adelante veremos que todo esto es posible), estar haciendo uso de un modelo de objetos que no tendra ningn sentido si utilizase este componente desde una aplicacin Visual Basic o Visual C++. Este componente no sera utilizable en estas aplicaciones, pero s en pginas ASP.
168
Grupo EIDOS
Un componente ActiveX Server, como el adRotator, genera una cadena HTML, que tendra sentido slo 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 podran considerarse de aplicabilidad universal. Podramos disear componentes que fueran capaces de reconocer por s mismos el tipo de entorno en el que se ejecutan, es decir, si estn instanciados desde una pgina ASP o desde una aplicacin Visual Basic. Seran componentes que se adaptaran en cada caso al entorno, usando el modelo de objetos de ASP slo si reconocieran que lo tienen disponible. Esta capacidad de adaptacin los convertira en reutilizables dentro de una aplicacin 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 ms adelante, es aqul que est involucrado en una transaccin sobre una base de datos. Estos componentes transaccionales tienen unas caractersticas especiales.
169
Grupo EIDOS
Conviene aclarar que habra que distinguir entre capas lgicas y capas fsicas. Cuando hablamos de capas normalmente nos referimos a capas lgicas. Por capas lgicas entendemos software, y por capas fsicas hardware. Lo usual es que la capa de datos est en una capa fsica separada, es decir, en un equipo separado donde slo se est ejecutando el software del gestor de base de datos, por ejemplo SQL Server u Oracle, y que la capa con la lgica de presentacin y la de datos est en otra capa fsica separada, es decir, el equipo del usuario, donde se ejecute la aplicacin cliente escrita en un lenguaje como Visual Basic. Pero es tambin muy normal que durante el tiempo de desarrollo estas dos capas lgicas estn en la misma capa fsica, es decir, que en nuestro equipo de desarrollo est ejecutndose el software del gestor de base de datos y el software de la aplicacin cliente. En estas aplicaciones cliente/servidor tradicionales hay una conexin permanente entre las dos capas, lo que las hace distintas de las aplicaciones web, como veremos a continuacin. 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 lgica de presentacin y la de negocio.
Grupo EIDOS
dientes, para que el gestor de base de datos pueda ejecutarse de una forma mucho ms eficiente, ya que consume bastante memoria, CPU y accesos al disco. En tiempo de desarrollo es muy frecuente que las tres capas estn en el mismo equipo fsico, y que se estn ejecutando en la misma mquina el gestor de base de datos, el servidor web y el navegador. En las aplicaciones web no hay una conexin permanente entre cliente y servidor. Recordemos que el protocolo HTTP es un protocolo sin estado. Cuando un navegador cliente hace una peticin de un recurso a un servidor, se crea una conexin temporal entre los dos, el servidor atiende la peticin y manda la respuesta e inmediatamente se cierra la conexin. El servidor pierde completamente el rastro de este cliente, y destruye toda la informacin de estado que hubiera utilizado durante el tiempo en que estaba procesando la peticin, de forma que si este mismo cliente vuelve a hacer otra peticin al servidor, sera 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 informacin de estado en el propio cliente, por medio de cookies, y otras pasan por almacenar esta informacin en el servidor, en bases de datos, en ficheros, o en el caso de pginas ASP conservando variables dentro del objeto Session. Tambin se usa con frecuencia el paso de informacin de una pgina a otra, por medio de parmetros ocultos (del tipo hidden) dentro de formularios. En cada caso ser ms adecuada una u otra solucin. El hecho de que la conexin entre cliente y servidor no sea permanente supone una desventaja de las aplicaciones web respecto a las aplicaciones cliente/servidor tradicionales. Resulta ms difcil conseguir que la lgica de la aplicacin funcione correctamente cuando se trata de un conjunto de pginas distintas que son enviadas al cliente una detrs de otra, sin mantenimiento de estado entre ellas. Sin embargo las aplicaciones web tambin tienen una ventaja, y es el hecho de que la parte cliente se actualiza automticamente, sin necesidad de ir a reinstalar cada vez que hay una modificacin. Esto es as porque el cdigo con la lgica de presentacin se ejecuta en el cliente, es cierto, pero es en el servidor donde se genera de forma dinmica en el momento en que se hace cada peticin (es decir, el script de la pgina ASP se encarga de generar dinmicamente el cdigo 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 pginas HTML o ASP, cuando el cliente haga una nueva peticin recibir la versin 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 lgica de presentacin realmente se genera en el servidor web, es decir, en la capa de negocio, aunque luego se ejecute en la capa de presentacin. Los procedimientos almacenados tambin se salen un poco del modelo de tres capas, porque suponen una lgica 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 divisin de una aplicacin en capas lgicas no debe entenderse como una clasificacin estricta. Normalmente el cliente en las aplicaciones web es lo que se llama un thin client, porque necesita muy poca capacidad de CPU. Realmente slo la necesaria para ejecutar un navegador, capaz de generar el interfaz de usuario con HTML y JavaScript. Si quiero conseguir un interfaz ms rico, tengo que cargar ms el cliente, con controles ActiveX y applets, pudiendo entonces descargar de trabajo al servidor.
173
Grupo EIDOS
<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;Data Source=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.Close objCnx.Close Set objRst = Nothing Set objCnx = Nothing %>
174
Grupo EIDOS
y conseguiramos el resultado que se muestra en la Tabla 6. stor_id 6380 7066 7067 7131 7896 8042 stor_name Eric the Read Books Barnum's News & Brews stor_address city state zip
788 Catamaugus Ave. Seattle 567 Pasadena Ave. 577 First St. Tustin
Los Gatos CA
Doc-U-Mat: Quality Laundry and Books 24-A Avogadro Way Remulade WA 98014 Fricative Bookshop Bookbeat 89 Madison St. 679 Carson St.
Tabla 6
Fremont Portland
CA OR
90019 89076
175
Grupo EIDOS
El acceso a los datos ser ms rpido, porque el cdigo estar compilado dentro del componente, y adems podremos utilizar el operador New de Visual Basic, lo que supone un enlace temprano al componente. Desde el script de una pgina ASP slo podemos utilizar el enlace tardo que proporciona el mtodo 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 mdulo de clase a Stores. Como el componente va a acceder a la base de datos a travs de ADO, necesitamos aadir al proyecto la referencia a ADO. Esto lo hacemos seleccionando la opcin 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 cdigo. Podr utilizar el early binding, lo que supone un mayor rendimiento a la hora de ejecutar el componente
Option Explicit Public Function listaStores() As ADODB.Recordset Dim objCnx As ADODB.Connection Dim objRst As ADODB.Recordset Dim strCnx As String
176
Grupo EIDOS
strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;Data Source=varrondo" Set objCnx = New ADODB.Connection objCnx.Open strCnx Set objRst = New ADODB.Recordset objRst.Open "Stores", objCnx, , , adCmdTable Set listaStores = objRst End Function Cdigo fuente 132
Como se ve, el interfaz est formado por un nico mtodo que no recibe parmetros, 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 pgina ASP, que ahora tendra el Cdigo fuente 133. Los objetos objCnx y objRst son locales al mtodo del componente, y se liberan automticamente al salir del mismo, sin necesidad de que yo lo haga explcitamente.
<%@ 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> Cdigo fuente 133
177
Grupo EIDOS
Slo tengo que crear una instancia del componente e invocar al mtodo listaStores, recuperando el recordset que me devuelve en el objeto objRst. Luego slo hay que formatear los datos que contiene en una tabla HTML, igual que en el caso anterior.
Y el Cdigo fuente 135 es el que tendra 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.Recordset Dim objCnx As ADODB.Connection Dim objCmd As ADODB.Command Dim objRst As ADODB.Recordset Dim strCnx As String strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;Data Source=varrondo" Set objCnx = New ADODB.Connection objCnx.Open strCnx Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.CommandText = "RecuperaStores" Set objRst = New ADODB.Recordset objRst.Open objCmd, , , , adCmdStoredProc Set listaStores = objRst End Function Cdigo fuente 135
Grupo EIDOS
Este mtodo recibe cinco parmetros: El primero puede tomar nicamente el valor por defecto adClipString. El segundo es el nmero de registros que van a ser convertidos a la cadena. Si no especifico este parmetro, 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 parmetro es el carcter que se usar para los campos que tengan valor NULL. Por defecto es la cadena vaca.
Option Explicit Public Function listaStores() As String Dim objCnx As ADODB.Connection Dim objCmd As ADODB.Command Dim objRst As ADODB.Recordset Dim strCnx As String Dim strRst As String strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;Data Source=varrondo" Set objCnx = New ADODB.Connection objCnx.Open strCnx Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.CommandText = "RecuperaStores" Set objRst = New ADODB.Recordset objRst.Open objCmd, , , , adCmdStoredProc strRst = 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 Cdigo fuente 136
La lnea 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 ms filas. El Cdigo fuente 137,de la pgina ASP, queda ahora mucho ms reducido.
179
Grupo EIDOS
<HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> </HEAD> <BODY> <% Set objCom = Server.CreateObject("CompStores.Stores") Response.Write objCom.listaStores Set objCom = Nothing %> </BODY> </HTML> Cdigo fuente 137
Ms adelante retomaremos este ejemplo, y veremos cmo se pueden crear estos componentes orientados al cliente, accediendo al modelo de objetos de ASP. Incluso la capa intermedia puede dividirse no slo en estas dos capas lgicas, sino en dos capas fsicas en dos servidores distintos: uno tiene el servidor web junto con los componentes orientados al cliente, y otro tiene el servidor de aplicacin junto con los componentes de lgica de negocio y los orientados a datos.
180
Tipos Variant
Los que programamos en ASP sabemos que los lenguajes de script, como el VBScript, son lenguajes dbilmente tipados, donde slo existe el tipo Variant. Este hecho tiene su importancia a la hora de disear un componente pensado para ser utilizado desde una pgina 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 mtodo 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, diseamos el mtodo de tal forma que reciba este parmetro por referencia, es decir, va a trabajar con la variable original y no con una copia de la misma.
Grupo EIDOS
Ya hemos probado este componente y hemos visto que funcionaba correctamente al instanciarlo desde una pgina ASP. Pero esto era as mientras en el mtodo tenamos el parmetro definido como Variant. De esta forma, desde la pgina ASP pasamos al componente una variable Variant, el componente trabaja con ella, tomndola como Variant, y puede modificar su valor. Si ahora abrimos el proyecto ActiveX DLL correspondiente a este componente, y modificamos el cdigo del mdulo de clase hasta dejarlo como queda en el Cdigo fuente 138, podemos volver a pedir la pgina ASP que lo utilizaba para ver lo que ocurre.
Public Function calcular(cantidad As Integer) As Boolean cantidad = cantidad * 1.07 calcular = True End Function Cdigo fuente 138
Lo nico que hemos cambiado es el tipo de datos del parmetro: ya no es Variant, sino Integer. Recordemos que el cdigo de la pgina ASP era como el Cdigo fuente 139.
<% Set objPorcentaje = CreateObject("CompPorcentaje.Porcentaje") cantidad = 1000 retorno = objPorcentaje.calcular(cantidad) Response.Write cantidad Set objPorcentaje = Nothing %> Cdigo 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 mtodo es precisamente eso: una referencia a una variable, con lo cual el cdigo del mtodo 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 mtodo intente considerarla como Integer, y se produce el error. Escrito de esta forma, el componente no sera utilizable desde una pgina ASP. Veamos qu ocurre si el parmetro se pasa por valor, y no por referencia. Para ello volvemos a modificar el componente, hasta conseguir el Cdigo fuente 140.
Public Function calcular(ByVal cantidad As Integer) As Currency calcular = cantidad * 1.07 End Function Cdigo fuente 140
182
Grupo EIDOS
Para probar esta nueva versin del componente, preparemos una pgina ASP con un formulario, que nos permita probar con distintos valores del parmetro. El Cdigo fuente 141 es el que escribimos para la pgina.
<%@ 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> Cdigo fuente 141
En la rama if generamos el formulario, con un campo de texto para introducir la cantidad y un botn de submitir, que enviar el formulario a la misma pgina. 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 parmetro al mtodo del componente. Si pedimos la pgina y metemos el valor 1000 en el campo de texto, el funcionamiento es correcto. Le estamos suministrando al mtodo un parmetro de tipo Variant, cuando el mtodo espera recibir un parmetro del tipo Integer. Pero entre medias est el motor del script, que es el que se encarga de hacer automticamente la transformacin, tomando la variable cantidad, del tipo Variant, y suministrndole al mtodo del componente una copia, del tipo Integer. Por supuesto que si el motor de script no puede hacer conversin automtica, porque los tipos son incompatibles, tambin falla. Probmoslo 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 redisear el componente para que reciba el parmetro por referencia, es decir otra vez como en el Cdigo fuente 142.
Public Function calcular(cantidad As Integer) As Boolean cantidad = cantidad * 1.07 calcular = True End Function Cdigo fuente 142
183
Grupo EIDOS
Y rescribamos la rama else de la pgina ASP para que quede como en el Cdigo fuente 143.
<% Set objPorcentaje = CreateObject("CompPorcentaje.Porcentaje") cantidad = Request.Form("cantidad") retorno = objPorcentaje.calcular(cantidad) Response.Write cantidad Set objPorcentaje = Nothing %> Cdigo fuente 143
De esta forma, pongamos lo que pongamos en el campo de texto, obtendremos siempre el error de No coinciden los tipos: 'objPorcentaje.calcular'. Sin embargo, si cambiamos la lnea en la que se invoca el mtodo calcular del componente por la que aparece en el Cdigo fuente 144, veremos que, al menos, no obtendremos error.
Este es un comportamiento un tanto curioso, pero que en todo caso no nos sirve en absoluto. Parece como si al pasarle al mtodo directamente el valor de Request.Form(cantidad), fuera considerada como una variable de tipo Integer, que es la que necesita el mtodo. 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 ningn elemento de cualquier coleccin del objeto Request es modificable directamente. Estamos consiguiendo lo mismo que si pusiramos la lnea del Cdigo fuente 145.
Como pasamos un valor constante, no una variable, no podemos acceder al valor modificado que debera devolvernos el mtodo. Luego no nos da error, pero tampoco nos es de ninguna utilidad. En definitiva, para componentes diseados para ser utilizados desde pginas ASP, me interesa pasar por valor los argumentos de los mtodos. Y esto por dos motivos: Consigo una mayor encapsulacin del cdigo del componente. Es posible que el componente trabaje internamente con tipos Integer, String, etc. El motor de script se encargar de hacer la transformacin automtica, siempre que los tipos sean compatibles, del Variant al tipo necesario en el mtodo del componente.
184
Grupo EIDOS
Dentro del componente podemos usar los tipos de datos que permite el Visual Basic, como Integer, Currency, etc, siempre tengamos la precaucin de pasar los argumentos por valor. El motor de script har la transformacin automtica del tipo variant de la pgina ASP al tipo determinado en el argumento del mtodo del componente. Si activamos el control de errores en la pgina ASP con On Error Resume Next antes de invocar al mtodo, podremos capturar un posible error en la conversin en el caso de haber pasado un valor incorrecto (por ejemplo una cadena como argumento de un mtodo que espera un Integer).
185
Grupo EIDOS
Figura 49
Public Function leeVariable(ByVal nombre As Variant) As Variant Dim objContext As ObjectContext Set objContext = GetObjectContext Set objApplication = objContext("Application") leeVariable = objApplication.Contents(nombre) End Function Cdigo fuente 146
Para poder probar este componente, lo haremos desde una pgina en la que demos valor a una variable de aplicacin, cuyo nombre pasaremos luego como parmetro al mtodo. El Cdigo fuente 147 podra ser el de la pgina.
Set objCom = Server.CreateObject("CompApplication.Application") Application("variable1")="aqu ira el valor de la variable" Response.Write objCom.leeVariable("variable1") Cdigo fuente 147
Si ejecutamos esta pgina, veremos que se muestra correctamente el valor de esa variable de mbito de aplicacin. Sin embargo, probemos a aadir un proyecto EXE estndar que haga uso de este componente, con un formulario que presente un botn y un campo de texto Text1, y escribamos como cdigo asociado al evento Click del botn el contenido en el Cdigo fuente 148. Agregemos a este nuevo proyecto las
186
Grupo EIDOS
referencias al componente CompApplication y a COM+ Services Type Library, y luego con el botn derecho sobre el nombre del proyecto en el explorador de proyectos seleccionemos la opcin Establecer como inicial.
Private Sub Command1_Click() Dim objCom As CompApplication.Application Dim valor As Variant Set objCom = New CompApplication.Application valor = objCom.leeVariable("variable1") Text1.Text = valor End Sub Cdigo fuente 148
Si ejecutamos este proyecto veremos que da error en la lnea Set objApplication = objContext("Application") del componente. Esto se debe a que ahora el componente no se est ejecutando en el contexto de una aplicacin ASP, sino en el contexto de una aplicacin tradicional de Visual Basic, luego no puede acceder a travs de su contexto al objeto Application, que slo tiene sentido en una aplicacin ASP.
Figura 50
187
Grupo EIDOS
Si llamamos CompFormulario al proyecto ActiveX DLL, y Formulario al mdulo de clase, el Cdigo fuente 149 muestra las lneas que debera contener el mtodo.
Public Sub procesaForm() Dim objContext As ObjectContext Dim objRequest As Request Dim objResponse As Response Dim strHTML As String Set objContext = GetObjectContext Set 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>" Next strHTML = strHTML & "</table>" objResponse.Write strHTML End Sub Cdigo fuente 149
El cdigo accede al objeto Request de ASP para ir leyendo, mediante un bucle foreach, a todos los elementos de la coleccin Form, y va construyendo una cadena strHTML con sus valores. En la ltima lnea, utiliza el mtodo Write del objeto Response para escribir esta cadena en la respuesta que ser enviada de vuelta al navegador del cliente. Una pgina ASP para probar este componente podra ser la del Cdigo 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.procesaForm Set objCom = Nothing %> <%end if%> </BODY> </HTML> Cdigo fuente 150
188
Grupo EIDOS
Vemos que en la rama else, cuando el formulario es submitido, slo es necesario instanciar el componente e invocar a su nico mtodo. El resultado que obtendremos ser algo parecido al de la Tabla 7. Campo Valor
Retomemos ahora el componente que ya hemos utilizado en temas anteriores, que acceda a la tabla Stores de la base de datos Pubs, creada durante la instalacin del SQL Server. Este componente tena un nico mtodo listaStores, que devolva un objeto recordset, para ser formateado en la pgina ASP. Lo modificaremos ligeramente, de forma que ahora tenga un mtodo llamado recuperaTabla, que reciba como parmetro 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 mtodo 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 podra tener algo parecido al Cdigo fuente 151.
Option Explicit Public Function recuperaTabla(ByVal nombreTabla As Variant) As Variant() Dim objCnx As ADODB.Connection Dim objCmd As ADODB.Command Dim objRst As ADODB.Recordset Dim strCnx As String strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;Data Source=varrondo" Set objCnx = New ADODB.Connection objCnx.Open strCnx Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.CommandText = "SELECT * FROM " & nombreTabla Set objRst = New ADODB.Recordset objRst.Open objCmd, , , , adCmdText recuperaTabla = objRst.GetRows End Function Cdigo fuente 151
189
Grupo EIDOS
Como este componente accede a la base de datos a travs de ADO, y queremos hacer uso del early binding, tenemos que aadir al proyecto la referencia a Microsoft ActiveX Data Objects 2.5 Library. Formamos la cadena SQL dinmicamente, con el parmetro del nombre de la tabla, y devolvemos como resultado del mtodo la ejecucin de GetRows sobre el recordset. Compilemos este componente y pasemos al siguiente. El componente CompStores2 quedara con el Cdigo fuente 152.
Option Explicit Public Sub generaTabla(ByVal nombreTabla As Variant) Dim objContext As ObjectContext Dim objResponse As Response Dim objCom As CompStores1.Stores1 Dim rec() Dim strHTML As String Dim i, j As Integer Set objContext = GetObjectContext Set 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>" Next strHTML = strHTML & "</tr>" Next strHTML = strHTML & "</table>" objResponse.Write strHTML End Sub Cdigo fuente 152
Dentro del mtodo 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 mtodo recuperaTabla, pasando el parmetro del nombre. Con el array bidimensional devuelto vamos construyendo una cadena strHTML con el cdigo necesario para formatear una tabla HTML. En la ltima lnea, escribimos esta cadena a travs del mtodo Write del objeto Response. Este componente no est orientado a los datos, es decir, no accede a la base de datos, luego no necesito aadir al proyecto la referencia a ADO. Si embargo, est orientado al cliente, porque tiene parte de la lgica de presentacin, puesto que accede al objeto Response del modelo de ASP. Para eso necesito aadir las referencias a las libreras de COM+ y ASP. Adems, este componente va a hacer uso del otro componente que acabamos de crear, CompStores1. Tendremos que aadir al proyecto esta referencia, como se muestra en la Figura 51.
190
Grupo EIDOS
Figura 51
El Cdigo fuente 153 es todo lo que necesita la pgina ASP para usar los componentes. Se reduce a instanciar el componente CompStores2, e invocar su mtodo generaTabla, pasando como parmetro 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 Cdigo fuente 153
De esta manera hemos creado lo que podramos considerar una aplicacin en cuatro capas: La capa de presentacin est en la mquina del cliente, donde se ejecuta el software del navegador web, capaz de hacer la peticin de la pgina ASP y recibir la respuesta, todo a travs del protocolo HTTP. El cdigo HTML que recibe puede interpretarlo, y mostrar en este caso una tabla. Parte de la capa de presentacin se encuentra en la pgina ASP, que es la que realmente genera dinmicamente ese cdigo HTML, que luego se encargar de visualizar en el formato adecuado el navegador. La capa intermedia orientada al cliente estara formada por el componente CompStores2, que se encarga de hacer la peticin al componente CompStores1 de la tabla, pero que adems accede directamente al objeto Response para escribir el cdigo HTML de la tabla. Este componente se ejecuta en la misma mquina que el servidor web, y es gestionado por la pgina ASP, cuyo cdigo se encarga de crearlo y destruirlo cuando es oportuno. La capa intermedia orientada a los datos la implementa el componente CompStores1, que recibe la peticin de tabla que le hace el componente CompStores2, y que accede al gestor de
191
Grupo EIDOS
base de datos a travs de los objetos de ADO. Si este componente se ejecutara en una mquina distinta de la del servidor web, podramos denominarla servidor de aplicacin. La capa de datos est formada por el gestor de base de datos, y podra ejecutarse en una mquina diferente de la del servidor web y de la del servidor de aplicacin.
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, slo tendra 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 parmetro un nombre de tabla y devolviendo un array bidimensional), todo funcionar igual que antes. Adems, al no depender el componente orientado a datos del modelo de objetos de ASP, puedo utilizarlo en otras aplicaciones, por ejemplo desde un EXE estndar de Visual Basic.
Option Explicit Public Function recuperaTabla(ByVal nombreTabla As Variant) As Variant() Dim objCnx As ADODB.Connection Dim objRst As ADODB.Recordset Dim strCnx As String strCnx = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=pubs;Data Source=varrondo" Set objCnx = New ADODB.Connection objCnx.Open strCnx Set objRst = New ADODB.Recordset objRst.Open nombreTabla, objCnx, , , adCmdTable recuperaTabla = objRst.GetRows End Function Cdigo fuente 154
Ahora no usamos el objeto Command, sino que pasamos como parmetro al mtodo Open del Recordset el nombre de la tabla. La ejecucin de la pgina ASP ser igual que antes. No tenemos que modificar el cdigo 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 instruccin Set objCom = New CompStores1.Stores1, al haber recompilado el CompStores1 tenemos que recompilar el CompStores2. De no hacerlo, al ejecutar la pgina ASP obtendramos el error Esta clase no admite Automatizacin o la interfaz esperada. Esta recompilacin no sera necesaria si utilizramos enlace tardo (late binding), es decir, si hubiramos usado Set objCom = CreateObject(CompStores1.Stores1).
192
Grupo EIDOS
Figura 52
Con ayuda de la utilidad Generador de clases, aadimos un mtodo al mdulo de clase, como se muestra en el Cdigo fuente 155.
Public Function metodo1(ByVal par As Integer) As Integer End Function Cdigo fuente 155
Vamos a utilizar esta clase abstracta en otro mdulo de clase. Para ello aadimos un nuevo mdulo de clase al proyecto, llamado Implementa, y en su seccin de Declaraciones aadimos la lnea Implements IInterfaz1. Esto significa que esta clase acepta el contrato, con lo cual est obligada a implementar todos y cada uno de los mtodos que formaran parte del interfaz. En este caso el metodo1. Si no lo implementara, obtendramos un error de compilacin. Nada ms aadir esta lnea, aparecer en el combo de Objetos, en la esquina superior izquierda del panel de edicin, el nombre del interfaz. Si lo seleccionamos de la lista, automticamente aparecer la estructura del mtodo metodo1, al que se le antepone el nombre del interfaz y un guin bajo _, listo
193
Grupo EIDOS
para que lo implementemos con las lneas de cdigo que creamos oportunas. Dejmoslo con el Cdigo fuente 156.
Implements IInterfaz1 Public Function metodo3(ByVal par As Integer) As Integer metodo3 = par + 3 End Function Private Function IInterfaz1_metodo1(ByVal par As Integer) As Integer IInterfaz1_metodo1 = par + 1 End Function Cdigo fuente 156
Como puede verse, hemos aadido adems un mtodo llamado metodo3, pero que no es fruto de implementar el interfaz anterior, sino un mtodo como los que hemos escrito hasta ahora. Vamos a repetir el proceso llevado a cabo con el mdulo de clase IInterfaz1, para crear otro mdulo de clase IInterfaz2, con un mtodo llamado metodo2. Haremos que la clase Implementa firme el contrato tambin con este interfaz, lo que le obliga a implementar tambin el metodo2. El resultado final se muestra en el Cdigo fuente 157.
Implements IInterfaz1 Implements IInterfaz2 Public Function metodo3(ByVal par As Integer) As Integer metodo3 = par + 3 End Function Private Function IInterfaz1_metodo1(ByVal par As Integer) As Integer IInterfaz1_metodo1 = par + 1 End Function Private Function IInterfaz2_metodo2(ByVal par As Integer) As Integer IInterfaz2_metodo2 = par + 2 End Function Cdigo fuente 157
Si ahora compilamos el proyecto, y desde una pgina ASP instanciamos este objeto, veremos que slo 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 carcter de subrayado bajo. Por ejemplo, el interfaz por defecto para la clase Implementa es _Implementa. Los mtodos que no forman parte de otro interfaz (precedido por la lnea 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 especificrselo. Pues bien, al ser el VBScript de una pgina ASP un lenguaje en que no es posible asignar tipo a las variables, slo nos est permitido acceder a este interfaz por defecto, es decir, slo podemos acceder al metodo3. A continuacin veremos que para acceder a los otros interfaces, distintos del interfaz por defecto, es necesario declarar variables con el tipo especfico de esos interfaces.
194
Grupo EIDOS
Vamos a probar este componente desde Visual Basic. Para ello, desde el men Archivo, seleccionemos la opcin Agregar proyecto, que elegiremos del tipo EXE estndar. El grupo de proyectos quedar al final como se muestra en la Figura 53.
Figura 53
Al formulario que se crea automticamente, aadimos un botn y hacemos doble clic sobre l para implementar el cdigo asociado a su evento Click, como se ve en el Cdigo fuente 158.
Set objCom = New Implementa var = objCom.metodo3(1) Set i1 = objCom var = i1.metodo1(1) Set i2 = objCom var = i2.metodo2(1) End Sub Cdigo 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 mtodo 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 mtodo que utiliza para ello se llama QueryInterface y pertenece a la interfaz IUnknown. Vamos a establecer el proyecto EXE estndar recin creado como proyecto de inicio. Para ello pulsamos con el botn derecho sobre l en el Explorador de proyectos y seleccionamos la opcin Establecer como inicial.
195
Grupo EIDOS
Si depuramos el componente, veremos que podemos invocar todos los mtodos correctamente, y la variable var toma los valores adecuados despus de la ejecucin de cada mtodo. En definitiva, desde el proyecto EXE estndar de Visual Basic conseguimos lo que no podamos hacer desde el script de ASP: acceder tanto a los mtodos del interfaz por defecto como a los mtodos 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 eleccin a la hora de realizar la implementacin depende de la complejidad de la aplicacin y de los requisitos del diseo. Desde luego, desde un componente instanciado desde una pgina ASP s podra 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 mtodos y parmetros de un interfaz, y no tiene nada que ver con la implementacin 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 compilacin o de ejecucin. La definicin 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.
196
Servicios de Componentes
Introduccin
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 evolucin de Windows NT a Windows 2000, y poder establecer comparaciones tiles para aquellos que ya conocieran este producto. Adems, los conceptos del MTS son aplicables en su prctica totalidad a los Servicios de Componentes, exceptuando algunas diferencias que se comentarn adecuadamente.
Grupo EIDOS
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 aadida a la del COM, proporcionando un nuevo runtime para los objetos que se estn ejecutando en la capa intermedia de una aplicacin distribuida segn el modelo de n-capas. Esta funcionalidad aadida consiste sobre todo en soporte para transacciones distribuidas, seguridad integrada, pooling de hilos de ejecucin, y facilidades de configuracin y administracin de los componentes mediante el uso de propiedades declarativas. Para Windows 95/98 existe una versin reducida del MTS, del mismo modo que existe una versin reducida del servidor IIS denominada PWS (Personal Web Server). Como ya se ha comentado, el MTS no slo proporciona la funcionalidad necesaria para gestionar las transacciones distribuidas, sino que incluso componentes no-transaccionales pueden obtener ventajas en su ejecucin si hacen uso de los servicios que aporta. El MTS ana dos funcionalidades principales: Object request broker (ORB). Gestiona la instanciacin de objetos para los clientes. Sabe dnde estn los objetos y cmo crearlos. Gestiona la comunicacin entre los componentes, ahorrando al programador el trabajo de escribir el cdigo en C++ que hiciera lo mismo). En una pgina 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 simultneos, 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 cdigo para gestionar el rollback; todo est centralizado en el MTS.
198
Grupo EIDOS
Implementando la seguridad, de tal manera que los usuarios slo tengan acceso a los recursos para los que el administrador les ha dado permisos. Implementando la administracin y configuracin, esto reduce el coste de distribucin, administracin y/o modificacin.
Comercio de objetos
MTS acta como un comerciante de objetos, sirviendo las peticiones de instanciacin que varios clientes hacen. MTS reconoce la peticin, coordina su creacin y mantenimiento, y destruye las instancias de componentes COM y de los hilos que stas hayan creado. La independencia de la ubicacin de los componentes respecto de los clientes es otra de las ventajas que aporta este servicio que, adems, soporta la reconfiguracin dinmica y el cambio de la ubicacin de un objeto sin tener que cambiar el cdigo de la aplicacin cliente, despus de la fase de desarrollo.
Grupo EIDOS
punto de vista del cliente, slo existe una copia del objeto desde que lo mand crear hasta que lo destruy. Realmente, el objeto puede desactivarse y reactivarse varias veces. La administracin de instancias de objetos y la activacin 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 ejecucin, quin quiere utilizar el componente. Un componente puede alterar su comportamiento dependiendo de la respuesta.
200
Grupo EIDOS
modificar el cdigo y recompilar. Ahora este esfuerzo no es necesario, y basta con modificar una serie de propiedades declarativas, sin necesidad de tocar una sola lnea de cdigo. La informacin de estas propiedades declarativas de cada componente registrado en algn paquete del MTS se guarda en el catlogo. Este catlogo almacena informacin adicional a la que se guarda en el registro de Windows.
El objeto de contexto
Almacena informacin asociada con el objeto (creador del objeto, informacin de seguridad, transaccin en curso, etc). Es usada por el entorno para saber cmo el componente interacta. Todos los componentes registrados en MTS lo tienen. Suele decirse que el objeto de contexto es como la sombra del objeto. Almacena informacin de seguridad, que le permite al Context Wrapper saber si el cliente tiene permiso para usar los mtodos que ha pedido. Almacena informacin del contexto de ejecucin del componente. Esta informacin es la que le permite al MTS meter un componente, programado de forma aislada y como si fuera monousuario, dentro de una transaccin distribuida con gestin de concurrencia, sin que yo tenga que programar
201
Grupo EIDOS
nada especial. Gracias a este objeto es posible monitorizar las transacciones y ver estadsticas desde la consola administrativa del MTS. IIS almacena informacin en el objeto de contexto, ya que IIS es parte del entorno y est construido con tecnologa MTS. Entre esta informacin almacenada estn 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 transaccin, ya sea temporal o permanentemente. Instanciar otros objetos de MTS e incluir su trabajo en el mbito de la transaccin del objeto creador. Averiguar la funcin del usuario que utiliza el objeto. Averiguar si dispone de los permisos necesarios. Averiguar si el objeto se est ejecutando en una transaccin. 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 lneas mostradas en el Cdigo fuente 159.
Los principales mtodos 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 transaccin terminen su trabajo. El mtodo SetComplete tambin 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 transaccin quedarn anulados. El mtodo SetComplete tambin indica al MTS que cualquier recurso retenido por el objeto, incluido el propio objeto, puede ser reciclado. CreateInstance: crea un nuevo objeto, pero adems MTS copia la informacin del objeto de contexto del objeto creador al objeto de contexto del objeto creado. As formar parte de la misma transaccin y tendr las mismas caractersticas de seguridad. Para que forme parte de la misma transaccin, el nuevo objeto debe tener su atributo transaccional configurado como Requiere una transaccin o Compatible con transacciones.
202
Grupo EIDOS
EnableCommit: Declara que el trabajo de un objeto no est necesariamente terminado, pero que sus actualizaciones de la transaccin son consistentes y que podran confirmarse en su forma actual. El objeto mantiene su estado interno durante las llamadas realizadas a otros mtodos hasta que le llame a SetComplete o SetAbort, o hasta que la transaccin termina. EnableCommit es la establecida por defecto para un objeto, si ste no llama a otros mtodos del objeto de contexto. Por ejemplo, una compaa tiene un objeto Pedido que crea pedidos que hay que suministrar a los clientes. Un cliente puede crear un pedido a travs de internet y solicitar que le sea enviado a una direccin determinada. O el cliente puede ir a buscar el pedido directamente a uno de los almacenes de la compaa. Un fichero ASP crea el pedido llamando al mtodo AadirPedido del objeto Pedido. ste llama a EnableCommit ya que no sabe dnde ir el cliente a buscarlo. Una vez el cliente elija, la pgina ASP podr llamar a los mtodos DejarEnAlmacn o EnviarADireccin, para indicar qu debe hacerse con el pedido. Cada uno de estos dos ltimo mtodos llamarn a SetComplete. DisableCommit: Declara que el trabajo de un objeto no est terminado, que sus actualizaciones de la transaccin 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 mtodos: Activate: es invocado automticamente por el MTS Excecutive cuando el cliente invoca un mtodo del componente. Aqu pondra el cdigo de inicializacin que sea global para todos los mtodos del componente. Por ejemplo, si todos los mtodos acceden a una BD, aqu creara la conexin. Deactivate: es invocado automticamente por el MTS Executive cuando finaliza la ejecucin del mtodo, dando como resultado un SetComplete o un SetAbort. Aqu pondra el cdigo de finalizacin que sea global para todos los mtodos del componente. En el ejemplo utilizado, ste sera el lugar en el que liberar la conexin. 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 mtodos Activate y Deactivate es donde se debe poner el cdigo de inicializacin y de finalizacin 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 mtodos Class_Initialize y Class_Terminate, con lo que hara la inicializacin y destruccin 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 inicializacin y finalizacin debe hacerse en Activate y Deactivate, que son los mtodos invocados precisamente entre estas llamadas. Desde los mtodos Class_Initialize y Class_Terminate no est disponible el objeto de contexto, con lo que no podremos acceder desde ellos, por ejemplo, a las caractersticas de seguridad del componente.
203
Grupo EIDOS
Usando el mtodo CreateObject: Equivale a New cuando se instancia desde servidores COM distintos; sin embargo, New es ms 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 informacin 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 transaccin.
Usando el mtodo CreateInstance: Al crear el nuevo objeto, el MTS copia toda la informacin del objeto de contexto del objeto creador al objeto de contexto del objeto creado, con lo cual podr compartir la transaccin y las caractersticas de seguridad.
Usando el mtodo Server.CreateObject: Este mtodo del objeto integrado Server transmite la peticin de instanciacin del objeto al IIS, que se encargar de utilizar el MTS en caso necesario. Si la pgina es transaccional, este componente correr en la misma transaccin. En definitiva, este mtodo emplea internamente el mtodo CreateInstance del interfaz ObjectContext.
204
Grupo EIDOS
205
Grupo EIDOS
Cuando una transaccin termina, MTS debe determinar su resultado y decidir si debe autorizar o abortar la transaccin. Determinar el resultado de la transaccin es un proceso anlogo a la toma de decisin de un grupo en el que se ha de llegar a una decisin unnime. Si un miembro del grupo disiente, habr que negociar una decisin unnime. Del mismo modo, cada objeto en una transaccin emite su voto llamando a un mtodo, 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 transaccin, pero si alguno de ellos llam a SetAbort o a DisableCommit, se abortar la transaccin.
Activacin en el momento
Una de las consideraciones del diseo ms 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 despus de haber realizado ms 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 tambin 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 direccin y nmero de telfono. Tambin puede tener mtodos que utilizan los valores de dichas propiedades. Un mtodo aade la informacin del cliente a la base de datos y,
206
Grupo EIDOS
ms tarde, otro mtodo hace un ingreso en su cuenta. El objeto existe y guarda la informacin del cliente hasta que es liberado. Un objeto como ste, que mantiene el estado internamente despus de mltiples llamadas, recibe el nombre de stateful. Sin embargo, si el objeto no expone propiedades y, el nombre del cliente, su direccin y su nmero de telfono se pasan en cada llamada al mtodo, 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 mtodos son sencillas porque el objeto recuerda la informacin de una llamada a otra. Sin embargo, los objetos que mantienen el estado ("stateful") influyen en la escalabilidad de una aplicacin. 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 especfico, se mantendrn los recursos hasta que el cliente libere al objeto. Esta decisin ha de tenerse en cuenta junto con otros requisitos de la aplicacin. 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 nmero limitado de conexiones a la base de datos que pueden asignarse y las conexiones que se han utilizado no pueden reunirse en el fondo comn. La Activacin 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 activacin tambin asegura el aislamiento de las transacciones, de forma que la informacin de una transaccin no se llevar a la siguiente. Cuando un cliente llama a un mtodo de un objeto, MTS activa el objeto, crendolo y permitiendo a la llamada del mtodo 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 mtodo. Al desactivar el objeto, MTS libera todas sus referencias, destruyendo tambin todo su estado local, es decir, las variables locales y las propiedades. Sin embargo, MTS controla el puntero del cliente para que siga siendo vlido. Cuando el cliente llama a un mtodo del objeto desactivado, MTS lo activa crendolo de nuevo y permitiendo a la llamada del mtodo 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 activacin anterior. Un objeto no est desactivado cuando llama a EnableCommit o al DisableCommit o cuando rechaza hacer una llamada a cualquier otro mtodo del objeto contextual. Tampoco estar desactivado cuando termine la transaccin por haberse agotado su tiempo. El objeto slo se desactiva cuando llama a SetComplete o a SetAbort y regresa de la llamada del cliente. La activacin 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 mtodo regresa, los objetos que participan en las transacciones han de ser stateless. Es decir, no pueden mantener ningn tipo de dato de la instancia desde que quedan desactivados. No obstante, esto no quiere decir que todas las aplicaciones deben disearse hacia un modelo de programa que no mantenga el estado, ya que ste puede almacenarse y mantenerse fuera del objeto.
207
Grupo EIDOS
208
Grupo EIDOS
paquete dejaramos activado el botn 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 tambin con nombre (objeto SharedPropertyGroup). Todo es gestionado por el administrador de SPM (objeto SharedPropertyGroupManager). En resumen, el SPM trabaja con tres objetos ordenados jerrquicamente: 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.
209
Grupo EIDOS
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 MTS, o los Servicios de Componentes en Windows 2000, se encargan de asegurar que slo exista una instancia por servidor de este objeto. Si ya exista esta instancia, se nos asignar una referencia a la ya existente.
210
Grupo EIDOS
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 simultneo a las propiedades comunes. En la Tabla 8 se muestra los dos tipos de valores que existen para hacer el bloqueo. Constante LockSetGet Valor Descripcin 0 Establecido por defecto. Bloquea una propiedad durante una llamada; de esta forma se asegura que, cada operacin de lectura/escritura comn sea atmica. Con esto se consigue que dos clientes no puedan leer o escribir la misma propiedad simultneamente, pero no impide que otros clientes de accesos concurrentes lo hagan con otras propiedades en el mismo grupo. Bloquea todas las propiedades del grupo para uso exclusivo del llamador; este bloqueo se mantendr mientras est ejecutndose el mtodo 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 despus de haberla ledo y antes de que se acceda a ella otra vez.
Tabla 8
1 LockMethod
Tiempo de vida: controla la forma en que se borra el grupo de propiedad comn. En la Tabla 9 se muestran los dos valores posibles para este caso. Constante Standard 1 Process Valor Descripcin 0 Cuando todos los objetos MTS han liberado sus referencias del grupo de propiedad, ste se destruye automticamente. 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 envindolos a Nothing.
Tabla 9
El cuarto parmetro devuelve un booleano que indica si el grupo de propiedades exista o no previamente. Si ya exista, se devolver una referencia al grupo existente, y entonces el segundo y tercer parmetro no tienen validez, pues el grupo tendr los valores que le fueron dados en el momento de su creacin. Puede usarse el valor devuelto por este parmetro para verificar si se est creando el grupo o recibiendo la referencia a uno existente, ejecutando el cdigo de inicializacin de las variables del grupo slo en el primer caso.
211
Grupo EIDOS
El Cdigo fuente 162 permite crear una propiedad comn llamada id. El segundo argumento del mtodo devuelve un valor booleano que indica si la propiedad es creada en ese mismo momento o ya exista. En el primer caso, haramos la inicializacin del bloque if.
Set objP = objPG.CreateProperty("id", bExiste) If bExiste = False Then objP.Value = 100 Cdigo fuente 162
Si todo este cdigo lo incluimos en un mtodo que devuelva la propiedad compartida id y la incremente en 1, el resultado final sera el del Cdigo fuente 163.
Option Explicit Public Function generaId() As Integer Dim objSPM As SharedPropertyGroupManager Dim objPG As SharedPropertyGroup Dim objP As SharedProperty Dim bExiste As Boolean Set objSPM = New SharedPropertyGroupManager Set objPG = objSPM.CreatePropertyGroup("contadores", LockSetGet, Process, bExiste) Set objP = objPG.CreateProperty("id", bExiste) If bExiste = False Then objP.Value = 100 objP.Value = objP.Value + 1 generaId = objP.Value End Function Cdigo fuente 163
Podemos probar este componente con una pgina ASP tan simple como la que se muestra en el Cdigo fuente 164. Si pedimos esta pgina, incluso desde varias instancias distintas de navegador, podremos ver cmo el contador se va incrementando.
212
Grupo EIDOS
Si queremos probar ms a fondo el comportamiento del SPM, hagamos un nuevo proyecto ActiveX DLL llamado CompContador2, con un mdulo de clase Contador2. Este mdulo de clase contendr un mtodo exactamente igual al del componente anterior. Hagamos otra pgina ASP similar a la del Cdigo 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 aplicacin web. Luego como comparten proceso, tambin 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 Aplicacin de servidor, este componente se ejecutar en un espacio de proceso distinto al de la aplicacin 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 sera que estos dos componentes tuvieran funcionalidad diferente, por ejemplo uno podra ejecutar operaciones de transferencias bancarias y otro de ingreso de cheques, pero que quisiramos numerar esas operaciones distintas con un contador nico. En ese caso, registraramos estos componentes en un mismo paquete, y dispondra cada uno de ellos de un mtodo generaId que accediera a la propiedad comn id, como hemos visto. Esta propiedad comn se conserva, incluso aunque el MTS est haciendo activacin justo a tiempo de los objetos.
Grupo EIDOS
Pero COM+ tambin est basado en MTS. Esto significa que extiende la funcionalidad bsica del COM, igual que haca el MTS, pero aade an ms funcionalidad que ste. Ahora esta funcionalidad aadida 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 transaccin, sin tocar una sola lnea de cdigo, 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 informacin de su contexto. Cada objeto est asociado con un nico contexto durante su vida, como si se tratara de su sombra. Mltiples objetos pueden estar asociados a un mismo contexto. Gestor de seguridad: Algunas caractersticas de seguridad no necesitan que sea aadida ni una sola lnea de cdigo y son configuradas administrativamente.
Pero adems, los Servicios de Componentes aportan algunas novedades: Componentes encolados: Combina COM con MSMQ. Permite invocar y ejecutar componentes de forma asncrona, estando el cliente o el servidor desconectados El cliente pide un mtodo de un componente encolado al Queued Components Recorder, que mete la peticin en una cola. El Queued Components Listener coge el mensaje y se lo pasa al Queued Components Player, para que sea ejecutado finalmente el mtodo sobre el componente. Fondo comn de objetos (Object Pooling): Mantiene instancias de componentes en un fondo comn o pool, que pueden ser usadas por cualquier cliente. Igual que el pool de conexiones a una BD. Actualmente slo puede usarse con componentes C++. Component Load Balancing (CLB): Puedo tener un mismo componente COM+ servido por varios servidores de aplicacin. Se utilizar uno u otro servidor en funcin de su carga de trabajo. No disponible todava en Windows 2000.
Muchos de los conceptos de MTS siguen teniendo aplicacin al hablar de los Servicios de Componentes. A veces slo cambia el nombre. Por ejemplo, el MTS ahora se llama Servicios de Componentes. Es accesible desde la opcin Herramientas administrativas del men Programas. Lo que antes se llamaba paquete ahora recibe el nombre de aplicacin COM+. Al igual que los paquetes del MTS, las aplicaciones COM+ pueden ser configuradas como: Aplicacin de biblioteca: Los objetos instanciados a partir de componentes registrados en esa aplicacin se ejecutarn en el mismo espacio de proceso que el cliente que instaci dicho objeto. Aplicacin de servidor: Los objetos instanciados a partir de componentes registrados en esa aplicacin se ejecutarn en un proceso de servidor dedicado. Este proceso que contiene la ejecucin de esta aplicacin era MTX.EXE en el MTS, y ahora pasa a ser DLLHOST.EXE, como puede verse en la Figura 56.
214
Grupo EIDOS
Figura 56
La intercepcin en COM+
Ya hemos visto que para que el MTS fuera capaz de aadir 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 ejecucin de ste. Para conseguir esto, la capa runtime del MTS, el MTXEX.DLL, se vala de dos objetos. El objeto Context Wrapper es el que se interpone en el momento del intento de instanciacin de un componente MTS por parte de un cliente: ste recibe una referencia a este objeto Context Wrapper, siendo as engaado, mientras que el MTS se encarga de gestionar la creacin del objeto real. Un segundo objeto, el objeto de contexto, se encarga de guardar informacin relativa al contexto de ejecucin del objeto, actuando como su sombra. El hecho de que el MTS no estuviera plenamente integrado en el modelo COM supona un problema importante, una de cuyas consecuencias principales era la necesidad del uso del mtodo CreateInstance del objeto de contexto. Si un componente MTS instanciaba otro componente MTS, y se empleaba el mtodo de Visual Basic CreateObject en vez de CreateInstance, ocurra lo siguiente: el runtime de Visual Basic pasaba la peticin de creacin 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 informacin 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 poda correr en la misma transaccin.
215
Grupo EIDOS
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 intercepcin de la capa runtime del COM+ slo se produce cuando la llamada se hace desde un contexto hasta otro distinto. Para esta intercepcin 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 decisin, COM+ se basa en la informacin almacenada en el objeto de contexto. En la mayora 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 aqul que est registrado dentro de una aplicacin 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 mtodo CreateInstance, aunque sigue pudiendo utilizarse para garantizar la compatibilidad con cdigo ya escrito. Las rutinas de COM+ saben perfectamente cmo deben pasar informacin del contexto en el momento de la creacin de objetos. Esto significa que el mtodo CreateObject, que utiliza dichas rutinas COM+, tendr el mismo efecto, y el objeto recin creado podr, por ejemplo, ejecutarse en la misma transaccin que el creador. El operador New de Visual Basic todava puede ser problemtico si los componentes correspondientes al objeto creado y al creador estn incluidos en la misma DLL. En este caso las rutinas de Visual Basic saben cmo crear el nuevo objeto y no utilizan las rutinas de COM+. Si estn en DLLs distintas, el operador New equivale al mtodo 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 mtodo de un tercer objeto 3 dentro de un contexto 3, y le pasa como parmetro del mtodo esta referencia al objeto 2, se crear automticamente 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 parmetro de un mtodo no supone ningn problema, porque los proxys necesarios se crean automticamente. Sin embargo, no sera correcto guardar la referencia que tena el objeto 1 al objeto 2, que es un proxy especializado en cambiar del contexto 1 al 2, como una variable dentro de un mdulo BAS de Visual Basic, ni como una propiedad compartida del SPM, porque esa referencia slo sera utilizable por el objeto 1, pero no por el objeto 3, que necesitara 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 intercepcin en el momento de la creacin del componente, ya que las rutinas COM no eran capaces de hacerlo por s mismas. El problema vena en el momento de recompilar el componente desde el Visual Basic: despus de la compilacin, ste llama automticamente a REGSVR32.EXE, y el componente volva a ser registrado segn la manera de COM, y el valor de la clave InProcServer32 volva a ser el de la ruta de la DLL, con lo que el componente ya no funcionaba correctamente porque el MTS no poda hacer la intercepcin.
216
Grupo EIDOS
Para mitigar este problema, el MTS contaba con la posibilidad de Actualizar los componentes de un paquete, que consista en que el MTS inspeccionaba en el registro de Windows las claves de los componentes de dicho paquete, y correga automticamente 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 informacin adicional en el registro. No es necesario refrescar los componentes despus de cada recompilacin en Visual Basic.
217
El interfaz ObjectControl
Hemos dicho que cuando un componente es registrado en el catlogo de COM+, los Servicios de Componentes se encargan de gestionar su creacin y destruccin. Si queremos conocer cundo es creado y destruido realmente el componente, podemos hacerlo implementado dentro del mismo el interfaz ObjectControl. Este interfaz tiene tres mtodos: 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 mtodo ser invocado automticamente por las rutinas de COM+ antes que cualquier otro mtodo. Sera lgico usar este mtodo para incluir cdigo de inicializacin que sea global para todos los mtodos del
Grupo EIDOS
objeto. Si se trata por ejemplo de un objeto que accede a una base de datos a travs de ADO, en este mtodo podramos crear la conexin. Tambin es normal obtener aqu la referencia al objeto del contexto, para poder usarla luego en los mtodos del componente. Deactivate: es invocado cuando el componente es desactivado. Igual que con el mtodo anterior, aqu pondra cdigo de finalizacin del objeto, como cierre de una conexin a travs de ADO. CanBePooled: este mtodo devuelve un valor booleano que indica si las rutinas COM+ pueden meter este objeto en un pool, una vez desactivado. Actualmente esta opcin slo estara disponible para componentes escritos en C++. Para componentes escritos en Visual Basic este mtodo 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 mdulo 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 adems tendr un mtodo adicional. Aadimos al proyecto las referencias a las libreras de COM+ y del modelo de objetos de ASP. El Cdigo fuente 165 muestra cmo quedaran estos mtodos.
Option Explicit Implements ObjectControl Private Sub ObjectControl_Activate() Dim objContext As ObjectContext Dim objResponse As Response Set objContext = GetObjectContext Set objResponse = objContext("Response") objResponse.Write "activado a las " & Time & "<br>" End Sub Private Sub ObjectControl_Deactivate() Dim objContext As ObjectContext Dim objResponse As Response Set objContext = GetObjectContext Set objResponse = objContext("Response") objResponse.Write "desactivado a las " & Time & "<br>" End Sub Private Function ObjectControl_CanBePooled() As Boolean ObjectControl_CanBePooled = False End Function Public Sub escribe() Dim objContext As ObjectContext Dim objResponse As Response Set objContext = GetObjectContext Set objResponse = objContext("Response") objResponse.Write "dentro del mtodo a las " & Time & "<br>" End Sub Cdigo fuente 165
220
Grupo EIDOS
El hecho de aadir la lnea Implements ObjectControl nos obliga a implementar los tres mtodos del interfaz; si no lo hacemos as, no podremos compilar. Esta lnea es necesaria para que los Servicios de Componentes puedan invocar automticamente a los mtodos del interfaz. En los mtodos ObjectControl_Activate, ObjectControl_Deactivate, y en el mtodo escribe, obtenemos una referencia al objeto de contexto, y a travs de l una referencia al objeto Response, para poder escribir directamente un corto mensaje y la hora del sistema. Ahora escribimos una pgina ASP con el Cdigo 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 = Time Response.Write inicio & "<br>" while Time<>DateAdd("s",5,inicio) wend Response.Write Time & "<br>" objCom.escribe & "<br>" %> </BODY> </HTML> Cdigo fuente 166
Deshabilitamos el buffer en la segunda lnea, para poder ir recibiendo gradualmente en el navegador el resultado de la ejecucin de la pgina. Instanciamos el componente, obtenemos la hora del sistema y la escribimos con Write. El bucle WhileWend consiste en un temporizador muy rudimentario, que ralentizar la ejecucin de la pgina durante cinco segundos. Obtenemos nuevamente la hora del sistema, la escribimos, e invocamos al mtodo escribe del componente. Si ejecutamos la pgina, obtendremos: 9:38:04 9:38:09 dentro del mtodo a las 9:38:09 Es decir, no han sido invocados los mtodos Activate ni Deactivate. Esto es as porque todava el componente no est registrado en el catlogo de COM+, y los Servicios de Componentes no se han encargado de interceptar la creacin y destruccin del objeto. Vamos pues a registrarlo. Dentro de Programas | Herramientas administrativas, seleccionamos la opcin Servicios de Componentes. Esto abrir la consola de administracin 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+.
221
Grupo EIDOS
Figura 57
En el panel derecho veremos las aplicaciones COM+ actualmente instaladas en el equipo. Para crear una nueva, pulsamos con el botn derecho sobre la carpeta Aplicaciones COM+ del panel izquierdo, y seleccionamos Nuevo | Aplicacin. En ese momento se inicia el asistente (ver Figura 58) para instalacin de aplicaciones COM+.
Figura 58
En la siguiente ventana (ver Figura 59) pulsaremos sobre el botn de Crear una aplicacin vaca. A esta aplicacin aadiremos luego nuestro componente recin creado.
222
Grupo EIDOS
Figura 59
En el siguiente paso (ver Figura 60) se nos pide el nombre de la nueva aplicacin, y adems se nos permite configurar en qu espacio de memoria queremos que se ejecuten los componentes de la aplicacin. Tenemos dos opciones, segn seleccionemos un tipo u otro de aplicacin: Aplicacin de biblioteca: las instancias de los componentes de la aplicacin se ejecutan en el mismo espacio de memoria que el cliente que las crea. Esta opcin puede ser recomendable en tiempo de desarrollo de los componentes. Aplicacin de servidor: las instancias de los componentes se ejecutan en un proceso separado del de la aplicacin cliente que los utiliza. Esta opcin es la que debe utilizarse en tiempo de produccin.
Figura 60
En la siguiente ventana (Figura 61) podemos elegir bajo que cuenta se ejecutarn los componentes. Si seleccionamos la opcin marcada por defecto, entonces cuando instanciemos el componente desde una pgina ASP, y si est activado el acceso annimo para la aplicacin web a la que pertenece dicha pgina, la cuenta utilizada ser la de invitado a internet (IUSR_nombreMquina).
223
Grupo EIDOS
Figura 61
En la siguiente ventana basta con pulsar el botn de Finalizar, y ya est nuestra aplicacin creada. Ahora tenemos que aadir el componente. Para ello la expandimos en el rbol del panel izquierdo correspondiente a la aplicacin COM+ recin creada hasta llegar a la carpeta Componentes, como muestra la Figura 62.
Figura 62
224
Grupo EIDOS
La carpeta de Componentes no tiene ningn elemento, puesto que hemos creado una aplicacin vaca. Vamos a aadirlo pulsando con el botn derecho sobre la carpeta Componentes del panel izquierdo, y seleccionando Nuevo | Componente. Con esto arranca el asistente para la instalacin de componentes COM. En la pantalla que se muestra en la Figura 63, debemos pulsar la opcin Importar componentes ya registrados, puesto que al compilar el proyecto de Visual Basic, ya se ha encargado de registrarlo por nosotros en la mquina.
Figura 63
Despus de un momento, el que tarda en buscar en el registro de Windows los componentes registrados en la mquina, 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. Ms adelante veremos las propiedades declarativas que podemos configurar, pero de momento nos basta con las que tiene por defecto.
225
Grupo EIDOS
Figura 65
Antes de volver a ejecutar la pgina ASP, vamos a descargarla, para descargar con ello la dll del componente. Recordemos que esto podamos hacerlo desde la consola de administracin del IIS, pulsando con el botn derecho sobre el nombre de la aplicacin web y seleccionando la opcin Propiedades, y luego la pestaa Directorio. Si ahora pulsamos el botn Descargar, conseguiremos nuestro objetivo. Al ejecutar otra vez la pgina, el resultado que obtendremos ser: 10:50:50 10:50:55 activado a las 10:50:55 dentro del mtodo a las 10:50:55 desactivado a las 10:50:55 Como podemos ver, ahora los Servicios de Componentes han interceptado la creacin del componente. Con la instruccin Server.CreateObject("CompActivar.Activar"), no se produce la instanciacin inmediata del componente, sino que esta se produce al invocar el primer mtodo, es decir, en la instruccin Response.Write objCom.escribe. Por cierto, que si abrimos de nuevo la consola de administracin 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 aplicacin 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 aplicacin COM+ es que podemos controlar la descarga de las DLLs. Basta con
226
Grupo EIDOS
pulsar con el botn derecho sobre el icono de la aplicacin y seleccionar la opcin Cerrar sistema. La DLL se descarga, y la bolita ahora deja de girar. Si no cerramos nosotros la aplicacin explcitamente, se cierra ella sola segn la opcin elegida en la pestaa Activacin de las propiedades de la aplicacin COM+, como se muestra en la Figura 66. Por defecto aparece marcada la opcin Minutos de inactividad antes de cerrar, con un valor de tres. Esto significa que si transcurren ms de tres minutos sin que se reciba una peticin de algn mtodo del componente incluido en dicha dll, la aplicacin se descargar.
Figura 66
Tambin podemos forzar nosotros mismos el comienzo de la aplicacin si pulsamos con el botn derecho sobre el icono de la aplicacin y seleccionamos la opcin Iniciar. De esta forma la primera peticin de la pgina ASP, que hace uso del componente de esta aplicacin, no se ralentizar por el proceso de carga de la dll en memoria, sino que se encontrar con que sta ya estaba cargada.
227
Grupo EIDOS
Figura 67
Vayamos ahora a la pestaa Activacin para deseleccionar la casilla Habilitar activacin puntual, es decir, deshabilitamos la activacin Just-In-Time del componente. Esto se muestra en la Figura 68.
Figura 68
228
Grupo EIDOS
Y si ahora ejecutamos de nuevo la pgina ASP, el resultado obtenido ser: 12:02:13 12:02:18 dentro del mtodo a las 12:02:18 que es el mismo que se obtena cuando el objeto no estaba registrado en una aplicacin COM+. Hemos impedido que los Servicios de Componentes intercepten la creacin del objeto, luego no se invocan los mtodos Activate y Deactivate. Permitir que los Servicios de Componentes gestionen la activacin del componente supone una mejora en la escalabilidad de la aplicacin, pues los recursos del servidor son administrados de forma ms 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, activndolo en el momento preciso (activacin Just-InTime).
Option Explicit Implements ObjectControl Private mvarobjContext As ObjectContext Private mvarobjResponse As Response Private Sub ObjectControl_Activate() Set mvarobjContext = GetObjectContext Set 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 Boolean ObjectControl_CanBePooled = False End Function Public Sub listaApplication() Dim strHTML As String Dim objApplication As Application
229
Grupo EIDOS
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>" Next strHTML = strHTML & "</table>" mvarobjResponse.Write strHTML End Sub Public Sub listaSession() Dim strHTML As String Dim objSession As Session Dim 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>" Next strHTML = strHTML & "</table>" mvarobjResponse.Write strHTML End Sub Cdigo fuente 167
Como puede verse, en el mtodo 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 mtodos listaApplication y listaSession, nos interesa guardarlos como variables miembro. En estos dos mtodos tomamos la referencia al objeto de ASP correspondiente, Application o Session, generamos el cdigo HTML necesario para la tabla, recorriendo la coleccin con un bucle Foreach, y escribimos directamente sobre el objeto Response. Registremos el componente dentro de la aplicacin COM+, ASPComp, y probmoslo desde una pgina ASP con un cdigo similar al del Cdigo 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
230
Grupo EIDOS
Response.Write "<h3>Variables de Session</h3>" objCom.listaSession %> </BODY> </HTML> Cdigo fuente 168
VARIABLES DE APPLICATION
activado a las 13:14:47 Variable Valor var1 var2 var3 valor1 valor2 valor3
VARIABLES DE SESSION
Variable Valor var1 var2 valor1 valor2
desactivado a las 13:14:47 Podemos ver que el mtodo Activate ha sido invocado automticamente, y slo en el momento de llamar al primer mtodo, no en el CreateObject. Por eso el mensaje que genera este mtodo aparece entre el ttulo, escrito desde la pgina ASP, y la primera tabla, generada por el componente en el mtodo listaApplication. El mtodo Deactivate es invocado al finalizar la ejecucin de la pgina, y salir de mbito la variable de referencia objCom. Ms adelante veremos que un objeto puede ser desactivado y reactivado entre las llamadas a sus mtodos, en vez de activado en la primera llamada y desactivado despus de la ltima.
231
Grupo EIDOS
Estado de un componente
El paradigma de Programacin Orientada a Objetos nos dice que los objetos se caracterizan por su identidad, estado y comportamiento. Pues bien, veremos que si queremos disear componentes que aprovechen al mximo los Servicios de Componentes, debemos programar componentes sin estado. Vamos a disear un componente que permita hacer un alta en una tabla. Esta tabla la crearemos en SQL Server, aunque podra valer otro gestor de base de datos, incluso Access. Aadiremos adems un procedimiento almacenado para realizar el alta. La secuencia SQL necesaria para crear la tabla y el procedimiento se muestra en el Cdigo fuente 169.
CREATE TABLE Clientes( id smallint PRIMARY KEY, nombre varchar(25), saldo money )
CREATE PROCEDURE alta @id smallint, @nombre varchar(25), @saldo money AS INSERT INTO Clientes VALUES(@id,@nombre,@saldo) Cdigo fuente 169
Disearemos el interfaz del componente de forma que disponga de una propiedad cadenaConex, que contendr la cadena de conexin, y un mtodo alta, que ser el que acceda mediante ADO a la base de datos, empleando para ello el procedimiento almacenado recin creado. En el Cdigo fuente 170 est el cdigo necesario para este componente.
mvarcadenaConex As String objCnx As ADODB.Connection objCmd As ADODB.Command objRst As ADODB.Recordset objContext As ObjectContext
Public Sub alta(ByVal id As Integer, ByVal nombre As String, ByVal saldo As Currency) Dim objPar1, objPar2, objPar3 As ADODB.Parameter Set objContext = GetObjectContext Set objCnx = New ADODB.Connection objCnx.Open mvarcadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.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 objPar1 objCmd.Parameters.Append objPar2 objCmd.Parameters.Append objPar3 objCmd.Execute , , adCmdStoredProc
232
Grupo EIDOS
objContext.SetComplete objCnx.Close Set objCmd = Nothing Set objCnx = Nothing End Sub Public Property Let cadenaConex(ByVal vData As String) mvarcadenaConex = vData End Property Public Property Get cadenaConex() As String cadenaConex = mvarcadenaConex End Property Cdigo fuente 170
Comentemos algunas cosas de este cdigo. 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 mtodo Property Let, o para obtener su valor mediante Property Get. En realidad una propiedad equivale pues a dos mtodos, y modificar el valor de la propiedad o leerla supone invocar un mtodo. En el cdigo obtenemos tambin la referencia al objeto de contexto, y cuando el mtodo alta ha finalizado su ejecucin, invocamos el mtodo SetComplete. Esto puede parecer extrao, puesto que este mtodo suele asociarse siempre con transacciones sobre bases de datos, al igual que el mtodo SetAbort. Pero realmente este mtodo 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 mtodos. Vamos a crear ahora una pgina ASP con la que probar este componente. El Cdigo fuente 171 podra 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;Data Source=varrondo" Response.Write "La cadena de conexin es: " & objCom.cadenaConex & "<br>" objCom.alta 1,"pepe",1000 Response.Write "La cadena de conexin es: " & objCom.cadenaConex & "<br>" On Error Resume Next objCom.alta 2,"pepa",2000 if Err<>0 then Response.Write Err.description On Error Goto 0 Set objCom = Nothing %> </BODY> </HTML> Cdigo fuente 171
233
Grupo EIDOS
Si la ejecutamos, veremos que funciona correctamente como podramos esperar. Instanciamos el componente y le asignamos valor a la propiedad cadenaConex. Esto equivale a invocar un mtodo, el Property Let. Luego obtenemos su valor y lo escribimos. Esto es una llamada al mtodo Property Get. Luego invocamos al mtodo alta, y seguidamente volvemos a escribir la propiedad cadenaConex. Activamos el gestor de errores de VBScript e invocamos una segunda vez al mtodo alta, con un nuevo valor de clave primaria. Este componente parece correcto, desde el punto de vista de la Programacin Orientada a Objetos. Tiene una propiedad de estado, la cadena de conexin, que es utilizada en uno de sus mtodos, alta. Sin embargo, vamos a ver lo que ocurre cuando registramos el componente en la aplicacin COM+ que venimos utilizando. Previamente hemos de quitar la DLL de memoria, mediante la descarga de la aplicacin web a travs de la consola de administracin del IIS. Eliminemos tambin los registros de la tabla, para evitar infringir la restriccin de clave primaria. Si ahora volvemos a ejecutar la pgina ASP, la primera alta se ejecuta correctamente, pero luego vemos que la propiedad cadenaConex aparece vaca, y la segunda alta falla al no serle suministrado al mtodo Open del objeto Connection una cadena de conexin correcta. Qu es lo que ha ocurrido? Los Servicios de Componentes han interceptado la creacin del objeto, y estn ahorrando recursos. Despus de la llamada al primer mtodo, 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 llamramos diez veces al mtodo alta, estaramos activando y desactivando el objeto diez veces, perdiendo entre las llamadas la informacin de estado del mismo. Esto puede parecer que tendr poco rendimiento, pero no es as, y se ahorran recursos que estaran sin utilizar entre las llamadas. Aunque la pgina 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 gestin de los Servicios de Componentes. Una forma de conseguir que el componente funcionara correctamente sera volver a asignar valor a la propiedad cadenaConex antes de llamar por segunda vez al mtodo alta. Otra manera sera modificando una de las propiedades declarativas del componente. Si de entre sus propiedades elegimos la pestaa Activacin y desactivamos la casilla Habilitar activacin puntual, conseguimos que los Servicios de Componentes no gestionen la activacin 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 pgina ASP guarda una referencia a l. Para que estos cambios en la propiedad declarativa del componente tengan efecto, debemos descargar previamente de memoria la aplicacin COM+. Pero de este modo perdemos las ventajas de escalabilidad mediante el ahorro de recursos que nos proporcionan los Servicios de Componentes. Ms eficaz sera hacer que la cadena de conexin fuera suministrada como parmetro al mtodo, 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 conexin directamente de una variable de aplicacin. Tambin podramos usar el mtodo Activate del interfaz ObjectControl, para asignar en ese momento el valor a la cadena de conexin, leda desde el objeto Application. Hagmoslo as, como en el Cdigo fuente 172.
234
Grupo EIDOS
Option Explicit Implements ObjectControl Private mvarcadenaConex As String Private objContext As ObjectContext Public Sub alta(ByVal id As Integer, ByVal nombre As String, ByVal saldo As Currency) Dim objCnx As ADODB.Connection Dim objCmd As ADODB.Command Dim objRst As ADODB.Recordset Dim objPar1, objPar2, objPar3 As ADODB.Parameter Set objContext = GetObjectContext Set objCnx = New ADODB.Connection objCnx.Open mvarcadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.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 objPar1 objCmd.Parameters.Append objPar2 objCmd.Parameters.Append objPar3 objCmd.Execute , , adCmdStoredProc objContext.SetComplete objCnx.Close Set objCmd = Nothing Set objCnx = Nothing End Sub Private Sub ObjectControl_Activate() Dim objResponse As Response Dim objApplication As Application Set objContext = GetObjectContext Set 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 Response Set objContext = GetObjectContext Set objResponse = objContext("Response") objResponse.Write "desactivado a las " & Time & "<br>" End Sub Private Function ObjectControl_CanBePooled() As Boolean ObjectControl_CanBePooled = False End Function Cdigo fuente 172
Si ahora ejecutamos la pgina con el Cdigo 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;Initial Catalog=ASPComp;Data Source=varrondo" Set objCom = Server.CreateObject("CompAlta.Alta") objCom.alta 1,"pepe",1000 objCom.alta 2,"pepa",2000
235
Grupo EIDOS
Hagamos ahora otro componente, que extienda la funcionalidad del anterior, permitiendo un mantenimiento sencillo de la tabla recin creada, por medio de tres mtodos: uno para hacer altas, otro bajas y otro consulta. Para hacer que el componente sea lo ms reutilizable posible, haremos que la cadena de conexin se suministre por medio de una variable de aplicacin, como acabamos de ver, y que el acceso a la base de datos sea a travs de procedimientos almacenados. Tendremos que aadir los dos nuevos que aparecen en el Cdigo fuente 174.
CREATE PROCEDURE baja @id smallint AS DELETE FROM Clientes WHERE id=@id
objContext As ObjectContext objApplication As Application mvarcadenaConex As String objCnx As ADODB.Connection objCmd As ADODB.Command objRst As ADODB.Recordset
Public Function consulta() As Variant() Set objContext = GetObjectContext Set objApplication = objContext("Application") mvarcadenaConex = objApplication.Contents("CadenaConex") Set objCnx = New ADODB.Connection objCnx.Open mvarcadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.CommandText = "consulta" Set objRst = objCmd.Execute(, , adCmdStoredProc) consulta = objRst.GetRows objCnx.Close Set objCmd = Nothing Set objCnx = Nothing End Function Public Sub baja(ByVal id As Integer) Dim objPar1 As ADODB.Parameter Set objContext = GetObjectContext Set objApplication = objContext("Application") mvarcadenaConex = objApplication.Contents("CadenaConex") Set objCnx = New ADODB.Connection objCnx.Open mvarcadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx
236
Grupo EIDOS
objCmd.CommandText = "baja" Set objPar1 = objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id) objCmd.Parameters.Append objPar1 objCmd.Execute , , adCmdStoredProc objCnx.Close Set objCmd = Nothing Set objCnx = Nothing End Sub Public Sub alta(ByVal id As Integer, ByVal nombre As String, ByVal saldo As Currency) Dim objPar1, objPar2, objPar3 As ADODB.Parameter Set objContext = GetObjectContext Set objApplication = objContext("Application") mvarcadenaConex = objApplication.Contents("CadenaConex") Set objCnx = New ADODB.Connection objCnx.Open mvarcadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.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 objPar1 objCmd.Parameters.Append objPar2 objCmd.Parameters.Append objPar3 objCmd.Execute , , adCmdStoredProc objCnx.Close Set objCmd = Nothing Set objCnx = Nothing End Sub Cdigo fuente 175
Y la pgina ASP necesaria para probar su funcionamiento est en el Cdigo 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;Initial Catalog=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")
237
Grupo EIDOS
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.consulta Response.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>" next Response.Write "</tr>" next Response.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> Cdigo fuente 176
238
Grupo EIDOS
Adems si le pasamos la cadena de conexin de esta forma, en vez de recuperarla del objeto Application, podemos reutilizar el componente desde clientes que no sean pginas ASP, puesto que ya no hacemos uso de un modelo de objetos especfico. Retomemos el ejemplo del componente de altas, que habamos llamado CompAlta. Eliminemos del proyecto la referencia a la librera con el modelo de objetos de ASP, que ya no vamos a utilizar. Eliminemos tambin, por claridad, los mtodos del interfaz ObjectControl. Si sustituimos: Implements ObjectControl por Implements IobjectConstruct, tendremos disponible el combo izquierdo el interfaz, y al seleccionarlo se generar automticamente el cdigo inicial de su nico mtodo, Construct. En este mtodo slo tenemos que tomar el parmetro pCtorObj, que es un objeto cuya propiedad ConstructString contiene precisamente la cadena del constructor, cuyo valor definimos mediante una propiedad declarativa. A continuacin asignamos a la variable miembro mvarcadenaConex este valor. Todo esto puede verse en el Cdigo fuente 177.
Option Explicit Implements IObjectConstruct Private mvarcadenaConex As String Public Sub alta(ByVal id As Integer, ByVal nombre As String, ByVal saldo As Currency) Dim objCnx As ADODB.Connection Dim objCmd As ADODB.Command Dim objRst As ADODB.Recordset Dim objPar1, objPar2, objPar3 As ADODB.Parameter Set objCnx = New ADODB.Connection objCnx.Open mvarcadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.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 objPar1 objCmd.Parameters.Append objPar2 objCmd.Parameters.Append objPar3 objCmd.Execute , , adCmdStoredProc objCnx.Close Set objCmd = Nothing Set objCnx = Nothing End Sub Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object) mvarcadenaConex = pCtorObj.ConstructString End Sub Cdigo fuente 177
Si ahora vamos a la consola de administracin de los Servicios de Componentes, y dentro de las Propiedades del componente CompAlta seleccionamos la pestaa Activacin, podemos marcar la casilla Habilitar construccin de objetos y dar valor a esta propiedad declarativa, como se ve en la Figura 69. Si ejecutamos ahora una pgina ASP con un cdigo tan sencillo como el del Cdigo fuente 178, todo funcionar correctamente. Ya se adivina lo fcil que es hacer que este componente trabaje contra otra
239
Grupo EIDOS
base de datos, incluso de otro fabricante, con tal de que disponga de un procedimiento almacenado llamado alta que necesite los mismos tres parmetros, y configuremos administrativamente su nueva cadena de conexin, sin necesidad de modificar en absoluto el cdigo del componente, ni por supuesto de recompilarlo.
Figura 69
Set objCom = Server.CreateObject("CompAlta.Alta") objCom.alta 1,"pepe",1000 objCom.alta 2,"pepa",2000 Set objCom = Nothing Cdigo fuente 178
240
Componentes transaccionales
Introduccin
En este tema vamos a ver componentes transaccionales, es decir, aquellos cuyas operaciones sobre una base de datos deben ser englobadas dentro de una transaccin. El caso ms tpico lo constituye la transferencia de dinero de una cuenta a otra. Utilizaremos la tabla de Clientes, ya conocida de temas anteriores, a la que aadiremos una segunda tabla LogTransferencias y dos procedimientos almacenados. Para lograr una mayor claridad, reduciremos el cdigo lo ms posible. El Cdigo 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 AS UPDATE Clientes SET saldo = saldo + @cantidad WHERE id=@id
Grupo EIDOS
CREATE PROCEDURE registro @fecha datetime, @idEmi smallint, @cantidad money, @idRec smallint AS INSERT INTO LogTransferencias VALUES(@fecha,@idEmi,@cantidad,@idRec) Cdigo 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.
La Propiedad MTSTransactionMode de Visual Basic, como se ve en la Figura 70, permite establecer el atributo de transaccin para una clase. Cuando se compile el proyecto, Visual Basic guardar esta
242
Grupo EIDOS
propiedad en la biblioteca de tipos del componente. Luego, si el componente se aade a una aplicacin COM+, los Servicios de Componentes leern el valor de la propiedad MTSTransactionMode y automticamente establecer el atributo de la transaccin en ese valor, tarea que simplifica enormemente la administracin de componentes escritos en Visual Basic.
Figura 70
Casos prcticos
La pgina contiene todo el cdigo transaccional
En el presente captulo veremos una serie de casos, con distintas opciones de diseo de la aplicacin 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 cmo afecta cada diseo al comportamiento transaccional de la aplicacin. Veremos una pgina ASP con todo el cdigo, parte del cdigo en componentes, todo el cdigo en componentes, distintas configuraciones de dichos componentes, etc. De este modo, viendo una serie de casos prcticos, se pretende que quede claro cmo se encargan los Servicios de Componentes de gestionar las transacciones cuando estn involucradas pginas ASP y componentes registrados en aplicaciones COM+. Veamos un primer ejemplo en el que todo el cdigo de acceso a la base de datos se encuentra en el script de la pgina ASP, como se muestra en el Cdigo fuente 180. En la rama if de esta pgina crearemos un formulario que permita efectuar una transferencia de dinero de una cuenta a otra. El formulario se submitir a la propia pgina, que ser tratado en la rama else.
243
Grupo EIDOS
</head> <body> <%Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=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=objCnx objCmd.CommandText="movimiento" Set objPar1=objCmd.CreateParameter("par1",adSmallInt,adParamInput,2,idEmi) Set objPar2=objCmd.CreateParameter("par2",adCurrency,adParamInput,8,cantidad) objCmd.Parameters.Append objPar1 objCmd.Parameters.Append objPar2 objCmd.Execute numReg,,adCmdStoredProc if numReg=0 then Response.Write "<b>No existe el idEmi</b>" ObjectContext.SetAbort objCnx.Close Response.End end if objCmd.Parameters("par1")=idRec objCmd.Parameters("par2")=cantidad objCmd.Execute numReg,,adCmdStoredProc if numReg=0 then Response.Write "<b>No existe el idRec</b>" ObjectContext.SetAbort objCnx.Close Response.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 objPar1 objCmd.Parameters.Append objPar2 objCmd.Parameters.Append objPar3 objCmd.Parameters.Append objPar4 objCmd.Execute numReg,,adCmdStoredProc objCnx.Close Set objCmd=Nothing Set objCnx=Nothing end if%>
244
Grupo EIDOS
<% Sub OnTransactionCommit if Request.Form("boton")<>"" then Response.Write "<h2>Transaccin completada</h2>" end if End Sub Sub OnTransactionAbort Response.Write "<h2>Transaccin abortada</h2>" End Sub %> </body> </html> Cdigo fuente 180
En la rama else creamos una nica conexin sobre la que instanciamos un objeto Command, que reutilizaremos modificando o eliminando los parmetros de su coleccin 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 mtodo Execute ser la que nos permita comprobar si el cliente exista o no exista. Si su valor es igual cero, no hay ningn registro afectado, luego el cliente no exista. Si su valor es igual a uno, s exista el registro. Por simplificar el cdigo, sta ser la nica comprobacin que hagamos. No verificaremos por ejemplo que el saldo del cliente despus de la operacin permanezca mayor que cero. La directiva <%@ transaction=required %> indica a COM+ que la pgina debe ejecutarse en el contexto de una transaccin. Si no existe una, como es el caso, es creada automticamente. Podemos comprobar que si se produce un error porque alguno de los clientes no existe, o generamos nosotros alguno intencionadamente con la lnea Err.Raise vbObjectError + numError, o hacemos explcitamente ObjectContext.SetAbort en la pgina, la transaccin hace rollback automticamente. Recordemos que los eventos OnTransactionCommit y OnTransactionAbort se automticamente cuando la transaccin ha tenido xito o ha fracasado, respectivamente. disparan
Acabemos diciendo que si la ejecucin de la pgina llega a su fin y no se ha producido ninguna instruccin SetAbort, se considera implcitamente que el voto de la pgina en la transaccin es de SetComplete.
Grupo EIDOS
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 pgina ASP. Acceder a la cadena de conexin a travs de la variable CadenaConex de mbito de aplicacin. El cdigo definitivo puede verse en el Cdigo fuente 181. Debemos aadir al proyecto las referencias a las libreras 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 ObjectContext Dim objApplication As Application Dim cadenaConex As String Dim objCnx As ADODB.Connection Dim objCmd As ADODB.Command Dim objPar1, objPar2 As ADODB.Parameter Dim numReg As Integer Set objContext = GetObjectContext Set objApplication = objContext("Application") cadenaConex = objApplication.Contents("CadenaConex") Set objCnx = New ADODB.Connection objCnx.Open cadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.CommandText = "movimiento" Set objPar1 = objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id) Set objPar2 = objCmd.CreateParameter("par2", adCurrency, adParamInput, 8, cantidad) objCmd.Parameters.Append objPar1 objCmd.Parameters.Append objPar2 objCmd.Execute numReg, , adCmdStoredProc objCnx.Close Set objCmd = Nothing Set objCnx = Nothing If numReg = 0 Then Err.Raise vbObjectError + 1000, "mover", "No existe el cliente" End Sub Cdigo fuente 181
Compilemos el componente. La pgina ASP necesaria para utilizar este componente slo necesita instanciarlo e invocar sus mtodos, como se ve en el Cdigo fuente 182. El cdigo necesario para escribir en la tabla de log lo mantenemos todava en la pgina ASP.
<%@ transaction=required %> <!--#INCLUDE file="ADOVBS.INC"--> <html> <head> <title>Transferencia</title> </head> <body> <%Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=ASPComp;Data Source=varrondo"%> <%if Request.Form("boton")="" then%>
246
Grupo EIDOS
<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 Next objCom.mover idEmi,-cantidad if Err<>0 then Response.Write "<b>Error en el idEmi: </b>" & Err.description ObjectContext.SetAbort Response.End end if objCom.mover idRec,cantidad if Err<>0 then Response.Write "<b>Error en el idRec: </b>" & Err.description ObjectContext.SetAbort Response.End end if On Error Goto 0 Set objCnx=Server.CreateObject("ADODB.Connection") objCnx.Open Application("CadenaConex") Set objCmd=Server.CreateObject("ADODB.Command") objCmd.ActiveConnection=objCnx objCmd.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 objPar1 objCmd.Parameters.Append objPar2 objCmd.Parameters.Append objPar3 objCmd.Parameters.Append objPar4 objCmd.Execute numReg,,adCmdStoredProc objCnx.Close Set objCmd=Nothing Set objCnx=Nothing end if%> <% Sub OnTransactionCommit if Request.Form("boton")<>"" then Response.Write "<h2>Transaccin completada</h2>" end if End Sub Sub OnTransactionAbort Response.Write "<h2>Transaccin abortada</h2>" End Sub %> </body> </html> Cdigo fuente 182
247
Grupo EIDOS
Si probamos ahora la pgina, veremos que funciona correctamente. Si ponemos por ejemplo un cliente de destino que no exista, aparece el mensaje de error correspondiente, y la transaccin hace rollback automtico, no habindose restado la cantidad del saldo del cliente de origen. Esto es as porque el cdigo de la propia pgina es el encargado de decidir el rollback; el componente se limita a efectuar la operacin con la base de datos y generar el error en caso necesario. Pero si ahora registramos el componente en la aplicacin 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 pestaa Transacciones de las Propiedades del componente, como aparece en la Figura 71.
Figura 71
Si ejecutamos de nuevo la pgina y ponemos un cliente de destino que no exista, o se produce cualquier otro error en la pgina, no se hace rollback de las operaciones efectuadas por el componente. Esto es as porque la configuracin No se admite para las transacciones significa que el componente no participa en la transaccin de la pgina, y no tiene voto en la misma. Sin embargo, las operaciones efectuadas por la pgina s hacen rollback en caso de error, y no llega a escribirse la lnea en la tabla LogTransferencias. Lo podemos comprobar haciendo ObjectContext.SetAbort explcitamente, a continuacin de la lnea 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 opcin 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 transaccin del cliente, en este caso la pgina ASP, con lo cual todo el cdigo ASP y el del componente forman una nica transaccin, que
248
Grupo EIDOS
fallar o tendr xito en su conjunto. El componente tambin tiene voto en esa transaccin, aunque no estamos utilizando ahora mismo esta posibilidad (lo haremos ms adelante). Si la pgina no hubiera arrancado la transaccin, es decir, no incluye la directiva <%@ transaction=required %>, entonces no habra ninguna transaccin en curso y no se creara 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 cdigo de la pgina, en caso de hacerse SetAbort. Al no estar la pgina definida como transaccional, no tiene acceso al ObjectContext y la instruccin ObjectContext.SetAbort genera un error. Dentro del bloque if de recepcin del error del componente est activado el gestor de errores de VBScript con On Error Resume Next, y lo pasa por alto, pero no podra hacer este SetAbort por ejemplo al final de la pgina. Si configuramos ahora la propiedad transaccional del componente como Necesario, y al no haber arrancado una transaccin la pgina, se crear una transaccin 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 pgina. La opcin Necesita nuevo produce en este caso el mismo efecto. Pero si volvemos a declarar la pgina como transaccional, y el componente como Necesita nuevo, entonces se iniciar una transaccin nueva para el componente, independiente de la transaccin en la cual se est ejecutando la pgina. En este caso, el SetAbort efectuado por la pgina slo tiene efecto en la transaccin propia, y no hace rollback de los cambios en la base de datos que hubiera provocado el componente.
Option Explicit Public Sub mover(ByVal id As Integer, ByVal cantidad As Currency) Dim objContext As ObjectContext Dim objApplication As Application Dim cadenaConex As String Dim objCnx As ADODB.Connection Dim objCmd As ADODB.Command Dim objPar1, objPar2 As ADODB.Parameter Dim numReg As Integer
249
Grupo EIDOS
Set objContext = GetObjectContext Set objApplication = objContext("Application") cadenaConex = objApplication.Contents("CadenaConex") Set objCnx = New ADODB.Connection objCnx.Open cadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.CommandText = "movimiento" Set objPar1 = objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, id) Set objPar2 = objCmd.CreateParameter("par2", adCurrency, adParamInput, 8, cantidad) objCmd.Parameters.Append objPar1 objCmd.Parameters.Append objPar2 objCmd.Execute numReg, , adCmdStoredProc objCnx.Close Set objCmd = Nothing Set objCnx = Nothing If numReg = 0 Then objContext.SetAbort Err.Raise vbObjectError + 1000, "mover", "No existe el cliente" Else objContext.SetComplete End If End Sub Cdigo fuente 183
En el Cdigo fuente 184 puede verse el fragmento del cdigo de la pgina ASP en que se invocan los mtodos del componente.
Set objCom=Server.CreateObject("CompTransferencia.Transferencia") On Error Resume Next objCom.mover idEmi,-cantidad if Err<>0 then Response.Write "<b>Error en el idEmi: </b>" & Err.description Response.End end if objCom.mover idRec,cantidad if Err<>0 then Response.Write "<b>Error en el idRec: </b>" & Err.description Response.End end if On Error Goto 0 Cdigo fuente 184
Marquemos la pgina como transaccional, y el componente con la opcin 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 transaccin de la pgina. La transaccin se da por buena y los cambios en la base de datos son definitivos. Adems se disparar el evento OnTransactionCommit. Si hago SetAbort desde la pgina, 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 transaccin iniciada por la pgina, con lo que el cdigo de la pgina y del
250
Grupo EIDOS
componente forman una nica transaccin. El voto del componente afecta a toda la transaccin conjunta, igual que el de la pgina, 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 cdigo de la pgina, de forma que desactivemos el gestor de errores de VBScript antes de la segunda llamada al mtodo mover, y eliminamos las lneas del Response.End, como se ve en el Cdigo fuente 185, veremos que si introducimos un id de cliente de origen inexistente, en la primera llamada a mover se hace SetAbort de la transaccin, y en la segunda obtenemos el error Realiz una llamada a un mtodo en un componente COM+ que tiene una transaccin que se ha anulado o que est en curso de anulacin. Esto se debe a que el SetAbort de la primera llamada hace que en el objeto de contexto asociado al componente se marca la transaccin como anulada, y los Servicios de Componentes pueden as liberar los recursos asociados a este objeto, que es inservible mientras dura la transaccin, que ya est anulada.
Set objCom=Server.CreateObject("CompTransferencia.Transferencia") On Error Resume Next objCom.mover idEmi,-cantidad if Err<>0 then Response.Write "<b>Error en el idEmi: </b>" & Err.description end if On Error Goto 0 objCom.mover idRec,cantidad if Err<>0 then Response.Write "<b>Error en el idRec: </b>" & Err.description end if Cdigo fuente 185
Slo nos queda por probar declarar el componente como Necesita nuevo. Con esta configuracin, se inicia una transaccin para el componente, pero es independiente de la transaccin iniciada para la pgina. Si introducimos en el formulario un id de cliente inexistente, se hace rollback de la transaccin del componente, no de la de la pgina. Hay un detalle ms: la transaccin iniciada para la pgina abarca todo el tiempo de ejecucin de la pgina, pero para el componente se inicia una cada vez que se invoca al mtodo mover. Por lo tanto, la operacin de retirar el dinero de un cliente y la operacin de ingresarlo en otro cliente no se consideran una nica transaccin, sino transacciones distintas, y no se har rollback de las dos sino de aqulla que haya fallado.
Option Explicit Public Sub registrar(ByVal fecha As Date, ByVal idEmi As Integer, ByVal cantidad As Currency, ByVal idRec As Integer) On Error GoTo Errores
251
Grupo EIDOS
objContext As ObjectContext objApplication As Application cadenaConex As String objCnx As ADODB.Connection objCmd As ADODB.Command objPar1, objPar2, objPar3, objPar4 As ADODB.Parameter
Set objContext = GetObjectContext Set objApplication = objContext("Application") cadenaConex = objApplication.Contents("CadenaConex") Set objCnx = New ADODB.Connection objCnx.Open cadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.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 objPar1 objCmd.Parameters.Append objPar2 objCmd.Parameters.Append objPar3 objCmd.Parameters.Append objPar4 objCmd.Execute , , adCmdStoredProc objCnx.Close Set objCmd = Nothing Set objCnx = Nothing Exit Sub Errores: objContext.SetAbort Err.Raise vbObjectError + 1000, "registrar", "Fall el registro en el log" End Sub Cdigo fuente 186
El cdigo necesario en la pgina ASP, como se ve en el Cdigo fuente 187, queda mucho ms reducido. Es el entramado que aglutina la funcionalidad de los componentes, invocando ordenadamente sus mtodos.
<%@ transaction=required %> <!--#INCLUDE file="ADOVBS.INC"--> <html> <head> <title>Transferencia</title> </head> <body> <%Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=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
252
Grupo EIDOS
idEmi=Request.Form("idEmi") cantidad=Request.Form("cantidad") idRec=Request.Form("idRec") Set objCom1=Server.CreateObject("CompTransferencia.Transferencia") On Error Resume Next objCom1.mover idEmi,-cantidad if Err<>0 then Response.Write "<b>Error en el idEmi: </b>" & Err.description Response.End end if objCom1.mover idRec,cantidad if Err<>0 then Response.Write "<b>Error en el idRec: </b>" & Err.description Response.End end if On Error Goto 0 Set objCom2=Server.CreateObject("CompLog.Log") On Error Resume Next objCom2.registrar date,idEmi,cantidad,idRec if Err<>0 then Response.Write "<b>Error en el log: </b>" & Err.description Response.End end if On Error Goto 0 end if%> <% Sub OnTransactionCommit if Request.Form("boton")<>"" then Response.Write "<h2>Transaccin completada</h2>" end if End Sub Sub OnTransactionAbort Response.Write "<h2>Transaccin abortada</h2>" End Sub %> </body> </html> Cdigo fuente 187
Lo normal en este caso sera declarar la pgina 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.
253
Grupo EIDOS
Option Explicit Public Sub mover(ByVal idEmi As Integer, ByVal cantidad As Currency, ByVal idRec As Integer) Dim objContext As ObjectContext Dim objApplication As Application Dim cadenaConex As String Dim objCnx As ADODB.Connection Dim objCmd As ADODB.Command Dim objPar1, objPar2 As ADODB.Parameter Dim numReg As Integer Dim objCom As CompLog.Log Set objContext = GetObjectContext Set objApplication = objContext("Application") cadenaConex = objApplication.Contents("CadenaConex") Set objCnx = New ADODB.Connection objCnx.Open cadenaConex Set objCmd = New ADODB.Command objCmd.ActiveConnection = objCnx objCmd.CommandText = "movimiento" Set objPar1=objCmd.CreateParameter("par1", adSmallInt, adParamInput, 2, idEmi) Set objPar2=objCmd.CreateParameter("par2",adCurrency,adParamInput,8,-cantidad) objCmd.Parameters.Append objPar1 objCmd.Parameters.Append objPar2 objCmd.Execute numReg, , adCmdStoredProc If numReg = 0 Then objContext.SetAbort Err.Raise vbObjectError + 1000, "mover", "No existe el cliente de origen" End If objCmd.Parameters("par1") = idRec objCmd.Parameters("par2") = cantidad objCmd.Execute numReg, , adCmdStoredProc If numReg = 0 Then objContext.SetAbort Err.Raise vbObjectError + 1000, "mover", "No existe el cliente de destino" End If objCnx.Close Set objCmd = Nothing Set objCnx = Nothing Set objCom = New CompLog.Log objCom.registrar Date, idEmi, cantidad, idRec objContext.SetComplete End Sub Cdigo fuente 188
Y el cdigo de la pgina ASP queda ahora todava ms reducido, como se muestra en el Cdigo fuente 189.
254
Grupo EIDOS
<body> <%Application("CadenaConex") = "Provider=SQLOLEDB.1;User ID=sa;Initial Catalog=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 Next objCom1.mover idEmi,cantidad,idRec if Err<>0 then Response.Write "<b>Se produjo un error: </b>" & Err.description 'Response.End end if On Error Goto 0 end if%> <% Sub OnTransactionCommit if Request.Form("boton")<>"" then Response.Write "<h2>Transaccin completada</h2>" end if End Sub Sub OnTransactionAbort Response.Write "<h2>Transaccin abortada</h2>" End Sub %> </body> </html> Cdigo fuente 189
255
Grupo EIDOS
Suele compararse un servicio de mensajera con un servicio de email. La diferencia principal es que un servicio de email intercambia informacin entre personas y un servicio de mensajera lo hace entre aplicaciones. Los servicios de mensajera entre aplicaciones trabajan con mensajes y colas. Un mensaje es un trozo de informacin intercambiado entre dos aplicaciones. El formato y contenido de este mensaje es especfico de la aplicacin (puede ser texto o binario), pero para el sistema de mensajera esto es indiferente. No exige un formato especfico para estos mensajes. De hecho, ni siquiera inspecciona su contenido, limitndose a transmitirlo. Sin embargo otras tecnologas, como HTTP, FTP, ODBC, etc, tambin permiten la comunicacin entre plataformas distintas, pero son para tipos particulares de aplicaciones, y se exige un formato especfico para los mensajes. Las colas son los lugares donde se depositan estos mensajes.
El MSMQ es ms lento que otros mtodos de comunicacin de ms bajo nivel, como sockets o canalizaciones con nombre, named pipes. De hecho, MSMQ usa internamente estos mtodos, aunque de forma completamente transparente para m. Sin embargo esta lentitud est compensada por las ventajas que ofrece. Si quiero obtener ms rendimiento, los mensajes se pueden almacenar en RAM. Esto supone mayor velocidad en la gestin de los mensajes, pero ante un fallo del servidor podra perderlos. Si quiero ms fiabilidad ante posibles fallos, los mensajes se pueden almacenar en el disco duro y ser recuperados cuando el servidor se recupere del fallo.
258
Grupo EIDOS
Habr una serie de situaciones en las que interese utilizar el MSMQ para transmitir mensajes entre mquinas que comparten la lgica de una aplicacin 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 mquina. El MSMQ simplemente depositar el mensaje en la cola de destino correspondiente hasta que el ordenador vuelva estar disponible. Si queremos lograr ms escalabilidad del sistema. Parece que esto no tiene sentido, puesto que la transmisin de mensajes con MSMQ es ms lenta, pero en realidad conseguimos ms escalabilidad en el sentido de que se puede manejar ms trfico con picos variables de mensajes sin fallo, aunque cada uno de ellos los maneje ms lentamente. Con comunicaciones sncronas el servidor tiene que estar sobredimensionado para poder soportar los picos ms fuertes en el trfico de mensajes, y an as puede llegar a sobrecargarse. Con comunicaciones asncronas, slo tiene que estar dimensionado para el trfico medio esperado. En los momentos de picos, los mensajes simplemente se almacenarn hasta que puedan ser procesados. Cuando nos interese garantizar que el mensaje ha sido recibido por la aplicacin de destino, pero no es necesario obtener una respuesta inmediata al mensaje.
Y hay dos tipos de clientes: Cliente independiente: Tiene su propia cola de mensajes. Se usa normalmente en porttiles. Cliente dependiente: No tiene cola; depende de un servidor MSMQ.
El MSMQ permite tres modos de envo de mensajes: Basado en memoria: Es el ms rpido. El mensaje se almacena en la memoria hasta que el gestor puede contactar con el gestor de destino. Si hay un problema en la comunicacin, esperar hasta poder hacerlo. El inconveniente es que si hay un fallo en la mquina, se pierde el mensaje. Basado en disco: Es ms lento. El mensaje se almacena en el disco. Cuando llega a la mquina de destino, se elimina del disco. Si hay un fallo en la mquina, se puede recuperar luego del disco. Hace falta un sistema de archivos como el NTFS que permite esta recuperacin.
259
Grupo EIDOS
Figura 72
Si pulsamos con el botn derecho sobre la carpeta de Colas privadas, y del men emergente seleccionamos la opcin Nuevo | Cola privada, podemos crear una nueva cola. Slo hay que suministrar la informacin que se pide en una ventana como en la Figura 73, es decir, el nombre de la cola y su comportamiento transaccional.
Figura 73
260
Grupo EIDOS
Si extendemos ahora el rbol de la cola1 recin creada obtendremos lo que aparece en la Figura 74.
Figura 74
Vamos a ver que podemos utilizar este modelo COM para acceder al servicio MSMQ desde una pgina ASP. Y lo primero que haremos ser repetir lo mismo que conseguimos desde la consola de administracin del servicio. Para ello creemos una pgina ASP con el Cdigo fuente 190.
<%@ Language=VBScript %> <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> </HEAD>
261
Grupo EIDOS
<BODY> <% Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo") objQueueInfo.PathName = ".\PRIVATE$\cola2" objQueueInfo.Create %> </BODY> </HTML> Cdigo fuente 190
En esta pgina simplemente recogemos una referencia al objeto MSMQQueueInfo. A continuacin 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 mtodo Create. Siempre debe asignarse la propiedad PathName antes de llamar al mtodo Create. Si ejecutamos la pgina podremos ver en la consola de administracin del MSMQ que se ha creado una nueva cola privada, de nombre cola2. Ejecutando el Cdigo fuente 191 conseguiramos eliminarla.
Envo de mensajes
Ahora vamos a enviar un mensaje a la cola1 recin creada desde una pgina 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 botn derecho sobre el nombre de la cola y seleccionamos la opcin Propiedades, y luego la pestaa 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 pgina ASP con acceso annimo, tiene activado el permiso de Escribir mensaje, pero no as los de recibir ni inspeccionar mensaje. Pero como ahora slo queremos escribir, con esto es suficiente. En el Cdigo fuente 192 se pueden ver las instrucciones que son necesarias para escribir un mensaje en la cola.
262
Grupo EIDOS
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.Close Set objMsg = Nothing Set objQueue = Nothing Set objQueueInfo = Nothing %> </BODY> </HTML> Cdigo fuente 192
263
Grupo EIDOS
Igual que antes, primero obtenemos la referencia al objeto MSMQQueueInfo, y le asignamos la propiedad PathName que identifica a la cola. A continuacin aplicamos el mtodo Open sobre este objeto para obtener una referencia a la cola. Este mtodo Open recibe dos parmetros, que son especificados por medio de constantes. Para poder utilizar los nombres de estas constantes en vez de tener que recordar su valor numrico, utilizamos la directiva METADATA con el nombre de la DLL en que se encuentran, que en este caso es MQOA.DLL. El parmetro Access especifica el modo de apertura de la cola por la aplicacin, 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 ledos. MQ_SEND_ACCESS (2): Permite enviar mensajes a la cola. MQ_PEEK_ACCESS (32): Slo permite inspeccionar los mensajes, pero no recibirlos.
El parmetro ShareMode especifica qu acceso tienen los dems a la cola mientras est siendo utilizada por la aplicacin. 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 opcin. Permito a los dems el acceso total a la cola. MQ_DENY_RECEIVE_SHARE (1): Si he abierto en modo MQ_RECEIVE_ACCESS, tengo la opcin 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 mtodo Send invocado sobre este objeto necesita como parmetro 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 administracin 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
264
Grupo EIDOS
Por cierto, que podemos configurar las propiedades del mensaje que queremos que aparezcan en el panel izquierdo. Basta con pulsar con el botn derecho sobre la subcarpeta Mensajes de la cola, y seleccionar la opcin Ver | Elegir columnas. Aparecer una ventana como la de la Figura 77 en la que podremos seleccionar la informacin que queremos ver de los mensajes.
Figura 77
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 = 7 objMsg.Send objQueue objQueue.Close Set objMsg = Nothing Set objQueue = Nothing Set objQueueInfo = Nothing Cdigo fuente 193
265
Grupo EIDOS
Podemos comprobar en la consola de administracin 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
Recepcin de mensajes
Una vez enviado el mensaje, vamos a intentar recuperarlo desde una pgina ASP. Normalmente las pginas ASP se limitarn a enviar mensajes a una cola, y ser otra aplicacin la encargada de recuperarlos y procesarlos, pero vamos a ver que tambin desde el VBScript de una pgina ASP podemos hacer esto mismo, aunque slo sea en este caso para listarlos en una tabla. De momento slo vamos a inspeccionar el mensaje, es decir, veremos su contenido pero no lo eliminaremos de la cola. Creamos para ello una nueva pgina ASP con el cdigo que puede verse en el Cdigo 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.PeekCurrent Response.Write objMsg.Label & " - " & objMsg.Body objQueue.Close Set objMsg = Nothing Set objQueue = Nothing Set objQueueInfo = Nothing Cdigo fuente 194
266
Grupo EIDOS
Esta vez abrimos la cola en modo MQ_PEEK_ACCESS, es decir, para inspeccionar. A continuacin obtenemos una referencia a un objeto MSMQMessage a partir del mtodo PeekCurrent invocado sobre la cola. Este mtodo 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 tena mayor prioridad. Escribimos la etiqueta y el cuerpo del mensaje, cerramos la cola, y eliminamos los objetos. Si ejecutamos esta pgina, 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 concedrselos a travs del grupo Todos, como se ve en la Figura 79, activando la casilla de verificacin correspondiente a Inspeccionar mensaje.
Figura 79
Ahora s podremos ejecutar la pgina 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 travs de un bucle, como se puede ver en el Cdigo 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
267
Grupo EIDOS
If objMsg Is Nothing Then Exit Do Response.Write "<b>" & objMsg.Label & "</b>: " & objMsg.Body & "<br>" Set objMsg = objQueue.PeekNext(,,100) Loop objQueue.Close Set objMsg = Nothing Set objQueue = Nothing Set objQueueInfo = Nothing Cdigo fuente 195
Utilizamos el mtodo de lectura anticipada, y luego un bucle infinito Do While True, del que slo se sale con Exit Do en el caso de que el mensaje ledo en un paso del bucle sea igual a Nothing, es decir, que ya no queden mensajes en la cola. Tanto en el mtodo PeekCurrent, que lee el mensaje actual, como el PeekNext, que lee el siguiente, son slo mtodos de inspeccin de mensajes: leen el mensaje pero no lo eliminan de la cola. Cuando se invoca a cualquiera de estos dos mtodos, la ejecucin 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 parmetros opcionales que pueden recibir estos mtodos, el ReceiveTimeout, que se especifica en milisegundos. Antes no hemos utilizado este parmetro porque sabamos que haba un mensaje en la cola. Pero si en este caso no lo utilizamos, la ejecucin de la pgina entrara en un bucle infinito, porque despus de leer el ltimo mensaje de la cola, volvera a ejecutar el bucle y se quedara intentando leer uno nuevo de forma indefinida. En el cdigo de ejemplo se han asignado 100 milisegundos de timeout de recepcin. Si en vez de slo inspeccionar un mensaje queremos recibirlo, es decir, leerlo y eliminarlo de la cola, debemos escribir algo parecido al Cdigo 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.Close Set objMsg = Nothing Set objQueue = Nothing Set objQueueInfo = Nothing Cdigo fuente 196
Ahora abrimos la cola en modo MQ_RECEIVE_ACCESS en vez de MQ_PEEK_ACCESS, e invocamos al mtodo ReceiveCurrent en vez de PeekCurrent. Para que funcione la pgina, debemos conceder permisos de recepcin de mensajes en la cola activando la casilla de verificacin correspondiente a Recibir mensaje, como se aprecia en la Figura 80.
268
Grupo EIDOS
Figura 80
Se puede observar en la consola de administracin del servicio MSMQ que el mensaje ha desaparecido de la cola despus de haber sido ledo.
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 botn derecho sobre el nombre de la cola y seleccionamos la casilla de verificacin 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.
269
Grupo EIDOS
Figura 81
Figura 82
270
Grupo EIDOS
Figura 83
Adems debemos implementar los procedimientos Class_ReadProperties y Class_WriteProperties, que sern invocados automticamente en la serializacin y en el proceso inverso, leyendo o escribiendo en el PropertyBag. El Cdigo fuente 197 muestra el resultado definitivo.
271
Grupo EIDOS
Private mvarnombre As String Private mvarsaldo As Currency Public Property Let id(ByVal vData As Integer) mvarid = vData End Property Public Property Get id() As Integer id = mvarid End Property Public Property Let nombre(ByVal vData As String) mvarnombre = vData End Property Public Property Get nombre() As String nombre = mvarnombre End Property Public Property Let saldo(ByVal vData As Currency) mvarsaldo = vData End Property Public Property Get saldo() As Currency saldo = 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", mvarid PropBag.WriteProperty "nombre", mvarnombre PropBag.WriteProperty "saldo", mvarsaldo End Sub Cdigo fuente 197
Hay un inconveniente ms, y es que las limitaciones inherentes a un lenguaje de script como es el VBScript nos impiden ejecutar desde una pgina ASP el cdigo necesario para enviar, y posteriormente recibir, este componente serializado a una cola de MSMQ. Tenemos que hacerlo tambin a travs de otro componente. Vamos a hacerlo creando un nuevo mdulo de clase en el mismo proyecto, al que llamaremos GestionMSMQ, y que tendr dos mtodos: uno para enviar el objeto a la cola y otro para recibir el objeto desde la cola. Debemos aadir al proyecto la referencia a la librera de Microsoft Message Queue, como se ve en la Figura 84. El Cdigo fuente 198 muestra el estado final de este nuevo mdulo de clase. En el mtodo EnviaComponente asignamos a la propiedad Body del mensaje el objeto instanciado. En el otro mtodo, RecibeComponente, recorremos en un bucle, slo de inspeccin, la cola de mensajes hasta encontrar el primero cuya etiqueta coincide con la que recibe el mtodo como parmetro. En ese momento, se recibe el mensaje, con lo que se borra de la cola, se sale del bucle y posteriormente de la funcin.
272
Grupo EIDOS
Figura 84
Option Explicit Private objCliente As CompCliente.Cliente Private objQueueInfo As MSMQ.MSMQQueueInfo Private objQueue As MSMQ.MSMQQueue Private objMsg As MSMQ.MSMQMessage Public Function EnviaComponente(ByVal id As Integer, ByVal nombre As String, ByVal saldo As Currency) As Variant On Error GoTo Errores Set objCliente = New CompCliente.Cliente objCliente.id = id objCliente.nombre = nombre objCliente.saldo = saldo Set objQueueInfo = New MSMQ.MSMQQueueInfo objQueueInfo.PathName = ".\PRIVATE$\cola1" Set objQueue = objQueueInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE) Set objMsg = New MSMQ.MSMQMessage objMsg.Label = "Mensaje Cliente" objMsg.Body = objCliente objMsg.Send objQueue objQueue.Close Set objMsg = Nothing Set objQueue = Nothing Set objQueueInfo = Nothing EnviaComponente = "Mensaje enviado" Exit Function Errores: EnviaComponente = Err.Description End Function
273
Grupo EIDOS
Public Function RecibeComponente(Etiqueta As String) As Variant On Error GoTo Errores Set objQueueInfo = New MSMQ.MSMQQueueInfo objQueueInfo.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 Do If objMsg.Label = Etiqueta Then Set objMsg = objQueue.ReceiveCurrent(, , , 100) Set RecibeComponente = objMsg.Body Exit Do Else Set objMsg = objQueue.PeekNext(, , 100) End If Loop Salida: objQueue.Close Set objMsg = Nothing Set objQueue = Nothing Set objQueueInfo = Nothing Exit Function Errores: RecibeComponente = Err.Description Resume Salida End Function Cdigo fuente 198
Si enviamos ahora varios mensajes a la cola, algunos como ya hemos visto, y otros utilizando el mdulo de clase recin creado, con una pgina ASP tan simple como la del Cdigo 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",7000 Set objCom = Nothing Cdigo fuente 199
Probemos ahora que funciona el otro mtodo. Cada vez que ejecutemos la pgina mostrada en el Cdigo 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 pgina ASP slo estamos recuperando el objeto, pero es fcil imaginar que podramos hacer un alta en la tabla con los datos recuperados. De esta forma podramos, por ejemplo, ir almacenando las peticiones de altas de clientes en la cola, para luego ser procesadas todas de golpe en otro momento.
274
Grupo EIDOS
Figura 85
Set objCom = Server.CreateObject("CompCliente.GestionMSMQ") 'objCom.EnviaComponente 7,"pepe",7000 'Set objCom = Nothing 'Response.End On Error Resume Next Set objCliente = objCom.RecibeComponente("Mensaje Cliente") if Err=0 then Response.Write objCliente.id & "<br>" Response.Write objCliente.nombre & "<br>" Response.Write objCliente.saldo & "<br>" else Response.Write "No hay ms mensajes de clientes en la cola" end if Cdigo fuente 200
275
El ejemplo ms utilizado para explicar lo que podra ser un directorio sera el de un listn telefnico. Almacena informacin, que est replicada, sin importar demasiado que la informacin almacenada en distintos sitios coincida exactamente. Est ms optimizado para lectura (bsqueda de un nmero de telfono) que para escritura (en este caso la escritura significa hacer una nueva impresin de listines).
Grupo EIDOS
No importa como est implementado internamente el directorio (podra utilizarse una base de datos relacional). Lo que importa es cmo veo y como accedo yo a esa informacin desde fuera. Si un Directorio es un almacenamiento de informacin, un Servicio de Directorio es el software que se encarga de obtener esa informacin. Tambin se encarga de proporcionar la gestin de seguridad, de forma que slo accedan a la informacin almacenada las personas que estn 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 ms directorios, como los de Microsoft Exchange, Lotus Notes, etc. El problema est en que cada uno de ellos tiene su propio servicio de directorio especfico, y la forma de acceder es distinta
La informacin almacenada en el Active Directory es realmente de dos tipos. Por una parte est la informacin que se necesita para la gestin del dominio, como equipos, cuentas, impresoras, etc. Por otra parte est la informacin que se quiera guardar, como un directorio de propsito general Disponer de un servicio de directorio como el Active Directory de Microsoft supone varias ventajas:
278
Grupo EIDOS
Simplifica la gestin del administrador, que a travs de este servicio de directorio puede configurar de igual forma cuentas, servidores, equipos, aplicaciones, etc. Permite la instalacin automtica de aplicaciones segn el usuario, independientemente de la maquina desde la cual ste haga login en el sistema, utilizando tecnologas IntelliMirror. Por ejemplo, se podra configurar de tal forma que todos los empleados del departamento de Nminas de la compaa tengan acceso a una cierta aplicacin de gestin de nminas. Permite una bsqueda ms eficientes de los recursos de los que dispone el dominio. Por ejemplo, se puede hacer una bsqueda de una impresora con unas determinadas caractersticas de impresin en color o calidad. Permite que el administrador delegue funciones y asigne privilegios a usuarios y grupos. Proporciona una seguridad ms 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 autenticacin. Adems este control de acceso es independiente de si el usuario hizo login a travs de la red local o desde internet. Permite controlar mejor los equipos, concediendo slo a ciertos usuarios o grupos la posibilidad de instalar aplicaciones en los equipos y modificar el registro de la mquina Permite el desarrollo de aplicaciones que se adapten al usuario, segn la informacin que hay almacenada sobre l en el directorio. En el caso del departamento de Nminas, por ejemplo, se podra desarrollar una aplicacin que tuviera una opcin de men disponible slo para el jefe del departamento, pero no para los empleados.
Grupo EIDOS
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 ms difcil trabajar con l que con OLE DB. De igual manera, se puede acceder a Active Directory directamente con LDAP, pero resulta ms cmodo como programador hacerlo con ADSI. Desde nuestras pginas 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 haba Active Directory. Este proveedor recoge informacin de las mquinas de la red, y la presenta como si estuviera almacenada en un directorio similar al Active Directory de Windows 2000, aunque con una funcionalidad ms limitada. Por otra parte, en Windows 2000 sirve para recuperar informacin de la mquina local, que por defecto no se almacena en el Active Directory. Proveedor ADSI para IIS. Accede a la metabase que guarda la informacin de configuracin del servicio web, ftp, etc. Proveedor ADSI para los servicios de directorio de Novell.
Grupo EIDOS
que cuando abrimos una conexin de ADO, a la cual estoy obligado a suministrar el proveedor mediante una cadena de conexin. Con ADSI la propia cadena ADsPath incluye las dos cosas: el proveedor y la identificacin del objeto del directorio.
<%@ 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> Cdigo fuente 201
281
Grupo EIDOS
En la pgina ASP nos limitamos a recoger una referencia al objeto raz 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 jerrquica en forma de rbol. Si este objeto no tiene padre, significa que es el raz. Este objeto tambin se conoce como ADSI Router, y de l derivan en jerarqua todos los proveedores ADSI intalados en el equipo. Estos proveedores son objetos de la clase Namespace, como podemos ver si ejecutamos la pgina anterior, sustituyendo el parmetro ADsPath por Set objProveedor = GetObject("WinNT:"). En la Tabla 11 est el resultado obtenido. Nombre WinNT: Ruta WinNT:
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 maysculas (devolvera error si ponemos Winnt en vez de WinNT), pero no as el resto de la cadena ADsPath. Esto es as en la mayora 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 ms, y obtenemos el objeto que representa al dominio. Pero adems para este objeto podemos mostrar una propiedad ms, llamada Schema. La Tabla 12 muestra un posible resultado. Nombre GRUPO Ruta WinNT://GRUPO
282
Grupo EIDOS
La propiedad Schema devuelve el ADsPath del objeto Schema, que especifica qu informacin (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 slo 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, segn el proveedor. Name: nombre comn del objeto. Parent: contiene la ruta que identifica al objeto superior en la jerarqua del rbol. Schema: contiene la ruta del objeto Schema que describe a este objeto, es decir, qu tipo de informacin debe almacenar (propiedades obligatorias y opcionales).
Y los mtodos del interfaz IADs son: Get: obtiene el valor de una propiedad identificada por su nombre. GetEx: igual que Get, pero tambin para propiedades con valores mltiples. 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 estn almacenadas, normalmente en otra mquina de la red, lo que sera muy lento, accedo a una copia local inprocess llamada cach de propiedades. Esta copia local puede actualizarse con este mtodo. Put: asigna valor a una propiedad. PutEx: igual que Put, pero tambin para propiedades con valores mltiples. PutInfo: hace el proceso inverso a GetInfo, es decir, enva 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 slo 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 jerarqua 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 Cdigo fuente 202.
283
Grupo EIDOS
<%@ 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> Cdigo fuente 202
Donde nombreDeDominio es el nombre de un dominio. El resultado devuelto sera similar al de la Figura 86.
Figura 86
284
Grupo EIDOS
Los contenedores, aparte de ofrecer el interfaz IADs, presentan tambin el interfaz IADsContainer. Este interfaz tiene las propiedades: Count: Contiene el nmero de objetos hijo del contenedor. Es slo 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 mtodos del interfaz IADsContainer son: CopyHere: copia aqu, como hijo de este contenedor, un objeto del servicio de directorio desde su ubicacin 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 ubicacin original.
<%@ 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>
285
Grupo EIDOS
<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> Cdigo fuente 203
Es necesario activar el manejador de errores de VBScript con On Error Resume Next, por un motivo que veremos a continuacin, 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. Despus 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 ms que ejecutar el Cdigo fuente 202, pero obteniendo ahora la referencia al objeto contenedor de esquemas, con Set objSchema = GetObject("WinNT://GRUPO/Schema"). Despus recorremos cada una de las colecciones de propiedades, obteniendo el valor almacenado para cada propiedad mediante el mtodo 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 coleccin 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
286
Grupo EIDOS
Path
G:\WINNT\System32\inetsrv\inetinfo.exe
ErrorControl 1
PROPIEDADES OPCIONALES
HostComputer LoadOrderGroup ServiceAccountName LocalSystem Dependencies
Tabla 13
WinNT://GRUPO/varrondo
Las propiedades de un objeto del directorio pueden estar almacenadas en cualquier lugar del dominio. Acceder a esa propiedad all donde est sera muy lento. Por eso lo que se hace es acceder a una copia local llamada cach de propiedades. Realmente los mtodos Get, GetEx, Put y PutEx acceden a esta copia local. Para actualizar el contenido de este cach se usa el mtodo GetInfo del interfaz IADs. Si slo quiero actualizar algunas propiedades, se usa GetInfoEx. Para hacer la actualizacin en sentido contrario, es decir, para enviar las propiedades de nuestra cach, que quiz hemos modificado, de vuelta al directorio, se usa el mtodo SetInfo. La primera vez que pido una propiedad, se invoca automticamente al mtodo GetInfo para traer las propiedades a la cach. No hace falta que lo haga yo explcitamente, a no ser que piense que la copia local est obsoleta.
<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)%>
287
Grupo EIDOS
PROPIEDADES OPCIONALES
HostComputer LoadOrderGroup ServiceAccountName LocalSystem Dependencies RPCSS ProtectedStorage
Tabla 14
WinNT://GRUPO/varrondo
La propiedad Dependencies, que antes no poda mostrarse, ahora s. Vemos que es un array formado por dos elementos.
Modificacin 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 pginas ASP es la cuenta de invitado a internet IUSR_NombreMquina, y esta cuenta normalmente tiene permisos muy restringidos. Luego para poder ejecutar con xito una pgina ASP que modifique propiedades de objetos de directorio debemos, o bien conceder permisos a esta cuenta de invitado a internet, o bien ejecutar la pgina ASP bajo otra cuenta con los permisos adecuados. Una vez hecho esto, el Cdigo fuente 205 muestra cmo podramos 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 opcin 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 Cdigo fuente 205
288
Si quiere ver ms textos en este formato, vistenos en: http://www.lalibreriadigital.com. Este libro tiene soporte de formacin virtual a travs de Internet, con un profesor a su disposicin, tutoras, exmenes y un completo plan formativo con otros textos. Si desea inscribirse en alguno de nuestros cursos o ms informacin visite nuestro campus virtual en: http://www.almagesto.com.
Si quiere informacin ms precisa de las nuevas tcnicas de programacin 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 artculos sobre tecnologas de la sociedad del conocimiento.
Si quiere hacer algn comentario, sugerencia, o tiene cualquier tipo de problema, envelo a la direccin de correo electrnico lalibreriadigital@eidos.es.
Si quiere ver ms textos en este formato, vistenos en: http://www.lalibreriadigital.com. Este libro tiene soporte de formacin virtual a travs de Internet, con un profesor a su disposicin, tutoras, exmenes y un completo plan formativo con otros textos. Si desea inscribirse en alguno de nuestros cursos o ms informacin visite nuestro campus virtual en: http://www.almagesto.com. Si quiere informacin ms precisa de las nuevas tcnicas de programacin 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 artculos sobre tecnologas de la sociedad del conocimiento.
Si quiere hacer algn comentario, sugerencia, o tiene cualquier tipo de problema, envelo a la direccin de correo electrnico lalibreriadigital@eidos.es.