Custom Approval Workflow - No rejection code ?
I am currently writing a custom authorization workflow to match users based on an XPath expression. If there is a "potential" match I want an approver to either approve the match (This part is working fine) or Reject the match - in which case I would like to create the user with a new ID. The problem I have is when the request is rejected it seem to end all workflow activity. Is there a way to check if the request was approved or rejected ? Thanks Phil
June 10th, 2010 10:02am

Hi Phil! Unfortunately I think a rejected approval simply cancels the workflow with the IsApproved property set to false and I don't think there is a way to stop it but I'm not sure. If the approval activity instead throws an exception you'll probably be able to catch it (there is a standard FaultHandler activitiy for this... http://msdn.microsoft.com/en-us/magazine/dd419656.aspx ) and read the IsApproved and RejectedReason properties on the ApprovalActivity . My recommendation is that you debug your WF and try to find out if it's throwing an exception or not... And please let my now because I know others that be helped if this is a fact. //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
June 10th, 2010 4:36pm

I know we (Joe) built a RejectRequest activity that simply throws an exception with your provided text. This always had the effect of stopping the process completely. Back in RC0 timeframe when we built this it was not possible to capture or do anything with the fault since that handler didn't seem to be implemented if I recall correctly. We had plans to build a fault management system for our workflow, but it simply wasn't possible, not sure about with RTM.Brad Turner, ILM MVP - Ensynch, Inc - www.identitychaos.com
June 10th, 2010 11:42pm

The way you normally implement an AuthZ activity is that you throw an exception on failed validation or approval but the out of the box approval activity instead seems to kill the whole workflow silently by canceling it (I'm still not 100% sure about this but Brad's comment made me believe this is actually the truth) and that makes it impossible to like in the example above make use of a rejected approval and turn it into something else that I've seen a couple of questions about recenty. I'll take this issue with me and I'll try to find a solution, there is a risk though that a rejection can't be captured just like back in the RC0 days which will force us to create a custom approval activity to solve this or hope the activity is rewritten to throw an exception instead of a silent cancellation of the workflow... //HenrikHenrik 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
June 11th, 2010 1:01am

Thanks Henrik and brad but I think I might be out of luck. It looks like the ApprovalActivity workflow component has a final Terminate Activity (See Image Below). So I guess I will need to write my own approval activty. Unless someone else ou there can think of a better way ???? Please ...
June 11th, 2010 9:32am

OK after a lot of stuffing around trying to find a way to do this, and determining that createing my own approval activity is way to hard. I finally found a way to do it. And as always it only takes one line of code. Basically what you need to do is disable the Terminate activity depicted in the image from my last response. To do this, within the InitializeComponent method of your Activity after the creation of the approvalactivity add the flowing line; this.<yourapprovalactivityname>.GetActivityByName("terminateRejectedRequest").Enabled = false; For example; // // ApproveMe // this.ApproveMe.ApprovalCompleteEmailTemplate = new System.Guid("17da025f-496f-4be6-bcce-34e2bccffbed"); .. .. .. this.ApproveMe.SetValue(System.Workflow.Activities.ReceiveActivity.WorkflowServiceAttributesProperty, workflowserviceattributes1); this.ApproveMe.GetActivityByName("terminateRejectedRequest").Enabled = false;
Free Windows Admin Tool Kit Click here and download it now
June 17th, 2010 6:49am

Thanks Phil! Great research, this will probably help a lot other implementer out there! Personally I think this should be an option (property) on the approval activity that believe it or not is supported for use within your own activities/workflows since it's not marked "This API is for FIM internal use and is currently not supported." or "This API supports the FIM 2010 infrastructure and is not intended to be used directly from your code." like the EmailNotificationActivity, FunctionActivity and ResolveGrammarActivity. //HenrikHenrik Nilsson, ILM/FIM MVP Blog: http://www.idmcrisis.com Company: Cortego (http://www.cortego.se)
June 20th, 2010 9:45am

hi Phil, sorry to dig up this subject, but I'm not able to reproduce your solution. Can you please be more specific on where you have put your code to disable the termination activity please ? Thank you beforehand, JF
Free Windows Admin Tool Kit Click here and download it now
November 14th, 2011 6:09pm

Jean-François, Lets say your workflow is called ApproveMe so in Visual Studio expand the ApproveMe.cs file and there should be na ApproveMe.Designer.cs. Open the source for that and locate the section relating to your approval node (Lets say ApproveUser) it should look something like this; // // ApproveUser // this.ApproveUser..ApprovalCompleteEmailTemplate = new System.Guid("17da025f-496f-4be6-bcce-34e2bccffbed"); this........ ..... ... this.ApproveUser.GetActivityByName("terminateRejectedRequest").Enabled = false; <-- Insert this bit at the end Hope this helps Phil
November 14th, 2011 8:37pm

Hi Phil, Thanks, it helps me to locate where to add the part of code. But when adding this piece, I got an error when building. I took the same taxinomy as you : Could not create activity of type 'FIM.CustomWorkflowsActivitiesLibrary.ApproveMe'. System.NullReferenceException : Object reference us not set to an instance of an object at FIM.CustomWorkflowsActivitiesLibrary.ApproveMe.InitializeComponent() at FIM.CustomWorkflowsActivitiesLibrary.ApproveMe..ctor() I think the .GetActivityByName(".........") method can not be called because the object is not fully instanciated. Did you encounter such an error previously ? JF
Free Windows Admin Tool Kit Click here and download it now
November 15th, 2011 5:15am

Hello Phil, To ensure that I fully understand, here is my code : using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Collections; using System.Drawing; using System.Reflection; using System.Workflow.ComponentModel; using System.Workflow.ComponentModel.Design; using System.Workflow.ComponentModel.Compiler; using System.Workflow.ComponentModel.Serialization; using System.Workflow.Runtime; using System.Workflow.Activities; using System.Workflow.Activities.Rules; namespace FIM.CustomWorkflowActivitiesLibrary.Activities { public partial class RequestLoggingActivity3 { #region Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> [System.Diagnostics.DebuggerNonUserCode] private void InitializeComponent() { this.CanModifyActivities = true; System.Workflow.Activities.Rules.RuleConditionReference ruleconditionreference1 = new System.Workflow.Activities.Rules.RuleConditionReference(); System.Workflow.ComponentModel.ActivityBind activitybind1 = new System.Workflow.ComponentModel.ActivityBind(); System.Workflow.ComponentModel.ActivityBind activitybind2 = new System.Workflow.ComponentModel.ActivityBind(); System.Workflow.ComponentModel.ActivityBind activitybind3 = new System.Workflow.ComponentModel.ActivityBind(); System.Workflow.ComponentModel.ActivityBind activitybind4 = new System.Workflow.ComponentModel.ActivityBind(); System.Workflow.Activities.WorkflowServiceAttributes workflowserviceattributes1 = new System.Workflow.Activities.WorkflowServiceAttributes(); this.BBApprovalWF_ErrorHandler_Code = new System.Workflow.Activities.CodeActivity(); this.BBApprovalRejected = new System.Workflow.Activities.CodeActivity(); this.BBApprovalWF_Code = new System.Workflow.Activities.CodeActivity(); this.BBApprovalWF_ErrorHandler = new System.Workflow.ComponentModel.FaultHandlerActivity(); this.ifElseBranchActivity2 = new System.Workflow.Activities.IfElseBranchActivity(); this.ifElseBranchActivity1 = new System.Workflow.Activities.IfElseBranchActivity(); this.faultHandlersActivity2 = new System.Workflow.ComponentModel.FaultHandlersActivity(); this.ifElseActivity1 = new System.Workflow.Activities.IfElseActivity(); this.BBApprovalWF = new Microsoft.ResourceManagement.Workflow.Activities.ApprovalActivity(); this.RSAPreparationForApproval = new System.Workflow.Activities.CodeActivity(); this.faultHandlersActivity1 = new System.Workflow.ComponentModel.FaultHandlersActivity(); this.UpdateBBValuesAfterApproval = new Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity(); this.BBPostApproval_PreCode = new System.Workflow.Activities.CodeActivity(); this.sequenceActivity3 = new System.Workflow.Activities.SequenceActivity(); this.BBPreparationForApproval = new System.Workflow.Activities.CodeActivity(); this.sequenceActivity2 = new System.Workflow.Activities.SequenceActivity(); this.sequenceActivity1 = new System.Workflow.Activities.SequenceActivity(); this.terminateActivityWhenRejected = new System.Workflow.ComponentModel.TerminateActivity(); this.FinalResultcontrol_PostCode = new System.Workflow.Activities.CodeActivity(); this.readResultControl = new Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity(); this.FinalResultControl_PreCode = new System.Workflow.Activities.CodeActivity(); this.parallelActivity1 = new System.Workflow.Activities.ParallelActivity(); this.LectureObjet = new System.Workflow.Activities.CodeActivity(); this.readResourceActivity = new Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity(); this.LectureAttributs = new System.Workflow.Activities.CodeActivity(); this.ReadcurrentRequestActivity = new Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity(); // // BBApprovalWF_ErrorHandler_Code // this.BBApprovalWF_ErrorHandler_Code.Name = "BBApprovalWF_ErrorHandler_Code"; this.BBApprovalWF_ErrorHandler_Code.ExecuteCode += new System.EventHandler(this.BBApprovalWF_ErrorHandler_Code_ExecuteCode); // // BBApprovalRejected // this.BBApprovalRejected.Name = "BBApprovalRejected"; this.BBApprovalRejected.ExecuteCode += new System.EventHandler(this.BBApprovalWF_ErrorHandler_Code_ExecuteCode); // // BBApprovalWF_Code // this.BBApprovalWF_Code.Name = "BBApprovalWF_Code"; this.BBApprovalWF_Code.ExecuteCode += new System.EventHandler(this.BBApprovalWF_Code_ExecuteCode); // // BBApprovalWF_ErrorHandler // this.BBApprovalWF_ErrorHandler.Activities.Add(this.BBApprovalWF_ErrorHandler_Code); this.BBApprovalWF_ErrorHandler.FaultType = typeof(Microsoft.ResourceManagement.WebServices.Client.PermissionDeniedException); this.BBApprovalWF_ErrorHandler.Name = "BBApprovalWF_ErrorHandler"; // // ifElseBranchActivity2 // this.ifElseBranchActivity2.Activities.Add(this.BBApprovalRejected); this.ifElseBranchActivity2.Name = "ifElseBranchActivity2"; // // ifElseBranchActivity1 // this.ifElseBranchActivity1.Activities.Add(this.BBApprovalWF_Code); ruleconditionreference1.ConditionName = "BBApproval"; this.ifElseBranchActivity1.Condition = ruleconditionreference1; this.ifElseBranchActivity1.Name = "ifElseBranchActivity1"; // // faultHandlersActivity2 // this.faultHandlersActivity2.Activities.Add(this.BBApprovalWF_ErrorHandler); this.faultHandlersActivity2.Name = "faultHandlersActivity2"; // // ifElseActivity1 // this.ifElseActivity1.Activities.Add(this.ifElseBranchActivity1); this.ifElseActivity1.Activities.Add(this.ifElseBranchActivity2); this.ifElseActivity1.Name = "ifElseActivity1"; // // BBApprovalWF // this.BBApprovalWF.ApprovalCompleteEmailTemplate = new System.Guid("17da025f-496f-4be6-bcce-34e2bccffbed"); this.BBApprovalWF.ApprovalDeniedEmailTemplate = new System.Guid("3357265f-277a-4acc-8f90-7fed4da4406e"); this.BBApprovalWF.ApprovalEmailTemplate = new System.Guid("c89dcabb-5ddc-41fa-aea2-9643b269f537"); this.BBApprovalWF.ApprovalObject = null; this.BBApprovalWF.ApprovalObjectId = new System.Guid("00000000-0000-0000-0000-000000000000"); this.BBApprovalWF.ApprovalResponseCreateParameters = null; this.BBApprovalWF.ApprovalTimeoutEmailTemplate = new System.Guid("ff3346be-ecbd-47a8-ba08-a0f095a1b38a"); this.BBApprovalWF.ApproverId = new System.Guid("00000000-0000-0000-0000-000000000000"); this.BBApprovalWF.Approvers = "4ebac550-57e0-48c4-83c2-e3183bd364a1;"; this.BBApprovalWF.AutomatedResponseObjectId = new System.Guid("00000000-0000-0000-0000-000000000000"); this.BBApprovalWF.CurrentApprovalResponse = null; this.BBApprovalWF.CurrentApprovalResponseActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); this.BBApprovalWF.Duration = System.TimeSpan.Parse("7.00:00:00"); this.BBApprovalWF.Escalation = null; this.BBApprovalWF.EscalationEmailTemplate = new System.Guid("33bdd279-9116-4d0e-97b3-11b753efd509"); this.BBApprovalWF.IsApproved = null; this.BBApprovalWF.Name = "BBApprovalWF"; this.BBApprovalWF.ReceivedApprovals = 0; this.BBApprovalWF.RejectedReason = null; this.BBApprovalWF.Request = null; this.BBApprovalWF.RequestTimedOut = false; this.BBApprovalWF.Threshold = 1; this.BBApprovalWF.GetActivityByName("terminateActivityWhenRejected").Enabled = false; // // RSAPreparationForApproval // this.RSAPreparationForApproval.Name = "RSAPreparationForApproval"; this.RSAPreparationForApproval.ExecuteCode += new System.EventHandler(this.RSAPreparationForApproval_ExecuteCode); // // faultHandlersActivity1 // this.faultHandlersActivity1.Name = "faultHandlersActivity1"; // // UpdateBBValuesAfterApproval // this.UpdateBBValuesAfterApproval.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); this.UpdateBBValuesAfterApproval.Name = "UpdateBBValuesAfterApproval"; this.UpdateBBValuesAfterApproval.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); this.UpdateBBValuesAfterApproval.UpdateParameters = null; // // BBPostApproval_PreCode // this.BBPostApproval_PreCode.Name = "BBPostApproval_PreCode"; this.BBPostApproval_PreCode.ExecuteCode += new System.EventHandler(this.BBPostApproval_PreCode_ExecuteCode); // // sequenceActivity3 // this.sequenceActivity3.Activities.Add(this.BBApprovalWF); this.sequenceActivity3.Activities.Add(this.ifElseActivity1); this.sequenceActivity3.Activities.Add(this.faultHandlersActivity2); this.sequenceActivity3.Name = "sequenceActivity3"; // // BBPreparationForApproval // this.BBPreparationForApproval.Name = "BBPreparationForApproval"; this.BBPreparationForApproval.ExecuteCode += new System.EventHandler(this.BBPreparationForApproval_ExecuteCode); // // sequenceActivity2 // this.sequenceActivity2.Activities.Add(this.RSAPreparationForApproval); this.sequenceActivity2.Name = "sequenceActivity2"; // // sequenceActivity1 // this.sequenceActivity1.Activities.Add(this.BBPreparationForApproval); this.sequenceActivity1.Activities.Add(this.sequenceActivity3); this.sequenceActivity1.Activities.Add(this.BBPostApproval_PreCode); this.sequenceActivity1.Activities.Add(this.UpdateBBValuesAfterApproval); this.sequenceActivity1.Activities.Add(this.faultHandlersActivity1); this.sequenceActivity1.Name = "sequenceActivity1"; // // terminateActivityWhenRejected // Terminate Activity this.terminateActivityWhenRejected.Name = "terminateActivityWhenRejected"; // // FinalResultcontrol_PostCode // this.FinalResultcontrol_PostCode.Name = "FinalResultcontrol_PostCode"; this.FinalResultcontrol_PostCode.ExecuteCode += new System.EventHandler(this.FinalResultcontrol_PostCode_ExecuteCode); // // readResultControl // this.readResultControl.ActorId = new System.Guid("00000000-0000-0000-0000-000000000000"); this.readResultControl.Name = "readResultControl"; this.readResultControl.Resource = null; this.readResultControl.ResourceId = new System.Guid("00000000-0000-0000-0000-000000000000"); this.readResultControl.SelectionAttributes = null; // // FinalResultControl_PreCode // this.FinalResultControl_PreCode.Name = "FinalResultControl_PreCode"; this.FinalResultControl_PreCode.ExecuteCode += new System.EventHandler(this.FinalResultControl_PreCode_ExecuteCode); // // parallelActivity1 // this.parallelActivity1.Activities.Add(this.sequenceActivity1); this.parallelActivity1.Activities.Add(this.sequenceActivity2); this.parallelActivity1.Name = "parallelActivity1"; // // LectureObjet // this.LectureObjet.Name = "LectureObjet"; this.LectureObjet.ExecuteCode += new System.EventHandler(this.LectureObjet_ExecuteCode); // // readResourceActivity // activitybind1.Name = "RequestLoggingActivity3"; activitybind1.Path = "readResourceActivity_ActorId"; this.readResourceActivity.Name = "readResourceActivity"; activitybind2.Name = "RequestLoggingActivity3"; activitybind2.Path = "readResourceActivity_Resource"; activitybind3.Name = "RequestLoggingActivity3"; activitybind3.Path = "readResourceActivity_ResourceId"; this.readResourceActivity.SelectionAttributes = null; this.readResourceActivity.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ResourceProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind2))); this.readResourceActivity.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ActorIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind1))); this.readResourceActivity.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity.ResourceIdProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind3))); // // LectureAttributs // this.LectureAttributs.Name = "LectureAttributs"; this.LectureAttributs.ExecuteCode += new System.EventHandler(this.LectureAttributs_ExecuteCode); // // ReadcurrentRequestActivity // activitybind4.Name = "RequestLoggingActivity3"; activitybind4.Path = "ReadCurrentRequestActivity_CurrentRequest"; this.ReadcurrentRequestActivity.Name = "ReadcurrentRequestActivity"; this.ReadcurrentRequestActivity.SetBinding(Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity.CurrentRequestProperty, ((System.Workflow.ComponentModel.ActivityBind)(activitybind4))); workflowserviceattributes1.ConfigurationName = "FIM.CustomWorkflowActivitiesLibrary.Activities.RequestLoggingActivity3"; workflowserviceattributes1.Name = "RequestLoggingActivity3"; // // RequestLoggingActivity3 // this.Activities.Add(this.ReadcurrentRequestActivity); this.Activities.Add(this.LectureAttributs); this.Activities.Add(this.readResourceActivity); this.Activities.Add(this.LectureObjet); this.Activities.Add(this.parallelActivity1); this.Activities.Add(this.FinalResultControl_PreCode); this.Activities.Add(this.readResultControl); this.Activities.Add(this.FinalResultcontrol_PostCode); this.Activities.Add(this.terminateActivityWhenRejected); this.Name = "RequestLoggingActivity3"; this.SetValue(System.Workflow.Activities.ReceiveActivity.WorkflowServiceAttributesProperty, workflowserviceattributes1); this.CanModifyActivities = false; } #endregion private TerminateActivity terminateActivityWhenRejected; private CodeActivity BBApprovalRejected; private IfElseBranchActivity ifElseBranchActivity2; private IfElseBranchActivity ifElseBranchActivity1; private IfElseActivity ifElseActivity1; private CodeActivity RSAPreparationForApproval; private CodeActivity FinalResultControl_PreCode; private CodeActivity FinalResultcontrol_PostCode; private Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity readResultControl; private CodeActivity BBPreparationForApproval; private Microsoft.ResourceManagement.Workflow.Activities.UpdateResourceActivity UpdateBBValuesAfterApproval; private CodeActivity BBPostApproval_PreCode; private FaultHandlerActivity BBApprovalWF_ErrorHandler; private FaultHandlersActivity faultHandlersActivity2; private SequenceActivity sequenceActivity3; private CodeActivity BBApprovalWF_ErrorHandler_Code; private CodeActivity BBApprovalWF_Code; private Microsoft.ResourceManagement.Workflow.Activities.ApprovalActivity BBApprovalWF; private SequenceActivity sequenceActivity2; private SequenceActivity sequenceActivity1; private ParallelActivity parallelActivity1; private FaultHandlersActivity faultHandlersActivity1; private CodeActivity LectureObjet; private Microsoft.ResourceManagement.Workflow.Activities.ReadResourceActivity readResourceActivity; private CodeActivity LectureAttributs; private Microsoft.ResourceManagement.Workflow.Activities.CurrentRequestActivity ReadcurrentRequestActivity; } } thank you for your help on this Regards, JF
November 15th, 2011 5:31am

Hello, Just for the follow-up setting of the Terminate Activity is, from my point of view, not possible. What is enforcing this fact is that the Terminate Exception that is received by the Approval Activity cannot be catched and ends in the termination of the MPR that bring the workflow. One solution possible, whcih I developped and tested, is to process rejected ApprovalResponse and run actions upon it. It needs a dedicated MPR and to implement : - the proper filtering to process only rejected ApprovalResponse that are interesting in the context. - the chain of resource readings needed to retrieve enough information to feed the action activity. If someone interessted in further information, contact me. Regards
Free Windows Admin Tool Kit Click here and download it now
December 14th, 2011 1:06pm

Hello, Just for the follow-up setting of the Terminate Activity is, from my point of view, not possible. What is enforcing this fact is that the Terminate Exception that is received by the Approval Activity cannot be catched and ends in the termination of the MPR that bring the workflow. One solution possible, whcih I developped and tested, is to process rejected ApprovalResponse and run actions upon it. It needs a dedicated MPR and to implement : - the proper filtering to process only rejected ApprovalResponse that are interesting in the context. - the chain of resource readings needed to retrieve enough information to feed the action activity. If someone interessted in further information, contact me. Regards
December 14th, 2011 1:06pm

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

Other recent topics Other recent topics