Tuesday 6 September 2011

K2 Blackpearl integration - invoking external WCF Service from K2 Blackpearl process - Part2 - English Version

After reading my first post about K2, we know how to use and how to choose outcome automatically from code behind of the activity. As we've seen, we've called an external DataSource and used it to build our business rules.
In this part, I'll show you how a way to integrate a WCF client inside the K2 project. The client will then communicate with any DataSource in your organization, keeping the K2 process highly decoupled to the Business Organisation. 

For example, I've already worked on project that uses datas from Dynamic CRM 4.0 and used them to make a decision on the K2 process.

Study case :

Suppose that your organization exposes a large webservice that is shared with all business units. Not a matter how they are made, you will only consume them by calling the method of your need.
Remember our code in the previous article :

 public void Main(Project_fd73bddd345e4782bbb4cb51bef68a2e.EventItemContext_04bac391a41e42aea8272dd6e8848693 K2)
        {
            //We will put our code here

        int dataFromAnExternalDataSource =     wcfServiceClient.GetDecisionCode();

        switch (dataFromAnExternalDataSource)
            {
                case 1: //will choose the first decision

                    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;
            }
        }
the wcfServiceClient.GetDecisionCode() is the line that we'll focus. It calls the GetDecisionCode() of a WCF webservice in our organization. wcfServiceClient is an instatiation of our wcf service client.

To build the client class:

1 - create a C# class library in visual studio.
2 - Add a service reference to the solution. Point to the Webservice URL of your organization
3 - At this time, Visual studio generate automatically the client class of the web service, update your web.config and the client is ready to query the service. But wait... that's not all.
    We have only setup our local environment to map the webservice. But the client will be used inside the K2 process. So any web.config updated, no libraries generated on the K2 server yet.
    The thing becomes more complicated as expected.
    Fortunately, we can configure the client by code to setup information about the server as URL, binding protocols and so for.
4- In the Class1 (created when we have created our visual studio library solution), let's put the code :

public static class Class1
    {
        public static Devenva.Service1Client GetsServiceReference(string serviceUrl)
        {
            BasicHttpBinding binding = new BasicHttpBinding();
            EndpointAddress address = new EndpointAddress(serviceUrl);    
        //you can put here more configuration about the service,
        //you must set the binding.Name property of WCF service, or the     //MessageEncoding ( by default is text)
        //You can see more example and a lot of way to do this on the book MCTS //Self-Paced Training Kit (Exam 70-503) : Microsoft .NET
        //Framework 3.5, Chapter 4 : Consuming Services      

            Devenva.Service1Client client = new Service1Client(binding, address);           
            return client;
        }
    }
}
Devenva.Service1Client is the Type of the reference that we have setup earlier.
   
5- Now, compile your solution and copy the generated dll to another location than bin/Debug. Why ? we'll use it with our K2 server and therefore it will be locked by this process and you can not recompile the solution again.

6- Go to the K2 IDE, click the project reference icon


7 - Click Add on the Project Reference window

8 - In the Add references, click browse to and choose the location of your dll.

9- Once the dll is added, on the Manage Project Reference, check if the Copy Local is checked for the dll. It will copy the dll into database once the process is deployed.

10 - We can now access all methods by instantiating first a reference to the service :

Devenva.Service1Client clt = Devenva.Class1.GetReference("url_of_your_service");


The codes becomes

public void Main(Project_fd73bddd345e4782bbb4cb51bef68a2e.EventItemContext_04bac391a41e42aea8272dd6e8848693 K2)
        {
            //instatiate the wcf proxy object
        Devenva.Service1Client wcfServiceClient = Devenva.Class1.GetReference("url_of_service");

        //the proxy will handle all WCF OperationContract
        //I can improve by stocking the url_of_service into a process datafield when the process begins.

        int dataFromAnExternalDataSource =     wcfServiceClient.GetDecisionCode();

        switch (dataFromAnExternalDataSource)
            {
                case 1: //will choose the first decision

                    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;
            }
        }

As you see, we have used WCF to allow our K2 process to communicate with the rest of your organization. In that manner, we can change data from external datasources without changing any data in our k2 process. I've used this way to design a process where K2 is only used to route the flow through the workflow tree. We can also remove datafields and use instead WCF OperationContract

In those 2 articles I've show you how to :
    - setup an activity system that decides which outcome should be choose depending on the value returned from an external datasource, this was done in the K2 code behind.
    - add a WCF Proxy library into the K2 solution, the proxy allow the K2 process to communicate with the rest of the world.


Cons/On. : it's up to you, all the following are my personal view

For the process design, K2 recommends the use of SmartObject. SmartObject allows a highly decoupled implementation of the process and the data used by the process. But personally, I think that building a SmartObject from scratch is more time consuming. The reasons are : needs of implementing extra modules, configuring ServiceBroker, deploying Process + SmartObject Service, need access to the K2 server... or instead configuring via the API....
One drawback is when there several developpers work on the same K2 process and code a common methods exposed by the SmartObject. As you know, we configure through the ServiceBroker the url of the service that should be contacted by the K2 SmartObject. Imagine that Developper A modify localy a SmartObject ClientList() method on his visual studio. Developper B also works on the Same method. What's happen ? The method that is invoked is the one that is located at the service declared in the ServiceBroker. So at least one of the Developper A orB will haven't their modification to be available for test. Only one can be invoked.
This is not the case with the method exposed before. By defining the "url_of_service" inside a process dataField, each developer can specify his own service URL (exposed via IIS on the local dev machine) , do their modifications on their local dev environment, and the K2 server process will contact the right service. So several developers can use an unique K2 server, deploy only one process, and can test their works independently.

Hope that it will help you.

Don't hesitate to mail me if you have another point of view.

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

1 comment:

  1. Part one?...Can you put up a link to part one? Thanks!

    ReplyDelete