Skip to main content

I hope I am not subverting the design of these things by attempting this, but here is what I am attempting:


a) I have a server event that's invoking a WCF service (this may happen asynchronously using MSMQ, so there's no guarantee of an immediate response).
b) The server event has two "Outcomes": success and failure
c) These outcomes result in lines leaving the activity, which have rules which assess the value of a datafield within the activity, called "Outcome". In this way, it's a direct mimic of the default client event (except without the actions, only outcomes).
d) When it's done what it was doing, the WCF service "calls back" through a generic service with the final result of the call (success / failure).


What I am missing is the ability to tell the activity instance which outcome has occurred. Is there a way to do this through the K2 Client namespace? I appear to be able to set values of datafields for the subsequent activity, but not "this" activity. I am not even sure, though, whether simply setting the value of the "Outcome" datafield will be enough to trigger the lines flowing from the activity or whether I will need to tell the activity it's "Complete".


I hope this is not too convoluted or off the beaten track. I wonder if I should be using a client event instead. That would afford me access to actions, which seem to be quite easy to trigger in code...

Let me see if I understand what you are saying.  You want to use a server event to invoke some sort of external process.  The external process may take an unknown amount of time to complete, but once it does, you want to complete the workflow activity?


No worries, that's a common scenario.  The server code event has two run modes:  synchronous (default) and asynchronous.  The asynchronous mode will execute all of the code in the event and then stop.  If you pass the serial number of the activity to your WCF service and then to your generic call back service, you can use the SourceCode.Workflow.Client API to set your result data field and complete the server event.  The server event will then resume and you can use line rules to go to the next activity based on the execution result.


In you can set to asynchronous mode by using this code:


K2.Synchronous = false;


Get the serial number of the current event from K2.SerialNumber and somehow pass that to your WCF service and then to your generic call back service.  Inside the callback service, use the workflow client API to connect to the K2 server, get access to the event by using the OpenServerItem method of the K2 connection, set your result data field and complete the event.


 


Very nice explanation David,  Thanks.


I just wanted to add one point to David's async server event explantion.  The identity that is used to connect back to K2 via the workflow client API within the callback service must have been granted "Server Event" permissions on the specific process within K2 Workspace.  See attached screen shot.


HTH.


12931i7D68CFD6C3CCB276.jpg
That sounds like a particularly sexy solution, David. I will try it out when I get into the office on Monday :)

Please make sure and let us know how it goes, and give us some feedback on your experiences


Ok, I must be daft. When I look at ServerItem, these are the interesting properties I can see:



  • ActivityInstanceDestination 
  • EventInstance
  • ProcessInstance
  • SerialNumber

The datafield which controls the outcome is in the activity instance. EventInstance affords me no access to the activity. ProcessInstance doesn't either. When I set the datafield in the destination activity instance I get an error as one would expect since that's not where the datafield resides.


Should I rather be storing the datafields that control the behaviour of my activity at the process level? This seems rather silly to me. I think that perhaps I am missing a large piece of the puzzle. David, could you elucidate?


Never mind. I figured out that in order to access data fields for the activity instance, I need to set the data fields for the process instance. At least, this is what appears to work.


This seems rather strange and counter-intuitive to me. Surely, an activity instance object should contain the activity instance's data fields and a process instance object should contain... well.. the process instance's data fields.


Update: Since my above solution didn't work, my complaints about the object model are unfounded in this case.


Hooray! my wizard is uploaded, yet incomplete. Please download and rip it to pieces:
http://k2underground.com/k2/ProjectHome.aspx?ProjectID=32


I am afraid I had to re-open this issue because I realised my "solution" above was a misunderstanding (on my part) of how things were working. The code I have at the moment is as follows:



Connection con = new Connection();
con.Open(K2Server);
ServerItem item = con.OpenServerItem(SerialNumber);
if (success)
{
    item.ProcessInstance.DataFieldsl"Outcome"].Value = "Success";
}
else
{
    item.ProcessInstance.DataFieldsF"Outcome"].Value = "Failure";
}
item.Finish();


This works brilliantly if I use a process datafield to trigger the rules /lines in my activity. But I am attempting to use an activity datafield in my activity, since this is the most logical place for it and besides, this is what the client event uses.


Can anyone give me an idea for how to set the value of a datafield in the activity, or is this just not possible?


Reply