El abanico de posibilidades que nos brinda SQL Server Integration Services (SSIS) es muy amplio para nuestras soluciones de integración y extracción y transformación de datos. Contamos con más de 30 componentes para nuestro flujo de control y con más de 40 para nuestro flujo de datos. Tareas como el volcado de datos de una tabla a otra, agregar datos, enviar correos en caso de error, bajar un fichero de un FTP y procesarlo… son tareas muy sencillas gracias a los componentes que nos ofrece SSIS out-of-the-box. Pero en ocasiones, encontramos que determinada funcionalidad no esta implementada. Estamos obligados en muchas ocasiones a utilizar la tarea de script o un componente de script para tener una funcionalidad fuera de la estándar proporcionada por el producto. ¿Y si pudiéramos utilizar esta funcionalidad una y otra vez? ¿Y si pudiera ser un nuevo componente y utilizarlo como los componentes que nos da SSIS? La respuesta es que es posible. Pero hay una serie de consideraciones:
- Extender la funcionalidad no es fácil:
- Dificultad: Requiere conocer las clases y métodos que se van a utilizar para codificar esta funcionalidad. Además es dependiente del lenguaje, con lo que tendremos que utilizar C# o VB.net y requiere también de un buen manejo de estos.
- Costes temporales: Debido a la dificultad que presenta esta codificación, el tiempo de desarrollo se ve incrementado sensiblemente.
- Utilizaremos la tarea de script cuando sea posible:
- Fácil: El componente nos abstrae de la mayoría de clases que tenemos que utilizar para realizar el componente, facilitándonos la tarea.
- Rápido: De la misma forma que comentábamos antes, al ser más sencillo, el tiempo de desarrollo es menor.
- Funcionalidad especifica: Si la funcionalidad que vamos a realizar esespecífica a un paquete individual, debemos de utilizar un script (no se reúsa, no se mantiene)
Pero no todo son inconvenientes. Hay requisitos no funcionales dentro de un proyecto como puede ser la mantenibilidad y la reutilización muy importantes. Imaginemos que debemos de utilizar un número de veces elevado la misma funcionalidad y nosotros estamos utilizado una tarea de script. Deberemos de copiar el mismo código o similar a lo largo del proyecto. Y si detectamos un fallo, deberemos cambiarlo en todos los paquetes. Utilizaremos componentes personalizados en cualquiera de estas situaciones
-
La funcionalidad es genérica: Este componente se podrá reutilizar en otros paquetes y por otros desarrolladores.
-
La funcionalidad se repite a lo largo del paquete: Por razones de mantenibilidad, se recomienda encapsularlo en un nuevo componente.
-
La implementación cambia con el tiempo: Imaginemos que tenemos 100 paquetes con una tarea de script y tenemos que cambiar el código. Deberemos de editar esos 100 paquetes. Si hubiéramos utilizado una tarea de script, solo tendríamos que cambiar el ensamblado.
Pasos para elaborar un componente personalizado en SSIS
Para ejemplificar de mejor forma este artículo, vamos a basarnos en la construcción de un componente de tarea de datos. Este componente realizara la siguiente operación, dada un conjunto de datos que tienen variaciones de stock, nos calcula el stock para un momento dado:
Podemos determinar en varias fases la elaboración de un componente personalizado:
Desarrollo de un componente personalizado en SSIS
La fase de desarrollo trata de la creación de una librería de clases en C# o en VB.net. Según el tipo de componente que estemos creando deberemos heredar de unas clases u otras. Así para los diferentes tipos de componentes, tenemos las siguientes clases
Nuestro punto de partida será, una vez elegido nuestro componente, heredar de la clase base para poder empezar nuestro desarrollo. Para verlo mejor, echamos una vista a nuestro proyecto
Tenemos una carpeta UI donde desarrollaremos la UI del componente. Una clase Buffer auxiliar y la clase Correcaminos.cs que se encarga de toda la lógica del componente. Es en esta clase donde tenemos que heredar, en este caso, de la clase PipelineComponent. Además debemos de hacer referencia a las librerías:
– Microsoft.SqlServer.Dts.Design
– Microsoft.SqlServer.DTSPipelineWrap
– Microsoft.SqlServer.DTSRuntimeWrap
– Microsoft.SqlServer.ManagedDTS
– Microsoft.SqlServer.PipelineHost
Pasemos a comentar algunos de los métodos más importantes. Estos se pueden dividir en dos clases, los métodos que son llamados en tiempo de diseño (cuando diseñamos nuestro paquete) y los métodos que son llamados en tiempo de ejecución, cuando se invoca DTEXEC.
Tiempo de diseño
Se llama cuando el componente se añade al dataflow. Crea y configura los inputs y outputs del componente. Es el primer método que se llama en tiempo de diseño, y debemos de configurar si nuestro componente tendrá un comportamiento síncrono o asíncrono.
Se llama cuando el componente es editado durante el diseño y una vez antes de la fase de PreExecute. En este método validamos lo realizado en ProvideComponentProperties y otros aspectos a configurar que deben cumplirse en el componente. Devuelve cuatro tipos de estados:
– DTSValidationStatus.VS_ISCORRUPT: El componente está dañado y debe de ser
– DTSValidationStatus.VS_ISVALID: El componente se ha validado
– DTSValidationStatus.VS_NEEDSNEWMETADATA: La metadata del componente
– UsageType.UT_READONLY: La columna es añadida a la entrada del
– UsageType.UT_READWRITE: La columna es añadida a la entrada del
Tiempo de ejecución
Es el primero de los métodos que es llamado. Aquí debemos de realizar las operaciones pertinentes antes de la ejecución propiamente dicha. Se realizan labores de mapeo de columnas en objetos propios, utilización de variables etc.
PrimeOutput es un método de especial importancia para componentes que se comportan de forma asíncrona. Es un método utilizado por los componentes para transferir filas a los buffers de salida (para los componentes de origen de datos y transformación)
El último de los métodos en tiempo de ejecución es el ProcessInput que se encarga de la ejecución de la lógica pura del componente. Es el que trata la información fila a fila, el que realiza el funcionamiento del componente. Dependiendo del uso de nuestro componente, se codificará.
En cuanto a la interfaz gráfica tendríamos que heredar de las siguientes clases:
Aunque no vamos a adentrarnos en este artículo, es interesante remarcar que la creación de una interfaz gráfica no es una tarea sencilla. Y que, aunque nosotros no tengamos desarrollada dicha interfaz, se nos proporcionan los mecanismos necesarios para poder configurar nuestro componente, una UI por defecto.
Generación
Para generar el ensamblado, debemos de compilar el proyecto. Este proyecto debe de estar firmado de forma que este ensamblado especifica un nombre completo que incluye el nombre del ensamblado, la referencia cultural, la clave pública y el número de versión. El motor en tiempo de ejecución utiliza esta información para localizar el ensamblado y distinguirlo entre otros ensamblados con el mismo nombre.
Para poder firmar nuestro ensamblado tendremos que generar una clave para firmarlo y especificar en las propiedades de Visual Studio que queremos que sea así
Implementación
La fase de implementación consiste en la instalación del ensamblado en la Global Assembly Cache. Este paso es fundamental, ya que si nuestro ensamblado no esta instalado en la GAC, el motor DTEXEC fallara en la ejecución de un paquete con un componente no instalado en la GAC. Para instalar en la GAC, recordar que se puede arrastrar el assembly a la carpeta C:[WindowsIntall]assembly o mediante la consola de comandos de Visual Studio y la herramienta “gacutil”
Instalación en SSIS
Una vez tenemos nuestro componente instalado en la GAC, el siguiente paso es instalarlo dentro de las carpetas correspondientes en el directorio de instalación de Integration Services. Debemos instalarlo en C:Program Files (x86)Microsoft SQL Server100DTS y dependiendo del tipo de componente lo instalaremos en las siguientes carpetas:
En la carpeta Connections, tendremos los ensamblados de los administradores de conexiones; en ForEachEnumerators tendremos los ensamblados de los enumeradores; en LogProviders los proveedores de registro.
En Pipeline components, pondríamos el componente que hemos creador y por último las tareas irían en Tasks
Además si el componente instalado puede ir en la barra de herramientas, tendremos que añadirlo manualmente
Pruebas
Para realizar el testeo de nuestro componente, tendremos que crear un nuevo paquete, ejecutarlo y comprobar los resultados. Si queremos hacer un debug durante la codificación de nuestro componente, tendremos que hacer un attach del proceso, siendo “denenv” el proceso durante la fase de diseño y “DtsDebugHost” el proceso durante la fase de ejecución.
Conclusión
La creación de un componente personalizado para SQL Server Integration Services no es una tarea sencilla. Requiere de un conocimiento bastante profundo de las clases que son utilizadas así como el tiempo de desarrollo es superior al de un fragmento de código en un Script Task o Script Component. Como ventaja las labores de mantenibilidad serán mucho más sencillas en nuestras soluciones de SSIS al igual que la gestión de cambios.
Podemos concluir que la elaboración de un componente solo es necesaria si dicho componente va a solucionar un determinado problema que es reproducible y que puede darse más de una sola vez en el tiempo. En este caso, la creación de un componente nos ayudará mucho en nuestras soluciones de SSIS. Hay que tener en cuenta que cuando tengamos que hacer una migración de estos paquetes, si es a un nuevo servidor que ejecuta la misma versión de SQL Server para el que fue creado, deberemos instalar estas librerías en el nuevo servidor para poder ejecutar estos paquetes. En el caso de que la migración se realice a una nueva versión de SQL Server, deberemos comprobar que ningún método a sufrido alteraciones de una versión a otra.
Por otro lado, cabe medir el tiempo de implementación del componte respecto al tiempo de mantenimiento de los paquetes de SSIS. En el caso de que el mantenimiento sea complejo será una buena elección, en caso contrario debemos de utilizar los propios componentes que nos proporciona SQL Server Integration Services out-of-the-box o soluciones de Script.