Habitualmente cuando se realizan ejemplos de workflows de Windows Workflow Foundation (WF) se suele recurrir al diseño y creación de workflows de tipo secuencial. Ahora bien, cómo sin duda sabéis, WF habilita la creación de workflows de máquina de estados, mucho más flexibles y capaces de modelar un espectro más amplio de procesos que los workflows de tipo secuencial sobre todo en lo que a la interacción humana se refiere.
Por otro lado, Windows Sharepoint Services 3.0 (WSS 3.0) y Microsoft Office Sharepoint Server 2007 (MOSS) son las plataformas y tecnologías que ofrece Microsoft para la colaboración y gestión de la información en los equipos de trabajo de una organización, y un conjunto de aplicaciones que mejoran la eficacia de las organizaciones permitiendo la colaboración y gestión de la documentación, aplicando flujos de trabajo con Windows Workflows Foundation, integra un potente motor de búsquedas, gestión de portales, publicación web, integración con Business Intelligence, etc. Por definición, tanto WSS 3.0 como MOSS son herramientas en la que los workflows de máquina de estados encajan a la perfección por estas características de flexibilidad y mayor interacción que hemos comentado. En este post vamos a detallar cómo crear un workflow de máquina de estados para ser desplegado y utilizado en WSS 3.0 & MOSS. Empecemos.
Creación del workflow
El workflow que vamos a crear es realmente sencillo y se compone de tres estados. Este workflow tiene la siguiente funcionaliad: al detectar que se crea un documento en una biblioteca de documentos genera una tarea en la lista de tarea , y que si el documento original sufre alguna modificación. el workflow se "despierta" y actualiza las tareas generadas inicialmente.
El primer paso es crear el proyecto de workflow para Sharepoint en el entorno de Visual Studio 2005 (ya vimos que con Visual Studio 2008 todo es mucho más automático, los pasos en este entorno serían los ya comentados). En este caso tenemos que seleccionar dentro de los proyectos de tipo Sharepoint la plantilla State Machine Workflow Library.
 |
