Saturday 31 December 2011

Bye Bye 2011 - Welcome 2012

Happy New Year 2012 to All - health - happiness - prosperity -  peace and unity to you and your familly

Sunday 25 December 2011

Comprendre la notion d'application role sous Sql Server en 05 minutes

Une application rôle est au même titre que les database role une notion de la base de données qui va permettre de faciliter la gestion des permissions au niveau des objets depuis un point de vue applicatif.
Les exemples qui suivent sont utilisés dans le contexte d'AdventureWorks
Pour créer une application role :
create application role MonRole with password='MonMotdePasse' , DEFAULT_SCHEMA = Production
Pour vous donner un peu plus d'approche sur la notion, executez la commande suivante :
select * from sys.database_principals
L'interêt d'utiliser une application rôle
- Supposons que dans une société, le département HR accède la base via une application Web1, le département TRAVEL l'accède via un client WPF et le département SERVICE l'accède à partir d'une application WEB2. Chaque membre de ses départements est supposé n'avoir droit qu'aux objects qui les concernent dans la base, et qu'il ne doit pas avoir accès directement à la base ( dans ce sens, pensez sur le fait que sur un client WPF qui s'execute sur le poste de l'utilisateur, l'authentification peut etre les 'credentials' de l'utilisateur lui même ).
Dans ces conditions, il s'avère que le choix de la stratégie d'une application rôle est le moindre effort et la moins couteuse pour le département informatique.

Comment le mettre en oeuvre ? 
Dans ce sens, il faut créer une application role pour chaque département (cf plus haut).

create application role HR_Departement_Role with password='MonMotdePasse' , DEFAULT_SCHEMA = Production
 Il faut noter qu'une application rôle ne contiendra pas d'utilisateurs.

Dans le code application de l'application web destinée aux membres du HR par exemple 

- le code est laissé tres rudimentaire pour se concentrer au contexte principal de l'article


Si je l'execute, alors j'aurai l'erreur

L'erreur montre qu'un select n'est pas permis pour celui sous lequel s'execute le contexte courant.
Celui est  normal car une fois que nous ayions fait appel à l'activation de l'application role dans notre code (sp_setapprole), il faut que celui ci dispose de suffisamment de privilèges pour faire la requête select * from Product

Pour corriger 
grant select on schema::Production to HR_Departement_Role
 Cette commande attribue le droit de faire un select sur le schéma Production (sous lequel appartient la table Product) pour l'application role HR
Après relance, la requête retourne bien la liste voulue.

Ainsi nous avons vu qu'il nous a fallu :
- crèer les application roles et leur droit au niveau de la base
- ajouter 02 lignes de codes pour le changement de contexte d’exécution au niveau du code, et ce totalement indépendant de l'implémentation existante.

Intéressant non !

Saturday 24 December 2011

Xmas Day

I wish you all and your family a Merry Christmas
Je vous souhaite un joyeux noel

Comprendre le type decimal sous SQL Server en moins de 30 secondes

No comment :
 
decimal(4,2) veut dire le nombre est composé de 4 chiffres au total dont 2 situés après la virgule.


Ceci étant la valeur peut varier de 00,00 jusqu'à 99,99 en valeur absolue

Thursday 8 December 2011

Entity Framework managing a many-to-many relationship

In this article, i'll will show how to manage a many-to-many relationship in Entity Framework 4.


First of all, lets's see the representation of the basic model, from power designer :


Here we have two entities named ENTITY_1 and ENTITY_2. One instance of ENTITY_1 may have 1 or more instance of ENTITY_2 and vice-versa. One instance of ENTITY_1 (ENTITY_2) is identified uniquely by a property called ENTITY1_ID (ENTITY2_ID).


At the PMD, we have a physical representation like this




And the corresponding SQL Server Diagram :




So, the question is how to link entries in ENTITY_1 with entries in ENTITY_2 by filling the association table RELATION_1. In TSQL, we need to insert explicitly this combination by doing something like :


INSERT INTO [RELATION_1] VALUES (.......)


This concept doesn't exist explicitly in EF as seen in the generated diagram : 
 The RELATION_1 table, which exist for real in the sys.tables of the current database, is not mapped as a real entity at the EF level.




 After running this code, take a look at all involved tables :


As we can see, the table RELATION_1 is auto filled with the corresponding association. 

Consider the case where the association entity has an attribute named value :


The generated edmx will show a concrete entity named relation_1 having an attribute named value:



As we can see, things become more explicit because EF has created a new entity mapping the RELATION_1 table.


Inserting becomes more easier as show :














Sunday 4 December 2011

