Search code examples
workflow-foundation-4workflow-foundationworkflow-activity

WF 4 OnUnhandledException not hit


I've created a custom activity which contains as a Body another Activity.

    [Browsable(false)]
    public Activity Body { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
    }

    private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
    {
        throw new Exception(propagatedException.Message);
    }

When an exception is thrown during the execution of the Body, ma handler for the OnFaulted is hit.

My execution starts with a call to static method Run of the WorkflowApplication class. My WorkflowApplication instance has a handler associated for the OnUnhandledException event.

 instance.OnUnhandledException +=
                       delegate(WorkflowApplicationUnhandledExceptionEventArgs args)
                    {
                        Console.WriteLine(args.ExceptionSource);
                        waitEvent.Set();
                        return UnhandledExceptionAction.Cancel;
                    };

But regardless of what happens when the Activity hosted in the Body is executed, i never reach the handler defined above. I thought that if i throw an exception from the OnFaulted, i will be able to redirect the flow to the OnUnhandledException but i was wrong. Any ideas ?

I need this in order to centralize my errors, check them and display messages accordingly. Also i need a way to stop the execution and so on and i don't want to define handlers all over the application. Is there any way to accomplish this ?


Solution

  • As Will suggested, i will post what i did to handle my scenario.

    Basically, in my custom activity i have hosted an Assign :

        [Browsable(false)]
        public Activity Body { get; set; }
    
        Activity System.Activities.Presentation.IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
        {
            return new Assignment()
            {
                Body = new Assign() { DisplayName = "" }
            };
        }
    

    I've added this code to my Execute method :

    ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
    

    I was trying to run this Assignment by giving an array a negative value as index and and an exception was thrown. This, somehow ended my execution but no handler for the events of my WorkflowApplication instance were hit.

    Here is the method given as a callback when executing the body ( in our case the Assign activity ) :

        private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
        {
            faultContext.HandleFault();
            CommunicationExtension ce = faultContext.GetExtension<CommunicationExtension>();
    
            ITextExpression toTextExpression = (propagatedFrom.Activity as Assign).To.Expression as ITextExpression;
    
            string valueTextExpression = string.Empty;
            if ((propagatedFrom.Activity as Assign).Value != null)
            {
                if ((propagatedFrom.Activity as Assign).Value.Expression != null)
                    valueTextExpression = (propagatedFrom.Activity as Assign).Value.Expression.ToString();
            }
    
    
            if (ce != null)
            {
                ce.AddData(string.Format("{0} found on Assignment definition [{1} = {2}]", propagatedException.Message, toTextExpression.ExpressionText, valueTextExpression));
            }
        }
    

    The trick was to call :

     faultContext.HandleFault();
    

    and use CommunicationExtension to allow me to to display the erros in the GUI.

    The code for this class is trivial :

    public class CommunicationExtension
    {
    
        public List<string> Messages { get; set; }
    
        public CommunicationExtension()
        {
            Messages = new List<string>();
        }
    
        public void AddData(string message)
        {
            if (string.IsNullOrEmpty(message))
                return;
            Messages.Add(message);
        }
    }
    

    Use this to add the extension:

    CommunicationExtension ce = new CommunicationExtension();
    instance.Extensions.Add(ce);
    

    where instance is my WorkflowApplication instance.

    I understood that for each instance of the workflow application we have one instance of its extension class. So i can send messages like this from all my custom activities in order to display their status.

    I hope this scenario can help other people too.