Custom Workflow Unique AccountName accross the forest
Hi, following a previous thread, I'm trying to write a custom workflow that will verify that an AccountName is unique accross a forest. I've written a workflow that implements an enumerateResourcesActivity enumerator and I'm hitting the following issue: After about 30 loops, it stops and raises the error "CompositeActivity cannot transition to 'Closed' status when there are active child context still exist for child activity" I've used the EnsynchILMActivity sample as skeletton, added an EnumerateResourcesActivity and linked a CodeActivity: private void InitializeComponent() { [...] this.enumerateResourcesActivity1.XPathFilter = "/Person"; [...] this.Activities.Add(this.enumerateResourcesActivity1); this.enumerateResourcesActivity1.Activities.Add(this.codeActivity1); Here is the code activity callback function: private void VerifyUniqueNess(object sender, EventArgs e) { TargetID = this.currentRequest.Target.GetGuid(); bool isUnique= true; string accountName = string.Empty; ReadOnlyCollection<CreateRequestParameter> requestParameters = this.currentRequest.ParseParameters<CreateRequestParameter>(); foreach (CreateRequestParameter requestParameter in requestParameters) { if (requestParameter.PropertyName == "AccountName") { accountName = requestParameter.Value.ToString(); } } enumerateResourcesActivity1.Selection = new string[] { "AccountName" }; ResourceType resource = EnumerateResourcesActivity.GetCurrentIterationItem((CodeActivity)sender) as ResourceType; if (resource != null) { string fimAccountName = resource["AccountName"].ToString(); SimpleLogFunction("Comparaison", fimAccountName + " : " + accountName, EventLogEntryType.Information, 1000, 100); if (string.Compare(accountName, fimAccountName, true) == 0) { isUnique = false; SimpleLogFunction("Comparaison", "Attention duplicate : ", EventLogEntryType.Information, 1000, 100); } } //if ( isUnique == true) //{ // MyUpdateParameter = new UpdateRequestParameter[] // { // new UpdateRequestParameter("AccountNameIsUnique",UpdateMode.Modify,1) // }; //} } I'm getting the same problem if I comment / uncomment the last part of the code. Another question that comes to my mind: where can I initialize the XPathFilter of enumerateResourcesActivity1 to "/Person[accountName]" instead of "/Person". This way, I get the AccountName beeing created and can enumerate all objects having this AccountName. If it returns one entry, it means that I have a duplicate. Btw, this workflow is for inbound synchronization (users created through AD mmc coming into FIM). For accounts created with the portal, this definition in the RCDC for the attribute AccountName blocks duplicates: <my:Property my:Name="UniquenessValidationXPath" my:Value="/Person[AccountName='%VALUE%']" /> May I ask one more question? Another approach instead of setting the attribute AccountNameIsUnique through code would be to exit the enumerate loop if duplicate is found and return true or false. How can I modifiy this code to achieve this?Cordialement, Emmanuel Dreux http://www.bcpsoft.fr Formation FIM 2010
May 31st, 2011 11:51am

Hi Emmanuel! To start with I hope you're aware AuthN and AuthZ isn't executed on requests created by FimSync account) therefore the AccountName will already be set to the resource in FIM service when this is executed. I'm not sure why you get the error but you can define the... this.enumerateResourcesActivity1.XPathFilter = "/Person[AccountName = 'your Account Name']"; ...as long as the enumerateResourcesActivity1 hasn't been executed so my recommendation is that you add that right after you've extracted the AccountName being added in the VerifyUniquness method... foreach (CreateRequestParameter requestParameter in requestParameters) { if (requestParameter.PropertyName == "AccountName") { accountName = requestParameter.Value.ToString(); } }this.enumerateResourcesActivity1.XPathFilter = string.Format("/Person[AccountName ='{0}']", accountName) ...By doing so your enumerateRequestActivity1 wont return more than one Person resource if you've managed to get unique account names and your problem should probably be gone. A couple of recommendations: 1. Since your current resource has already been added to FIM when this activity is executed in an action workflow you can replace the CurrentRequest with a ReadResourceActivity instead and feed it the value of the Workflow. You get the workflow with these lines of code... SequentialWorkflow containingWorkflow; if (!SequentialWorkflow.TryGetContainingWorkflow(this, out containingWorkflow)) throw new InvalidOperationException("Unable to get Containing Workflow"); ...But I usually put it in a property (in a base class that could be inherited by all my activities but could of course be added to any activity) for having it available at all times... protected SequentialWorkflow ContainingWorkflow { get { SequentialWorkflow containingWorkflow; if (!SequentialWorkflow.TryGetContainingWorkflow(this, out containingWorkflow)) throw new InvalidOperationException("Unable to get Containing Workflow"); return containingWorkflow; } } ..From that you can then do... readResourceActivity1.ResourceId = ContainingWorkflow.TargetId; readResourceActivity1.SelectionAttributes= new string[]{"AccountName"}; ...for getting the account name of the resource currently being added. ResourceType resource = readResourceActivity1.Resource; string accountName = resource["AccountName"]; 2. before any activity is executed you can add the Execute handler that is useful for initiating activities when you need to do it in code... protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { // Your initialization code here! // Dont leave this line out! return base.Execute(executionContext); } 3. Since the resource is already added you should propably remove the current resource in you query otherwise you will have a least one hit when searching with the EnumerateResourceActivity each time so maybe your filter should be... this.enumerateResourcesActivity1.XPathFilter = string.Format("/Person[AccountName ='{0}' and not(ObjectID = '{1}')]", accountName, containingWorkflow.TargetId.ToString()); ...In order to only get any conflicting names... I hope this have helped you out. //Henrik Henrik Nilsson, ILM/FIM MVP Blog: http://www.idmcrisis.com Company: Cortego (http://www.cortego.se)
Free Windows Admin Tool Kit Click here and download it now
May 31st, 2011 12:55pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics