Tuesday 6 September 2011

K2 Blackpearl - dynamically set activity outcome from code behind - Part1 - English Version

In this article, I will show you how to set an activity outcomes programmatically.

When the business requirements grow, it's is more easy for developers to manage directly the business logic from the code behind instead of trying to manage it from the IDE.

This article also shows a different way to communicate with a third party datasource, from the K2 process as the SmartObject does, but it will not use SmartObject.

Study case (simplified for the lab) :

Let's suppose that the SYSTEM IS ABLE TO MAKE AUTOMATICALLY A DECISION under specific conditions. This type of activity doesn't require any Destination User but is used only for making decision with input parameters received from an external datasource.

Step 1 :

Create an activity and add a Default Server Event (Code) from the toolbox. Name the activity "System"




Step 2 :

Create a datafield on the activity "System". Select the activity system and do as shown


1 - Select K2 ObjectBrowser
2 - Select the Process/Activity Data icon
3- Select the Activity System, right click and Add

You are going to add a new Data Fields on this activity. When a Datafield is created on an activity, it becomes a property of this activity and is only accessible inside this activity.

Fill the DataField form like the following


Notice that I've set the category to Outcomes.

Step 3 :

Create  OutCome lines on System Activity as many as there's outcomes the activity can take.
To do it, drag a Default line to the System activity


In this article, I create 3 default lines on the System activity. The activity should be like that :
Step 4 :

We need to configure each line to have their own outcomes rules.

Right click the first arrow line, and fill the Line General properties  like :


On the Line General properties Line Rule tab  :


 1 - Select the Line Rule Option
 2 - Click Add
 3 - Click the Browse
 4 - Go to the SystemOutCome datafield, drag and drop it to the First Variable input.
 5 - On comparison operator, choose =
 6 - Set the Second Variable input to the string "Decision 1" (without quotes)
 7 - Click finish

Then click OK. You should have :


Repeat the same steps with the 2 others lines, but change the Decision 1 to Decision 2 or Decision 3.

You should have something like this :

Note : In the real world, you should connect each of those lines to other activities into your K2 process diagram. In this labs, we focus only on the System activity.

Step 5 :

Configure the code behind of the ServerEvent. We'll set our business rule there. To do it :

Right click on the ServeEvent component > View Code > Event Item. It will open the code behind

namespace ExtenderProject_fd73bddd345e4782bbb4cb51bef68a2e
{
    public partial class EventItem_04bac391a41e42aea8272dd6e8848693 : ICodeExtender<hostContext>
    {
        public void Main(Project_fd73bddd345e4782bbb4cb51bef68a2e.EventItemContext_04bac391a41e42aea8272dd6e8848693 K2)
        {
            //We will put our code here
        }
    }
}

Your code is not exactly the same.

Generally when using this approach, the body of the Main method should be a condition switch based on inputs that will used to decide where to dispatch the process, an update method is also expected to perform some business before leaving the activity.

First of all, I will set some const variables that will be used in our code

namespace ExtenderProject_fd73bddd345e4782bbb4cb51bef68a2e
{   
   
    private const string decision1 = "Decision 1";
    private const string decision2 = "Decision 2";
    private const string decision3 = "Decision 3";

    public partial class EventItem_04bac391a41e42aea8272dd6e8848693 : ICodeExtender<hostContext>
    {
        public void Main(Project_fd73bddd345e4782bbb4cb51bef68a2e.EventItemContext_04bac391a41e42aea8272dd6e8848693 K2)
        {
            //We will put our code here
        }
    }
}
Now I need to make the business body of function. To keep thing simply, I only show the general structure of the process

namespace ExtenderProject_fd73bddd345e4782bbb4cb51bef68a2e
{   
   
    private const string decision1 = "Decision 1";
    private const string decision2 = "Decision 2";
    private const string decision3 = "Decision 3";
    private const string systemOutCome = "SystemOutCome";
   
    public partial class EventItem_04bac391a41e42aea8272dd6e8848693 : ICodeExtender<hostContext>
    {
        public void Main(Project_fd73bddd345e4782bbb4cb51bef68a2e.EventItemContext_04bac391a41e42aea8272dd6e8848693 K2)
        {
            //We will put our code here

        int dataFromAnExternalDataSource =     wcfServiceClient.GetDecisionCode(); // get data from an external datasource, described later

        switch (dataFromAnExternalDataSource)
            {
                case 1: //will choose the first decision
                //you can add here some business method that update some entities on the external server
                //wcfServiceClient.UpdateCustomerList();
                    K2.ActivityInstanceDestination.ActivityInstance.DataFields[systemOutCome].Value = decision1 ;
                    break;
                case 2: //will choose the second decision
                    K2.ActivityInstanceDestination.ActivityInstance.DataFields[systemOutCome].Value = decision2 ;
                    break;
                case 3: //will choose the third decision
                    K2.ActivityInstanceDestination.ActivityInstance.DataFields[systemOutCome].Value = decision3 ;
                    break;
                default:
                    break;
            }
        }
    }
}

We will see in the part 2 of this article that we can remove the datafield SystemOutCome and replace it by an OperationContract exposed by a WCF, having a String as return value.

The activity "System" is now ready to take automatically decision depending on the value provided by the external dataSource.

We notice that we haven't include  any embedded methods in the K2 process but have deferred it to a reference of a WCF service instance wcfServiceClient that will retrieve the data through the GetDecisionCode() operationContract. In that manner, we avoid to keep this value into a DataField and make a highly decoupled communication between K2 and other DataSource in our organization.

How to do it ? Read the second part of the article

If this article was helpful for you, please click on one advertisement link on the blog page ;) 

No comments:

Post a Comment