SQL Server - une bonne pratique pour la déclaration de CONSTRAINT - French Version

Un objet d'une base de données SQL Server peut être relié à plusieurs contraintes (clé primaire, clé étrangère, contrôle de valeurs, ...). Ces contraintes peuvent être définis soit à la création de l'objet lui-même soit plus tard par une modification depuis la commande ALTER.

J'ai vu souvent vu des scripts de création de contraintes de ce type :


CREATE TABLE [TIPS_05] (ID INT, AGE INT CHECK( AGE > 0))

Malgré le fait que le script passe en exécution, il importe de noter que SQL Server va créer implicitement une contrainte pour 'CHECK(AGE > 0)'


Problématique :

- Supposons que l'entreprise ait une norme établie pour le nommage des objects SQL créés ( y compris les contraintes).
- A un certain moment, une contrainte peut faire l'objet d'une désactivation temporaire, par exemple pour une modification exceptionnelle d'une valeur de la colonne AGE - pour le cas de personne dont l'age n'est pas connue.


La pratique ci-dessus ne vas pas à l'encontre de ce principe. En effet, par principe, la recommandation est de désactivée temporairement la contrainte avant l'insertion et de le remettre une fois les mises à jour effectuées.
Dans le cas présent, nous ne pouvons pas 'deviner à priori' le nom de la contrainte car c'est SQL qui l'a attribué automatiquement

Néanmoins, nous pouvons la voir en executant la requête suivante : 


select * from sys.tables where name = 'TIPS_05'




puis par 
SELECT * FROM sys.objects where type = 'C' and parent_object_id = 759673754



Nous pouvons alors voir que le nom de la contrainte est 'CK__TIPS_05__AGE__2E3BD7D3'

Nous pouvons alors provisoirement la desactiver par 

ALTER TABLE [TIPS_05] NOCHECK CONSTRAINT CK__TIPS_05__AGE__2E3BD7D3

Puis insérer des valeurs non autorisées

INSERT INTO [TIPS_05] VALUES (3,-30)

Puis réactiver la contrainte

ALTER TABLE [TIPS_05] CHECK CONSTRAINT CK__TIPS_05__AGE__2E3BD7D3

Il était alors plus simple  et plus pratique de déclarer la contrainte comme ceci :

-à la rigueur :
CREATE TABLE [TIPS_05] (ID INT, AGE  INT CONSTRAINT CK_AGE  CHECK( AGE > 0))

- idéalement :
CREATE TABLE [TIPS_05] (ID INT, AGE INT);
GO
ALTER TABLE  [TIPS_05]  ADD CONSTRAINT CK_AGE CHECK (AGE > 0);
GO

Ici le nom de la contrainte a été défini explicitement, d'une manière plus facile à deviner selon les conventions de nommages établies.

Friday 2 December 2011

JQuery Autocomplete in an ASP.NET page - The quick howto step by step

Today, i have the need to build quickly a lightweight web control using an 'autocomplete' style. Severals products in the market exist for this implementation :
- ultracombo from infragistics
- autocomplete for ajaxcontroltoolkit
- a jquery plugin as : autocomplete  . it will be shown in this post.

For this purpose, you need to download jquery autocomplete plugin available at http://jqueryui.com/download

1- Deselect all components
2- Select only the autocomplete plugins


3- Click on the download link on the rigth pane of the page ( not display in the screenshot).
It will package all the scripts, samples pages etc... refering this plugin.


In the visual studio, create a web application projet, add folder and files as shown in the screeshot




In this screeshot :
1- Create the folder 'script' and put all js script from the dowloaded package above.
   Those script are needed to run the autocomplete component

2- Create the folder 'style' and put all css from the download package
  Stylesheet to be used 

3- Create an aspx page named 'Json'
  The main page
4- Create an Handler1.ashx ( Generic Handler ) from Visual Studio Add item.
  An handler to handle all ajax requests, process request in server side and return the datas to clien.


In the page Json.aspx :


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
    
    <link rel="stylesheet" href="../style/jquery.ui.all.css">
    <script type="text/javascript" src="../script/jquery-1.6.2.js"></script>
    <script type="text/javascript" src="../script/jquery.ui.core.js"></script>
    <script type="text/javascript" src="../script/jquery.ui.widget.js"></script>
    <script type="text/javascript" src="../script/jquery.ui.position.js"></script>
    <script type="text/javascript" src="../script/jquery.ui.autocomplete.js"></script>
   
    <script type="text/javascript">
        $(function() {
        $(".Form_Product").autocomplete({
                source: "Handler1.ashx",
                minLength: 2,
                select: function(event, ui) {
           
                }
            });
        });
    </script>
