16 November, 2011

FIM 2010: How to make a workflow persist

Having used an extensive amount of time with WF 3.5 and FIM 2010 in combination; it has become evident to me that it is not all that obvious how you enable persistence of a FIM-hosted workflow?

Normally when working with WF you control the hosting environment (runtime-environment) and as such are in full control when it comes to persistence and tracing of workflows; as you add these features yourself when initializing the runtime. This is not the case in FIM where the runtime is provided to you (by the Microsoft.ResourceManagement.Service.exe file [Window Service]). You would then potentially expect to find an entry in <app>.config for this service about persistence; but alas this is not so. You actually need to open up the assemblies using Reflector to detect the whereabouts of this functionality!

Why is this needed or even relevant you might rightfully ask? If your workflowinstance is shut down during execution or power of the server is killed during execution, your workflow will attempt to resume from latest persistence point (if one exists!) when power is restored. A persistence point is the lastknown good state of your workflow.

So – how do you enable this stuff? It so happens that persistence is enabled by default in the WF-runtime provided by FIM. The database this persistence-service uses is the std. FIMServiceDB which by default is named: “FIMService”. You can see the tables involved here:

Persistence tables

Great – so what do you have to do to use this from within your own workflows?

Out-of-the-box, you can use the DelayActivity (std. workflow). This activity will persist the current workflow instance to the database tables when entered.

DelayActivity

You can also force persistence at an arbitrary point in your workflow by adding your own persistence points. You do so by creating a new Activity and decorate this with the [PersistOnClose]-attribute.

PersistOnClose-attribute

This will make the WF-runtime persist the workflow instance to the database as soon as this activity leaves it’s executemethod with a resultcode = ActivityExecutionStatus.Closed;

That’s what it takes to enable and use persistence…

 

StackOverflow Tags:

14 November, 2011

FIM 2010: How to use std. EnumerateResourcesActivity

This actually originates in an error in the Microsoft.RessourceManagement WF-activities, but none the less – it is a problem for many people on how to use this specific Activity.

When dragging on a EnumerateResourcesActivity to your design surface – you do not immediately see a lot of possibilities for enumerating the retrieved values! The only mandatory values you can set from the designer/properties dialog are:

- XPathFilter (what to search for…)
- ActorId (who is performing the readselection?)

After dragging on enumerateResourcesActivity to design surface    Empty propertyGrid

Why is it not possible to retrieve the values enumerated by the Activity? This is due to the fact that the Activity designer built-in to the EnumerateResourcesActivity is wrong. You unfortunately need to go into the <activity>.designer.cs file to correct these errors manually ;-)

Great – so how to do?

1) Open the designer-file (<activity>.Designer.cs) and add a new CodeActivity to the class.

image

2) Instantiate the CodeActivity and set properties after this.CanModifyActivities=true:

image

Important is of course the eventHandler (.ExecuteCode += ….) on the codeactivity. This event wiring will point to a method you add to your main code class like this:

private void RetrieveEnumeratedValues(object sender, EventArgs e)
{
//code missing…
}
3) Now – the most important piece is actually this. You need to add this custom made codeActivity as a childactivity to the fimEnumerate activity.
image
In this way you have bound together the EnumerateResourceActivity and your own CodeActivity. Next is only to actually implement the enumerate code we just wired up. This is quite simple but requires you to use a (non-intuitive) static method called (EnumerateResourcesActivity.GetCurrentIterationItem) like this;
private void RetrieveEnumeratedValues(object sender, EventArgs e)
{
//run though each resource found by fimEnumerate (NOTE: this is a static method!)
var currentItem = EnumerateResourcesActivity.GetCurrentIterationItem((CodeActivity)sender) as ResourceType;

if (currentItem != null)
{
//add to local list for later processing...
m_lst.Add(currentItem);
}
}
As seen if the currentItem (non-null) has a value – it is added to a local List<T> (m_lst) for later processing. The method will be called for each item the fimEnumerate activity has retrieved from FIM.
Again – another example of how (counter) intuitive FIM actually is to work with!

StackOverflow Tags:

FIM 2010: How to read values using native FIM WF objects.

When using the “native” FIM workflow activities for FIM 2010 interaction, it is not always intuitive how to actually retrieve the values from the objects in FIM. In this example, we will be reading properties from a Person-object.

1) Start by creating a new WorkflowActivity [std. WF 3.5]

image_thumb1

2) Drag in the following Activities

2.1) CurrentRequestActivity [Microsoft.ResourceManagement]

2.2) CodeActivity [std. WF 3.5]

2.3) ReadResourceActivity [Microsoft.ResourceManagement]

2.4) CodeActivity [std. WF 3.5]

image

3) Bind the first Activity (fimCurrentRequest) to a newly created DependencyProperty (fimCurrentRequest_CurrentRequest). This will create an object in your workflow of the type: (Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType)
This object you will be referring later in code.

image

4) Bind the second FIM Activity (fimReadResource) to a newly created DependencyProperty (fimReadResource_Resource). This property will hold the result (TargetObject) read by the activity (fimReadResource). A property we will be referring to later…

