24 May, 2011

FIM 2010: How to run a “Hello world” - workflow

Given the very poor mass of examples found for FIM 2010, I’ll be aiding this problem for people new to FIM 2010. Manipulation of data in FIM is done in a number of different ways. One developer centric way is via execution of a custom workflow (.NET 3.5), which will be the method I’ll be exploring in this sample.

For an overall introduction to FIM 2010 – see this post:
http://blog.clauskonrad.net/2011/05/fim-2010-developers-quick-introduction.html

The process goes through these steps:

1) Create the custom workflow in Visual Studio (2008/2010)

2) Install it into FIM 2010

3) Create a condition for invoking the workflow (via an MPR)

4) Invoke the workflow

architecture

The above figure (coming from Microsoft's website) presents the extension points in FIM 2010. As seen the FIM Service exposes 3 different kinds of workflows for you to extend:

6) Authentication (who is calling)

7) Authorization (is the individual allowed access/execution)

8) Action (basically every other manipulation)


The nature of these workflow types is kind of self-explanatory and the “Hello World” sample will be an Action Workflow. But, before engaging in code, let’s determine what actually happens when triggering an event in the FIM Service.

Every incoming action in a FIM Service is presented to the FIM Service via it’s web-service API as a Request. The Request contains info on What Operation (Create,Update,Read,Delete) is requested, Who (Actor) is calling and for What Resource (e.g. PersonObject) is the request intended? The below illustration (coming from Microsoft) shows the request processing of an incoming Request.

FIM service request pipeline

Note: The webservice (as far as I know) in itself does not perform any action apart from presenting the Request to the FIM Service for evaluation.

As seen in the figure – the last step is calling of an ‘Action’ workflow if such exists. This is where we will be coming in. Before invoking the Action Workflow lets see how the workflows are actually hosted in FIM?

 

Workflows in FIM 2010

Coming from a WF 3.5 background, you should think that it is straight forward? Well – not entirely :-). The workflows need to obey to certain rules and to be embedded as an activity in a special parent sequential workflow class (Microsoft.ResourceManagement.Workflow.Activities.SequentialWorkflow) from FIM’s universe. This FIM parent workflow actually itself inherits from a System.Workflow.Activities.SequentialWorkflowActivity-class from the native WF 3.5 namespace.

FIM version of SequentialWorkflow

Why a need for this special FIM workflow?
The FIM version of the SequentialWorkflow holds a number of FIM related properties that allows you to gain access to among other things, the incoming Request object as well as the Resource you wish to manipulate (e.g. PersonObject). If you inherited directly from the std. WF version, you would not be able to gain access to these in a FIM context essential properties! If you open the FIM version (the blue element above) in e.g. Reflector or Visual Studio; you will see properties of type ResourceID, Resource, Request etc.

Okay – so far so good; now we know how it is hosted. So how do you create a HelloWorld workflow?

Creating your HelloWorld workflow

1) Open Visual Studio and select Target = 3.5

2) Select ProjectType = ‘Workflow Activity Library’

Visual Studio 2010

3) By default – this projecttype will present you with an Activity that inherits from System.Workflow.Activities.SequenceActivity, which is exactly what you need to create a sequence of actions.

Default designer: SequenceActivity

4) To read a request – drag a ReadResourceActivity into the design surface

ReadResourceActivity

5) Bind Actor, Resource and ResourceID of this activity to 3 new fields

new fields...

6) Override the Execute method' and retrieve the Parent workflow (the FIM version)

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
SequentialWorkflow parentWF = null;
if (!SequentialWorkflow.TryGetContainingWorkflow(this, out parentWF))
throw new InvalidOperationException("Logging activity can not run outside the context of the FIM SequentialWorkflow.");

readRequest_ResourceId = parentWF.RequestId;
readRequest_ActorId = parentWF.ActorId;

m_logData.Add("Got called by FIM...");
m_logData.Add("\tIncoming requestId: {0}", readRequest_ResourceId);
m_logData.Add("\tIncoming actor: {0}", readRequest_ActorId);

base.OnSequenceComplete(executionContext);
return base.Execute(executionContext);
}
The parent workflow is the special FIM-version, remember? This guy carries the incoming Request, Actor and Resource to be manipulated. Set the newly created fields ‘ResourceID’ and ‘Actor’ to point to these properties of the ParentWF (i.e. let the parentWF populate the fields of your custom activity). Note that if we fail to retrieve the parentworkflow, we will throw an exception. It makes little sense to run without it!
7) Override the OnSequenceComplete method to report on progress
protected override void OnSequenceComplete(ActivityExecutionContext executionContext)
{
var reqType = readRequest_Resource as RequestType;
if (reqType == null)
throw new InvalidOperationException("Cannot locate current request...");

m_logData.Add("Request (type=[{0}]) has been processed with the following parameters:", reqType);

var reqParameters = reqType.ParseParameters<CreateRequestParameter>();
foreach (var item in reqParameters)
{
m_logData.Add("\trequestParameter.PropertyName: [{0}] / requestParameter.Value: [{1}]", item.PropertyName, item.Value);
}

base.OnSequenceComplete(executionContext);
}
Note: Due to some reason unknown to me at this time, the ‘Resource’ itself is only available at the time the OnSequenceComplete method is being called by the Parent Workflow. Due to this reason, it is extracted in the OnSequenceComplete method and NOT the Execute method (where Resource = null).
That was a long way to go, but we are not done yet.
 