</head>
<body>
    <form id="Form" runat="server">  
    <div class="ui-widget">
    <label for="Item">Products : </label>
    <asp:TextBox id="Form_Product" class="Form_Product" runat="server" />       
    </div>
    <asp:HiddenField ID="Form_HiddenValue" runat="server" />   
    </form>
</body>
</html>


In the source parameter, i've define the handler.ashx to where the request is sended. 
The minLength parameter means that the request is fired once the user type 2 caracters in the input.
The select parameter is used to fire action on client side once the server response is received

The Form_Product textbox is the main input linked to the autocomplete feature.

Notice that I've defined a class named 'Form_Product' into it. 
If we look at the second line of the javascript code, i've used a jQuery selector 


Using a class selector $(".Form_Product") is more powerfull than using an Id selector $("#Form_Product") in the way that if the Textbox is embedded into a Master Page, the Id generated by asp.net is changed automatically depending on the hierachical level of the contentplaceholder. The class attribut of the Textbox will always be the same.


The div class="ui-widget" is not mandatory, I've put it for having a specific style.


The Form_HiddenValue is optional, it is used to store the content of the selected item if the page has to support a postback. I will not described that in this post.



That's all of the modification that we need to do in the aspx file.


Go to the code behin of the handle1.ashx and paste the code 


public class Handler1 : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "application/json"; //since i will use a json format as //response, it need to set the contentType to application/json.
            context.Response.ContentEncoding = System.Text.Encoding.UTF8;//will use UTF8 //encoding - optional
            Collection<Data> s = new Collection<Data>();//here I've create a class named Data - we will //see it later in this post
           // Add some value in the collection, noticed the property id and value of the object. They are //required to be set to make the auto mapping of autocomplete plugin. If omitted, the autocomplete //failed
            s.Add(new Data { id = "1", value = "987", Brand = "Apple" });
            s.Add(new Data { id = "2", value = "98765", Brand = "Windows" });
            s.Add(new Data { id = "3", value = "9876534", Brand = "Android" });   
 
// Using of the javascriptSerializer to transform the collection to json format - the input form the //textbox is retrieved by context.Request.QueryString["term"].Here I've used a Linq to filter the //hardcoded collected by the StartWith method.        
            JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
            context.Response.Write(jsonSerializer.Serialize(s.Where(v => v.value.StartsWith(context.Request.QueryString["term"])).ToList()));
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
//here is the Data class. Notice the id, value property. You can omit them in this class and use an anonymous type in the linq query but it's beyond of the scope.Also notice that the class is marked as Serializable to allow the json serialization 
    [Serializable]
    public class Data
    {
        public String id { get; set; }
        public String value { get; set; }
        public String Brand { get; set; }
    }
Now the test


Interpretation :
The autocomplete automatically maps the value property of the json string. In the screen below, the json format returned by the handler.


The textBox is filled by this value property. 


How to access the Brand property ?


In the function select body :


  <script type="text/javascript">
        $(function() {
        $(".Form_Product").autocomplete({
                source: "Handler1.ashx",
                minLength: 2,
                select: function(event, ui) {
            //HERE PUT 

                    alert(ui.item.id);
                    alert(ui.item.value);
               alert(ui.item.Brand); //Magic isn't it ???
                   
                }
            });
        });


The strength :This implementation suits very well in an mvc or mvvm implementation. the viewmodel return only the representation of the business and javascript will do the rest in the view layer.


Hope that this post was helpfull for you.

Sunday 13 November 2011

SQL Server - from xml flat to tabular data

This is a quick tips to show you the simplest way to convert a set of xml data into the equivalent tabular representation.
The data is taken from the adventurework2008 database sample.
Under this database, execute the script below :

SELECT * FROM SALES.INDIVIDUAL


The column Demographics has xml as type. The content looks like :

<IndividualSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey">
  <TotalPurchaseYTD>8248.99</TotalPurchaseYTD>
  <DateFirstPurchase>2001-07-22Z</DateFirstPurchase>
  <BirthDate>1966-04-08Z</BirthDate>
  <MaritalStatus>M</MaritalStatus>
  <YearlyIncome>75001-100000</YearlyIncome>
  <Gender>M</Gender>
  <TotalChildren>2</TotalChildren>
  <NumberChildrenAtHome>0</NumberChildrenAtHome>
  <Education>Bachelors </Education>
  <Occupation>Professional</Occupation>
  <HomeOwnerFlag>1</HomeOwnerFlag>
  <NumberCarsOwned>0</NumberCarsOwned>
  <CommuteDistance>1-2 Miles</CommuteDistance>