image

Now we are all set to implement the 2 code activities.

The first code activity will prepare the ReadResourceActivity that should read the TargetObject. This preparation consist of setting the ActorId as well as the ResourceId of the TargetObject. The code behind the first Code Activity is seen below:

private void prepareRead_ExecuteCode(object sender, EventArgs e)
{
//set actor
this.fimReadResource.ActorId = this.fimCurrentRequest_CurrentRequest.Creator.GetGuid();

//set resourceID
this.fimReadResource.ResourceId = this.fimCurrentRequest_CurrentRequest.Target.GetGuid();
}

Reading values from TargetObject (second CodeActivity)
When reading values from the targetobject, you need to know the system names of the attributes you are interested in as well as the data type. In this example, we will be looking for the value of “Cost Center”. As seen in the below screenshot, this attribute is of type Indexed String and the system name is CostCenter.


image


The last codeactivity – is using the below code snippet. As seen you can read explicit properties like ‘DisplayName’ etc, but also custom properties like Cost Center. As previously discussed you need to know the system Name as well as the data type to read this property.

Accessing properties on an object other than the immediate available, you get these like this:
<type> variable = <object>[<propertyName>]. Example see below for ‘CostCenter’.

private void writeOutResource_ExecuteCode(object sender, EventArgs e)
{
//read creator ID (of the TargetObject!)
Guid cId = this.fimReadResource_Resource.Creator.GetGuid();

//read displayName (of the TargetObject)
string disp = this.fimReadResource_Resource.DisplayName;

//read Manager of this person
Guid mgrId = (Guid)this.fimReadResource_Resource["Manager"];

//read name of Cost Center
string ccName = (string)this.fimReadResource_Resource["CostCenter"];

//Write out values...
Trace.WriteLine(string.Format("TargetID = {0}", cId.ToString()));
Trace.WriteLine(string.Format("DisplayName = {0}", disp));
Trace.WriteLine(string.Format("Manager (ID) = {0}", mgrId.ToString()));
Trace.WriteLine(string.Format("Cost Center = {0}", ccName));
}

Not all that intuitive I must admit!


StackOverflow Tags:

I screwed up my VS-settings severely!

I today killed my VS settings. But, luckily it is quite easy to revert to “install-state” in this way:

1) Tools – Import and Export Settings

2) You see the below dialog sequence

image

image

image

3) You are done!

StackOverflow Tags:

03 November, 2011

FIM 2010/WF: UpdateResourceActivity and While-iterations

I today struggled a great deal with a while-loop that gave me null-values when attempting to use the contained UpdateResourceActivity as seen below. Every time I entered the UpdateResourceActivity (‘fimUpdateGroup’) it kept complaining that some collection was null?

image

What’s happening?

Well – it turns out that if you execute a child-activity (as ‘updateSequence’ above) more than once, you actually gain a separate instance for each run!

From MSDN:
When a child activity is executed more than once, a separate instance of the activity is created for each iteration. This allows the instances to execute independently (and potentially in parallel, as in the case of a ReplicatorActivity activity). As a consequence, the definition of the child activity in the activity tree (referred to as the template) is never executed and is always in the Initialized state. Access to the running instances of the template is provided by the composite activity that is the parent of the template. For example, in the case of the WhileActivity activity, there is always one active instance, and the DynamicActivity property retrieves this instance.

So – where does this leave us?
In the above scenario – you can the correct instance in this way:

private void prepare_GroupUpdate(object sender, EventArgs e)
{
Logger.DebugWriteEnter();

//VERY IMPORTANT!: grap hold of the proper fimUpdateGroup INSTANCE!!
var seqParent = (SequenceActivity)this.whileTrue.DynamicActivity;
UpdateResourceActivity currentUpdateActivityInstance = (UpdateResourceActivity)seqParent.Activities.OfType<UpdateResourceActivity>().First(); //only 1!
Logger.DebugAssert(currentUpdateActivityInstance != null, "currentUpdateActivityInstance == null");

//add accounts
var upLst = new List<UpdateRequestParameter>();
this.accountLst.ForEach(x => upLst.Add(new UpdateRequestParameter("ExplicitMember", UpdateMode.Insert, x)));
Logger.DebugWrite("Adding '{0}' accounts to updatelist", upLst.Count);

//set values on this INSTANCE!
currentUpdateActivityInstance.UpdateParameters = upLst.ToArray();
currentUpdateActivityInstance.ActorId = this.ActorId;
currentUpdateActivityInstance.ResourceId = this.groupObjectLst[this.currentIndex].ObjectID;
Logger.DebugWrite("\tCurrent Resource to update: '{0}'", currentUpdateActivityInstance.ResourceId);

Logger.DebugWriteLeave();
}

So – there you have it. To make this scenario work (with a While-loop); you need to use the <parent>.DynamicActivity property on the parent activity to gain proper access.


Who should have known ;-)


StackOverflow Tags: ,

iPhone/XCode - not all cases are equal!

This bit me! Having made some changes to an iPhone application (Obj-C); everything worked fine in the simulator. But, when deploying the s...