Introducción
La tecnología DotNet Framework 3.0 tiene un componente para implementar Workflow’s[0] llamado Windows Workflow Foundation [1]. Este no es un producto de Workflow sino un motor de workflow más herramientas para los desarrolladores para que construyan sus propias soluciones de Workflow.
Dentro de las cosas más interesantes que veo en WF se encuentra su motor de Reglas de negocio (Rule Engine)[2].
Rules Engine permite hacer desde evaluación de condiciones lógicas hasta la definición y evaluación de complejas reglas que conforman políticas. En este post voy a tratar de explicar cómo se implementan esas políticas y cómo podemos usarlas en nuestros Worklows.
Lo primero que hay que entender es que las políticas son definidas por un conjunto de reglas semánticas llamado RuleSet. Estas reglas son del estilo If/Then/Else. Para poder invocar desde un Workflow la evaluación de un RuleSet se usa la actividad Policy[3].
Procedimiento de evaluación de las Reglas
Las Reglas que componen un RuleSet tienen una propiedad llamada Priority, que permite asignarle una prioridad a cada regla. El procedimiento de Evaluación del RuleSet es el siguiente:
- La regla de mayor prioridad se evalúa y ejecuta la acción del Then o Else.
- Si la acción (Then o Else) cambia el valor de un campo o propiedad que es usado por una regla anterior en la lista de reglas, esa regla afectada por el cambio se re evalúa.
- La siguiente regla de la lista se evalúa y ejecuta la acción del Then o Else.
Veamos el siguiente ejemplo. Tenemos un Workflow sencillo de 3 Actividades, el que se muestra en la imagen 1. La primera actividad muestra los valores de las variables A, B, C, D, E en la consola. La segunda actividad es una Política que tiene 4 reglas que están priorizadas y la última muestra los valores después de aplicar el RuleSet de reglas.
Imagen 1: Workflow de Ejemplo y RuleSet.
El RuleSet se ve en la imagen 1. Las reglas se ejecutan desde la mayor prioridad (4) hasta la menor (1). El proceso en que se ejecutan las reglas es el siguiente:
- Regla_4: Falso
- Regla_3: Verdadero entonces B = 10.
-
Regla_2: Verdadero entonces A=15.
- Como cambio A la Regla_4 se re evalua. Regla_4: Verdadero entonces B=5.
- Regla_1: Verdadero entonces E=7.
Quedando cuando se ejecutan los valores mostrados en la imagen 2 en color Rojo.
Imagen 2: resultados.
Las dependencias entre las reglas son identificadas de tres maneras por el Rules Engine:
-
Dependencia implícita.
Este tipo de dependencia es la que vimos en el ejemplo 1, donde las acciones cambian valores que se usan en otras reglas.
-
Dependencia por atributos.
La dependencia por atributos es usado en reglas que llaman a métodos en el Workflow. Como llama a un método no tiene como deducir implícitamente que reglas debe ReEvaluar. Para usar este tipo de dependencia se debe usar uno de estos tres atributos en el método:
- RuleRead: Este quiere decir que el método lee un valor usado en el RuleSet
- RuleWrite: Este atributo indica que en ese método el valor indicado es modificado.
- RuleInvoke: Este atributo le indica al motor que el método llama a otro método.
Veamos un ejemplo para que sea más simple de entender. Tenemos un Workflow igual al anterior pero con el RuleSet mostrado en la imagen 3. Las reglas son las mismas que antes, pero en vez de cambiar los valores de las propiedades A,B, C, D y E directamente en la acción de la regla se invoca a un método.
El código de cada uno de los métodos invocados desde el RuleSet se muestra en el código 1.
Pueden ver en la imagen 4 que el resultado de la evaluación es el mismo que en ejemplo de reglas implícitas porque se hacen los mismos cambios de valores pero en métodos decorados con los atributos que le dan al motor de regla la información necesaria para actuar.
Imagen 3
[RuleWrite("B")] private void CambiarB(int valor) { this.B = valor; } [RuleWrite("A")] private void CambiarA(int valor) { this.A = valor; } [RuleWrite("E")] private void CambiarE(int valor) { this.E = valor; } |
Código 1.
-
Dependencia Explicita
La dependencia explicita se basa e declarar uno mismo los cambios que ocurren al ejecutar una acción. Para ello se usa la instrucción Update de esta forma Update("this/A") por ejemplo para indicarle al motor que el valor de la propiedad A cambio.
La única ventaja que he encontrado en la dependencia explicita es que se puede hacer por ejemplo esto Update("this/OrdenCompra/*") que le indica al motor que todos los atributos de la orden de compra cambian con esa acción. Esto es notable!!.
El próximo ejemplo se muestra en la imagen 4. Las reglas contienen ahora en la acción la directiva Update. El código de los métodos ya no tiene la directiva RuleWrite, por lo que el motor se entera del cambio de manera explícita. El código de los métodos de cambio, sin el atributo, se muestra en el código 2.
Por último el resultado sigue siendo el mismo!!! Y se muestra en la imagen 4.
Imagen 4.
private void CambiarB(int valor) { this.B = valor; } private void CambiarA(int valor) { this.A = valor; } private void CambiarE(int valor) { this.E = valor; } |
Código 2.
Imagen 4
El motor de reglas es mucho más potente de lo que se muestra en este POST, espero seguir explicando cómo funciona en una serie de post que quiero hacer sobre Windows Forkflow Foundation Rules Engine.
El código fuente de los ejemplos pueden descargarlos dese este Link
Salu2
Referencias
[0] Sistemas de Workflow, http://es.wikipedia.org/wiki/Sistemas_de_workflow
[1] Windows Workflow Foundation, http://msdn2.microsoft.com/en-us/netframework/aa663328.aspx
[2] Introduction to the Windows Workflow Foundation Rules Engine, http://msdn2.microsoft.com/en-us/library/aa480193.aspx
[3] Introducing Microsoft Windows Workflow Foundation: An Early Look , http://msdn2.microsoft.com/en-us/library/aa480215.aspx
Hola Juan Pablo.
Me quedó una duda en la dependencia por atributos (RuleInvoke).
Tu texto:RuleInvoke: Este atributo le indica al motor que el método llama a otro método.
¿Esto significa que el método llamado también debería tener uno de los atributos anteriores (RuleRead, RuleWrite)?
También tengo otra duda con la Dependencia Explicita y en forma puntual con la instrucción que escribiste:
Update("this/OrdenCompra/*")
Con esta instrucción al indicarle al motor de reglas que todos los atributos de la orden de compra cambiaron.¿Como sería el tema de re evaluar las reglas?¿Se volverian a re evaluar todas las reglas?
Gracias y estaremos atentos a los otros post de WF.
Hola Rogelio,
Pregunta 1:
Sí, cuando usas RuleInvoke le estás diciendo al motor que ese método internamente llama a otro método. Ese segundo método debe tener RuleRead o RuleWrite como atributo para que tenga sentido para el motor saber que es llamado, si no lee o escribe una variable de evaluación no tiene sentido que sea sindicado en el atributo RuleInvoke del primer método.
Pregunta 2:
Update("this/OrdenCompra/*")
Las reglas que se re evaluarían son aquellas que usan algún valor de OrdenCompra. Por ejemplo si la condición de la regla es OrdenCompa>1000 entonces, como * significa todo entonces esa regla será re evaluada.
¿ok? ¿se entiende?
Gracias por las preguntas 😉 alguien leyó este POST
Jajajaj
Salu2
Si gracias, me quedó claro.