Installing the workflow in FIM 2010

To install the workflow (the parent FIM version) including your own SequenceActivity, you need to write some XOML to import into FIM. The XOML is generated quite easily in a console app with these lines of code:
static void Main(string[] args)
{
var logAct = new FIMLoggingActivity();

var seqWorkflow = new SequentialWorkflow(); //parent = special FIM SeqWF!
seqWorkflow.Activities.Add(logAct); //add std. WF acticity to parent

var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;

using (var xmlWriter = XmlWriter.Create("CustomWF.xoml", settings))
{
var ser = new WorkflowMarkupSerializer();
ser.Serialize(xmlWriter, seqWorkflow);
xmlWriter.Flush();
}

}

As seen, these few lines of code will create a FIM SequentialWorkflow as parent and add your custom activity (‘logAct’ in the above) as the single activity. Next, it will simply serialize the objectgraph to disk using the standard XmlWriter (system.xml). This resulting file (“customWF.xoml) will be imported into FIM when creating the workflow.


1) Copy the assembly from your development machine –> FIM Server at (C:\Program Files\Microsoft Forefront Identity Manager\2010\Service\*.*)


2) Open the FIM Portal and hit ‘administration’ – ‘workflows’


3) Press ‘new’ and import the xoml-file


WF creation in FIM


4) You are done importing the WF into FIM


 


Invoking the workflow in FIM 2010


Finally – you need some means of invoking the new workflow.


1) Open ‘Management Policy Rules’


2) Add a new policy


MPR


3) Note that is will run when a single property is edited on a Person object (All People)


4) Select Target Resources (before/after)


image 


5) Select your ‘Action’ workflow (in the below ‘CK_MobileWF’)


image


6) You are done!


 


Now – open a person object and change a property. This will trigger the MPR which will trigger your workflow (technically the parentWF which will call your activity).


Change a property -> invoke WF


That’s how ‘easy’ it is (in the simple version!)


 


StackOverflow Tags: ,

9 comments:

dusty said...

Great tutorial, but where is 'm_logData' defined? is this part of FIM?

Claus Konrad said...

m_LogData is just a List<string>. You can't see it in the blogposting...

Steve said...

first timer here, I'm stuck on the BIND statement, my "bind selected property" option is gray... any thoughts?

Claus Konrad said...

Hi

You are most likely using the wrong activity. Note that there are 2 similar activites "ReadRequestActivity" and "ReadResourceActivity". It you "bind-option" is disabled (grey) it because of types not matching...

Rockmus said...

Hello,

I hope someone read my comments, because the last post dates way back. I'm doing a FIM workflow for the first time, but it seems to me there's a bunch of steps omitted from this tutorial.

1. Where does the serialization code go? Separate console app that references the activity assembly? A separate sequential workflow project with separation code?

2. Does the activity dll need ot deployed in GAC? Nothing about dll's in the post.

3. Does the activity need to be configured through Activity Configuration manager in FIM?

4. The code listed doesn't seem to do anything visible to the user. By the looks of it, all it does is dump logging data into a List. Where is the code that actually writes out that list to a file on disk? What are we going to see when the workflow has run?

Here's what I've done:

1. Created the activity library project and the activity as described;

2. Created a separte console app referencing the activity assembly and ran the serialization code;

3. Loaded XOML file when adding a workflow into FIM;

4. Obvisouly, nothing happened when I changed an attribute on a user. Now that I think about it, this is an XOML of an activity, not a workflow.

If anyone reads this, I'd appreciate some clarification.

Thank you,
Ilya

Claus Konrad said...

I actually no longer use this method for workflows in FIM.
But, have a look here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ff859524(v=vs.100).aspx

Rockmus said...

Thank you for the response. Yes, I actually saw that article, that is why I had all these questions. But the method in this post cannot be obsolete, since there's an option to load XOML file in FIM. What am I missing, if I wanted to do it XOML way? You must have had it working at one time...

Claus Konrad said...

Well, it's not obsolete per se. The XOML loading is when you do not want to have a UI to your workflow activity. If you do wish to have such, you do not need to generate the XOML as you make FIM aware of the workflow activity by maeans of an entry in Activity Configuration (the first entry in the Administration section of the Portal). That will take care of the XOML generation for you.

But, if you insist on XOML - look here: http://blog.clauskonrad.net/2012/03/how-to-register-workflow-in-fim-2010.html

Rockmus said...

Ok, so if I understand correctly, KMD.FIMNativeWF is a separate workflow project (empty WF project or sequential workflow library?) where you've probably dropped the custom activity. Then added a console app to the workflow project that serializes it. Is this about right?



I am guessing that my mistake was that I was serializing the activity instead of a workflow with that activity in it.


With XOML apporach, there shouldn't be any dll manipulation, right?