|
Una vez creado el proyecto, vemos que en la superficie de diseño ya tenemos un estado inicial (al igual que ocurre con los workflows de tipo secuenciales y la actividad OnWorkflowActivated): WorkflowInitialState. Por lo tanto, tendremos que añadir dos nuevos estados. El primero de estos estados se encargará de la generación de la tarea, así como de la detección de cambios en el elemento que provocó la generación de la misma. El segundo de los estados es el estado de fin del workflow. Para añadir un nuevo estado al workflow, hacemos clik con el botón derecho del ratón y seleccionamos la opción Add State. Repetimos la operación para añadir el segundo estado a la superficie de diseño:
|
|
Una vez que hemos añadido los estados, el siguiente paso consiste en dotarles de capacidad lógica añadiendo las actividades (propias de WF o de Sharepoint) necesarias. Para añadir estas actividades a un estado del workflow basta con arrastrarlas desde la toolbox del diseñador al estado. En mi caso, el estado 1 se compondrá de 1 actividad de tipo StateInitializationActivity, 2 actividades de tipo EventDrivenActivity, y 1 actividad de tipo StateFinalizationActivity. Cada una de ellas se encargará de responder a los eventos respectivos de creación de una tarea al crearse un ítem en la biblioteca de documentos, modificación de la tarea (para marcarla como completada, especificar un % de completado,...), detectar que se ha producido un cambio en las propiedades del documento que desencadenó el workflow y finalmente detectar que se ha completado el estado y se puede hacer la transición al estado final del workflow.
|
|
Una vez que ya tenemos los estados del workflow y sus correspondientes niveles hijos (actividades que acabamos de añadir), el siguiente paso consiste en especificar los estados de inicio y fin del worlflow a través de las correspondientes propiedades y establecer las transiciones entre estados:
- Para especificar que un estado sea el estado final del workflow, lo seleccionamos y en el menú contextual (botón derecho del ratón) hacemos clic sobre la opción Set As Completed State.
- Para el estado inicial se sigue la misma idea, pero seleccionando la opción Set As Initial State para el estado que queramos que sea el de inicio del workflow.
- Para definir las transacciones, tenemos dos posibilidades:
- De manera visual y seleccionando el nivel hijo dentro de un estado que vaya a ser origen o destino de la transición y cuando en el límite de la misma aparezca el símbolo
, arrastramos hasta el siguiente estado con la que queremos definir la transición. En mi caso, siguiendo este procedimiento, he enlazado la actividad onWorkflowActivated del estado inicial (InitialState) con el segundo estado del workflow...¿y esta transición en que se traduce? Pues si hacéis doble clic sobre el estado inicial varéis que el diseñador de workflows ha añadido a continuación de la actividad onWorkflowActivated una actividad de tipo SetStateActivity que es la responsable de que la transición entre estados tenga lugar.
- De nuevo de manera visual, pero controlando como se realiza la transición en función de definir una cierta condición. Esta técnica la vamos a utilizar para modelar la transición entre el estado intermedio y el definido como final de nuestro workflow:
- Hacemos doble clic sobre la actividad desde la que produce la transición (en este caso on TaskChanged).
- A continuación de la actividad anterior añadimos una actividad de tipo IfElseActivity, que configuramos de manera que en la primera rama situamos una actividad de tipo SetStateActivity que es la que nos permitirá definir la transición del estado actual al destino. Para definir esta transición especificamos que el valor de la propiedad TargetStateName sea CompletedState (que es el último estado del workflow de máquina de estados que estamos construyendo).
Tras realizar los pasos anteriores, tendremos definidas las correspondientes transiciones entre los estados que hemos definido en el workflow.
Configurando los niveles hijos
Hasta ahora hemos diseñado e implementado de manera visual el workflow de máquinas de estados a partir de crear una serie de estados y unas transiciones entre los mismos. como hemos visto, cada estado se compone de una serie de actividades (niveles hijos) que tienen que ser configurados de manera adecuada. En particular, para el workflow creado hay que realizar las siguientes configuraciones:
- Estado InitialState, Actividad onWorkflowActivated, tenemos que configurar la propiedad CorrelationToken. Especificamos para la misma workflowToken (por defecto aparecerá esta).
- Estado TaskCreatedState, para el que realizamos las siguientes configuraciones:
- Hacemos doble clic sobre la actividad InitTaskCreatedState y añadimos a continuación de esta una actividad de tipo CreateTask con las siguientes propiedades:
- CorrelationToken, especificamos como valor taskToken.
- MethodInvoking, especificamos InitCreateTask.
- TaskID, que se configura a partir de la definición de una propiedad (taskID) o campo de la clase que representa el workflow. Se podrá definir de manera visual (a través de la ventana de definición, de la que se detalla un ejemplo debajo) o directamente en código.
- TaskProperties, que configuramos con otra nueva propiedad denominada taskProperties (creada con el mismo mecanismo seguido para taskID).
- Para la actividad onTaskChanged (que es de tipo EventDriven) realizamos las siguientes configuraciones:
- Añadimos una actividad de tipo onTaskChanged encima de la actividad IfElse que gobierna la transición al estado final del workflow. Esta actividad la configuramos del siguiente modo:
- Especificamos como taskToken como valor para la propiedad CorrelationToken.
- Especificamos taskID como valor para la propiedad TaskID.
- Creamos un nuevo campo denominado afterProps (siguiendo el procedimiento visual comentado) para asignarlo a la propiedad AfterProperties.
- Especificamos la condición para la actividad IfElse. En este caso vamos a definir una condición de tipo declarativo (Declarative Rule Condition) con la siguiente expresión: onTaskChanged1.AfterProperties.PercentCompleted==1, es decir, para poder realizar la transición al estado final es necesario que el usuario complete la tarea al 100 %.
- Para la actividad onWorkflowItemChanged (que responde a cambios en el ítem que desencadeno el workflow), realizamos los siguientes pasos:
- Añadimos una actividad de tipo onWorkflowItemChanged, para la que especificamos que su correlation token sea workflow token.
- Añadimos una actividad de tipo Code especificando que el método invocado sea updateDueDates().
- Añadimos una actividad de tipo UpdateTask (responsable de actualizar las tareas si se ha producido un cambio en los ítems a partir de las cuales se generaron) en la que especificamos:
- Propiedad CorrelationToken=taskToken.
- Propiedad TaskID=taskID.
- Propiedad AfterProperties, creamos un nuevo elemento denominado taskProperties.
- Estado CompletedState, en este caso añadimos una actividad de tipo CompleteTask, configurando las propiedades:
- CorrelationToken=taskToken.
- TaskID=taskID.
Codificando los manejadores
Una vez configurados los niveles hijos de cada estado, tenemos que codificar los manejadores que hayamos especificado en los correspondientes niveles hijos. En nuestro caso:
- Método InitCreateTask(), inicializamos la propiedad taskID y definimos algunas de las propiedades propias del objeto taskProperties...en concreto el usuario al que asignaremos la tarea y el título de la misma.
| private void InitCreateTask(object sender, EventArgs e) { this.taskID = Guid.NewGuid(); this.updateDueDates(null, null); this.taskProperties.AssignedTo = "litwaredemo\\Administrator"; this.taskProperties.Title = "Documento a revisar"; } |
- En el método updateDueDates() lo que hacemos es actualizar la fecha de creación de la tarea a partir de añadirle un número aleatorio entre 5 y 15 días (suponemos que este es un requerimiento de negocio).
| private void updateDueDates(object sender, EventArgs e) { Random rand = new Random(); this.taskProperties.DueDate= DateTime.Now.AddDays(rand.Next(5,15)); } |
Sin más, firmamos el proyecto para que el ensamblado que se genere sea seguro y se pueda desplegar en WSS 3.0 / MOSS y compilamos para asegurarnos de que no hay ningún error.
Despliegue y prueba del workflow
Aunque ya comentamos en un post previo la técnica de despliegue de workflows (aunque con Visual Studio 2008 esta tarea se simplifica), vamos a recordar los pasos esenciales:
- El workflow lo desplegaremos como una feature de Sharepoint, por lo que tendremos que crear el correspondiente archivo XML de definición de la misma:
| <?xml version="1.0" encoding="utf-8"?><Feature Id="BD2F0F08-8295-4543-9005-1C051CA8E7C5" Title="Ejemplo de Workflow Máquina de Estados en VS" Description="Ejemplo de workflow de máquina de estados."
Version="1.0.0.0" Scope="Site" xmlns="http://schemas.microsoft.com/sharepoint/"> <ElementManifests> <ElementManifest Location="workflow.xml" /> </ElementManifests> <Properties> <Property Key="GloballyAvailable" Value="true" /> </Properties></Feature> |
- Tenemos que definir el correspondiente manifiesto que describe el workflow:
| <?xml version="1.0" encoding="utf-8" ?><Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Workflow Name="Ejemplo de Workflow Máquina de Estados en VS" Description="Ejemplo de workflow de máquina de estados." Id="A9824E24-3608-4504-A09B-323A492714BB" CodeBesideClass="ResetTaskWorkflow.Workflow1"
CodeBesideAssembly="ResetTaskWorkflow, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31d35b2bfb1b9654"> <Categories/>
<MetaData>
<StatusPageUrl> _layouts/WrkStat.aspx</StatusPageUrl> </MetaData> </Workflow></Elements> |
- Crearnos un script .bat en el que especificaremos los correspondientes comandos para copiar el assembly en la gac, copiar los XML, activar e instalar la feature en los correspondientes directorios dentro del directorio 12 del servidor donde tengamos instalado Sharepoint.
- Nos vamos al site collection dónde vamos a utilizar el workflow y activamos la feature desde la galería de features del site collection.
Probando el workflow
Para probar el workflow, simplemente desde las settings de una biblioteca de documentos de nuestro site collection especificamos que queremos utilizar el workflow que acabamos de desplegar, indicando para ello el nombre de la instancia, la lista de tareas en la que se van a a generar tareas y el modo de arranque (en este caso automático y cuando se cree un nuevo ítem):
Una vez que hemos asociado el workflow a una biblioteca de documentos, para comprobar que la máquina de estados funciona como se espera:
- Creamos o subimos un documento en la biblioteca, de manera que el workflow se iniciará y en la vista de listado de documentos de la biblioteca aparecerá una nueva columna con el nombre de la instancia del workflow y con valor In Progress (se ha creado una tarea que está pendiente de ser completada).
- Si nos vamos a la lista de tareas, veremos que efectivamente se ha creado una tarea y que el estado de la misma es Not Started.
- Volvemos a la biblioteca de documentos y cambiamos uno de los metadatos del elemento que desencadeno el arranque de la instancia al workflow.
- Si volvemos a la lista de tareas, veremos que la columna Due Date presenta un valor distinto al inicial. El workflow ha cumplido con su cometido, a actualizado esta columna al detectar que se había cambiado el ítem origen de la biblioteca de documentos responsable del inicio de la instancia del workflow.
- Modificamos ahora la tarea y especificamos que el campo % Completed tenga un valor 100...si lo hemos hecho bien, esto significa que el workflow tiene que concluir y por lo tanto la columna de estado del workflow en la biblioteca debería tener el valor Completed...y así es!
Y hasta aquí llega este post en el que os queríamos contar como construir un workflow de máquina de estados para Sharepoint. Os podéis descargar el proyecto del workflow de este enlace. Esperamos que os haya resultado interesante.
Comparte este post: