Por: Lucas E. Luna
Introducción
Estamos trabajando en AVANADE participando de un proyecto de desarrollo para una compañía farmacéutica. Estamos realizando un sitio web basado en SharePoint 2010 que utilizaran los empleados para gestionar el ciclos de vida de los productos, mediante unos formularios InfoPath que tendrán proceso de aprobación o rechazo que determinaran la ejecución del Workflow.
Necesidad
Necesitamos que los Workflows se detengan hasta que haya un nuevo cambio determinado por el usuario. El problema fue no tener en cuenta el CorreletionToken
Solución
Agregar un control de InitializeWorkflow y Sequence para crear un nuevo Token.
Para explicar crearemos un nuevo proyecto y armaremos un Workflow con algunos controles. El Workflow debería detenerse antes OnWorkflowItemChanged esperando seguir cuando haya un cambio en el ítem.
Todo Workflow empieza con OnWorkflowActivated y tiene asociado un Correlation Token.
· Un Correletion Token se puede considerar como un identificador único, que serviría para que el flujo se comunique. Este toquen se le asocia a un control.
Este Correlation Token se genere en el Designer.cs del Workflow, como todo control que se agrega.
Y algunos controles tiene un Correlation Token asociado, como es el onWorkflowsActivated.
NOTA: Los componentes de Designer.cs se general automáticamente al agregar controles, mover, eliminar o cambiando propiedades. Es recomendante tratar de no mover controles del Worflow porque quedan “residuos” en ese archivo que puede dar un mal funcionamiento. Lo ideal es que si se quiere mover un control es eliminarlo y volverlo a agregar desde la Toolbox.
Diseñaremos un Workflow básico que se deploya en una List de SharePoint, en donde este se debería detenerse en cada control OnWorkflowItemChange (cada vez que el Ítem cambie el valor en algún campo) sin usar el control InitializeWorkflow para generar un Token nuevo.
Al agregar un Ítem el Workflow se activa, muestra un mensaje “Primero” en el Workflow History y queda detenido hasta que un cambio se produzca.
Hasta ahora el Workflow funciona como lo diseñamos. Cuando vamos a modificar algún campo del Workflow, ese continuara su ejecución. Deteniéndose en el próximo control OnWorkflowItemChange.
Al observar el ítem el estado del Workflow aparece Completed, y si vemos el History podemos notar por el historial que no se debuto en el control OnWorkflowItemChange y el Workflow finalizo.
Esto pasa porque al tener el mismo token el evento ejecuta todos los eventos ya que no tienen forma de diferenciar a que actividad corresponde.
La solución es generar un nuevo Token cada vez que se va a utilizar algún control como ese. Y para diseñarlo debemos usar el control InitializeWorkflow, que se encuentra en la Toolbox, también podemos usar el control Sequence, que se usa como contenedor.
Para generar un nuevo Token, primero agregamos el control Sequence. Y ahí adentro vamos a poner el InitializeWorkflow.
Y en las propiedades del InitializeWorkflow podemos genererar el nuevo Token, asociado a nuestra Sequence. En CorrelationToken ingresamos un nombre, “Token1”, y en OwnerActivityName la Sequence, en este caso el nombre del control, “sequenceActivity1”.
Y luego asociamos a nuestro control OnWorkflowItemChange el Token que creamos. También a todos los controles que estén en esta Sequence asociarle el Token creado, si lo requiere.
Así nuestro flujo no se finalizara sin esperar algún control.
Este es un pequeño ejemplo de como hicimos uso de este control teniendo un perfecto funcionamiento del Workflow.
Si dentro del Workflow tenemos código que modifican el ítem, es posible que disparen otros eventos y entre en un bucle no deseado. Para eso lo ideal es congelar los eventos y hacer las modificaciones al ítem y luego activar los eventos con esta Clase.
Creamos una instancia a la clase y utilizamos el método DisableHandleEventFiring() para desactivarlo y el método EnableHandleEventFiring() para volver a activar los eventos.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
namespace SharePoint.Core
{
public class HandleEventFiring : SPItemEventReceiver
{
public void DisableHandleEventFiring()
{
//obsolete
//this.DisableEventFiring();
this.EventFiringEnabled = false;
}
public void EnableHandleEventFiring()
{
//obsotete
//this.EnableEventFiring();
this.EventFiringEnabled = true;
}
}
}