</IndividualSurvey>


To translate this result into tabular data, let's see the query below :

WITH XMLNAMESPACES(DEFAULT
    'http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey')
SELECT DEMOGRAPHICS.query('data(/IndividualSurvey/TotalPurchaseYTD)') as TotalPurchaseYTD       
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/BirthDate)') as BirthDate
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/MaritalStatus)') as MaritalStatus
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/YearlyIncome)') as YearlyIncome
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/Gender)') as Gender
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/TotalChildren)') as TotalChildren
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/NumberChildrenAtHome)') as NumberChildrenAtHome
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/Education)') as Education
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/Occupation)') as Occupation
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/HomeOwnerFlag)') as HomeOwnerFlag
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/NumberCarsOwned)') as NumberCarsOwned
       ,DEMOGRAPHICS.query('data(/IndividualSurvey/CommuteDistance)') as CommuteDistance
       FROM SALES.INDIVIDUAL


Since there is a xml namespace declared in the xml, we have to declare it by using :
WITH XMLNAMESPACES.

In the XQuery, we locate each element through their hierarchical order.In the xml result, we can see that the IndividualSurvey is the root of each xml data set. All the others elements come under this hierachy level.
Although this query is very simple to write, its drawback is about the performance.
I'll show you in a next trick how to improve and optimize this query to make the most of the XQuery

Thursday 10 November 2011

11/11/11 11:11 - un peu de souffle

11/11/11 11:11 - boffffff onze s''en fout !!!!

Friday 28 October 2011

SQL Server - prevent some action on tables by using Trigger

Sometimes, were're tired after a long working day.... and by inadvertance, the risk of executing some disasters commands - like delete - becomes higher.
For prevention, we can rollback those operations in all our server object or only on some specifics objects by configuring a DDL trigger.
In the following examples, let's prevent all 'drop table' on the whole objects of our server :

CREATE TRIGGER tddl_droptableprevent
ON ALL SERVER
FOR DROP_TABLE
AS
    BEGIN
        ROLLBACK;
    END
if we try to drop one table, we will receive the message : 
The transaction ended in the trigger. The batch has been aborted.

In other words, the DDL trigger rollbacks all DROP TABLE command

Sunday 23 October 2011

Critique du livre : "The Art of Jazz Saxophone" - Atiba Taylor

Comme le titre l'indique, ce livre se focalise sur l'étude de l'improvisation et de son application dans la pratique du saxophone. Il comporte 124 pages ( 10 chapitres) composées en large partie d'explications techniques et d'illustrations. L'auteur y développe les fondements de l'improvisation ( les gammes et leurs variations , les accentuations ( swing...), etc)  , les styles typiques des grands saxophonistes, partage aussi ses expériences pédagogiques sur les bonnes pratiques d'une apprentissage efficace pour le lecteur.
Dès les premières lignes de l'ouvrage, un connaisseur s’apercevra que le livre est destiné à un public ayant déjà des connaissances théoriques musicales plus ou moins intermédiaire/avancées. Tout au long du développement, l'auteur a mis en avant l'intérêt pragmatique de son ouvrage. En effet, une application pratique immédiate accompagne chaque partie théorique et que la lisibilité des illustrations facilite l'interprétation musicale.


Les chapitres sont : 

Chapter 1 Swing Section
Chapter 2 Blues Section
Chapter 3 Pentatonic Patterns
Chapter 4 Dominant 7ths
Chapter 5 Minor Scale Patterns
Chapter 6 Diminished Scales and Patterns
Chapter 7 Major Patterns
Chapter 8 John Coltrane Patterns and Ideas
Chapter 9 II-V-I
Chapter 10 Fourths




Ce livre est disponible sous format pdf à l'adresse suivate : http://www.lulu.com/product/ebook/the-art-of-jazz-saxophone-improvisation/17969178?showPreview
 La date de publication annoncée est en octobre 2011, ce qui le place parmi l'une des  dernières publications dans ce domaine.



Pour un prix de 8.67 $, ce livre convient parfaitement au saxophoniste qui désire avancer d'un cran dans la pratique de l'instrument. 

Tuesday 20 September 2011

Play sound with Windows Phone 7 SIlverlight App -

Hi all,

There's a time that I've used the Emulator for my dev purpose. One of my apps played a mp3 file, the file has been hard-coded for keeping the thing simple.
Today, I deployed it on my windows phone 7 device, and guess what ?!!! any sound played..., but it perfectly works on the emulator.
First,I think that it is a frequency and rate of the file which is not supported by my phone.So, I've moved the file via Zune on the phone and it can play the song.
What's the matter. I'm sure that my code is correct, but it must be something wrong somewhere.


In the MainPage.xaml, I've used the MediaElement like this :

<MediaElement x:Name="media" AutoPlay="True"  ></MediaElement>

And I the main Page, I've added those two lines after the InitializeComponent method

media.Source = new Uri("Audio/song1.mp3", UriKind.Relative);
media.Play();

When debuging using the device, the screen main application appears but I dont hear any song...

I don't see what's wrong... it becomes boring I've said. So decided to shutdown my PC, unplug the USB cable.... and guess what ???!!!!!  the song is being played ....

Finally, I found the solution... BEFORE TESTING ANY APPS, DISCONNECT FIRST THE USB CABLE

Thursday 15 September 2011

Windows Developer Preview Release of "Windows 8"

Hi all,

As you may know, today is released the Windows Developer Preview Release of "Windows 8", with VS2011 Preview!!!!!  packaged only for x64 at writing


Tomorrow, the new  NET Framework 4.5 Developer Preview will be available too.

So wish you a nice download and a nice preview.


Sunday 11 September 2011

Windows phone 7 tips - Please check that the Zune software is running and that Zune's sync partnership with your phone has been established

Hi all,

I write this article to help some of you when unlocking your windows phone 7 for development purposes.

Why do I write it ?
The reason is that I've spend  a lot of time when I've done it, to resolve the trouble about this process. For some of you, it may be passed for the first time, at the first attempt , but for the others, it was a nightmare... a very very black nightmare ever seen :)

What do you need to unlock the phone ?
- A windows phone 7 device :) A Samsung I8700 Omnia 7 in this article.
- Zune at www.zune.net
- Windows Phone Developer Tools at http://create.msdn.com/en-us/home/getting_started
- Visual studio (optionally for testing deployment to a device)
- An appHub account (with some fees :) ) or if your region is not available for an appHub account, you can subscribe onto your regional center. For example, I live in Mauritius, this country is outside of the global appHub, so I need to subcribe on Yallaapps to unlock my device.

Each of them are available for download.


First of all, install visual studio, the Zune (take care of this installation, read below) and finally the Windows Phone Developer Tools.

Zune install is one of the tricky part of the process. Don't plug your phone during this installation.
Once the install is finished, Zune looks for an available upgrade for the OS. ( Don't accept it, instead "Install later"), it is very important otherwise it will break all futures steps.
Your phone is now plug to your PC. In Zune Go to Settings :


Name your device :

Click OK to save your modification.

At this time, we're ready to register your phone.

Go to Start > Programs > Windows Phone Developer Tools > Windows Phone Developer Registration. Keep phone plugged and Zune running.

It will ask you to enter your account that has been activated on appHubs or others ( for me that was Yallaapps).

Normally, if everything goes well, it will display :


Troubleshoots :
- Error communicating with the developer portal. Please set the correct date and time on the phone, check the Internet connection and try again later ( ErrorCode:0x64) : if you have this error, set the same time on both side ( pc and phone ). Try to have the same time even in seconds unit.
- Please check that the Zune software is running and that Zune's sync partnership with your phone has been established : if you have this error and have checked that your phone is plugged on the pc and Zune is correctly running, do the following :
Go to setting, click update :

This problem is due to an incompatibility between the Zune version and the firmware update. You've certainly done an upgrade before. The restore point is the one that has keeped an image of your last firmware. In major case, the factory setting firmware is the one that is intact. I my case, I've done an upgrade just after I've bought the phone ;) . A hard reset doesn't work.

Before a restore, may be you must backup all your data on the phone. Installed apps will be lost after.

Don't worry to do a restore ;). During the restore operation, my laptop crashed and had rebooted. It was a nightmare for  me, what happened if it will not resume the process ??? The phone screen displayed a dramatic information aaaaaahhhhhhh. But be sure, it was not a problem. Restart Zune and plug your phone, it will redo all the processes from the beginning.


Once your phone is restored, redo the registration process. Normally, the process will be ok.


But that's not all.


You can now upgrade your firmware and your device remains unlocked!!!

If you do a hard reset, the phone will be locked, you need to do the same process registration . May be, you need to restore the factory version for that. 


For any problem on this process , you can post here, i'll reply you as soon as I can.


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

Tuesday 6 September 2011

Windows vista temp folder cleaning

Don't forget to check periodically the folder C:\Users\[USER]\AppData\Local\Temp

Mine costs me 4.92 Go of 160 Go.

SHIFT + DELETE

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

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