Search code examples
c#.networkflowworkflow-foundationworkflow-activity

Unable to access Dictionary using CSharpValue expression in WF 4.5


I have tried to create workflow using code as explained here. But I can't get through my result. I have created Console Application with Class1.cs containing my workflow code and Program.cs which the workflow is hosted in WorkflowApplication class including inputs. while executing the unhandled exception occurs with the message "Expression Activity type 'CSharpValue`1' requires compilation in order to run. Please ensure that the workflow has been compiled". But also I have included the method CompileExpressions for compiling, as said here. I appreciate in advance for your help!

ReverseStringWorkflow.cs

 public class ReverseStringWorkflow : Activity
    {
        public InArgument<Dictionary<string,object>> StringToReverse { get; set; } 

        protected override Func<Activity> Implementation
        {
            get
            {
                return () =>
                {
                    Sequence sequence = new Sequence
                    {
                        Activities =
                        {
                             new WriteLine
                             {
                                 Text = new CSharpValue<string>("StringToReverse[\"name\"].ToString()")

                             }
                        }
                    };
                    return sequence;
                };
            }
            set
            {
                base.Implementation = value;
            }

        }
    }

Program.cs

class Program
    {
        static void Main(string[] args)
        {
            Activity workflow2 = new ReverseStringWorkflow();
            Dictionary<string, object> mainInputs = new Dictionary<string, object>();
            Dictionary<string, object> subInputs = new Dictionary<string, object>();                
            subInputs.Add("name","name123");
            mainInputs.Add("StringToReverse", subInputs);
            WorkflowApplication app = new WorkflowApplication(workflow2, mainInputs);
            app.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
            {
                Console.WriteLine("Error occurred");
                return UnhandledExceptionAction.Terminate;
            };
            CompileExpressions(workflow2);

            app.Run();

            Console.ReadLine();
        }
        public static void CompileExpressions(Activity activity)
        {
            // activityName is the Namespace.Type of the activity that contains the
            // C# expressions.
            string activityName = activity.GetType().ToString();

            // Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
            // to represent the new type that represents the compiled expressions.
            // Take everything after the last . for the type name.
            string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
            // Take everything before the last . for the namespace.
            string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

            // Create a TextExpressionCompilerSettings.
            TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
            {
                Activity = activity,
                Language = "C#",
                ActivityName = activityType,
                ActivityNamespace = activityNamespace,
                RootNamespace = null,
                GenerateAsPartialClass = false,
                AlwaysGenerateSource = true,
                ForImplementation = false
            };

            // Compile the C# expression.
            TextExpressionCompilerResults results =
                new TextExpressionCompiler(settings).Compile();

            // Any compilation errors are contained in the CompilerMessages.
            if (results.HasErrors)
            {
                throw new Exception("Compilation failed.");
            }

            // Create an instance of the new compiled expression type.
            ICompiledExpressionRoot compiledExpressionRoot =
                Activator.CreateInstance(results.ResultType,
                    new object[] { activity }) as ICompiledExpressionRoot;

            // Attach it to the activity.
            CompiledExpressionInvoker.SetCompiledExpressionRoot(
                activity, compiledExpressionRoot);
        }
    }

Full Error Message:

[System.NotSupportedException]  {System.NotSupportedException: Expression Activity type 'CSharpValue`1' requires compilation in order to run.  Please ensure that the workflow has been compiled.
   at System.Activities.Expressions.CompiledExpressionInvoker.InvokeExpression(ActivityContext activityContext)
   at Microsoft.CSharp.Activities.CSharpValue`1.Execute(CodeActivityContext context)
   at System.Activities.CodeActivity`1.InternalExecuteInResolutionContext(CodeActivityContext context)
   at System.Activities.Runtime.ActivityExecutor.ExecuteInResolutionContext[T](ActivityInstance parentInstance, Activity`1 expressionActivity)
   at System.Activities.InArgument`1.TryPopulateValue(LocationEnvironment targetEnvironment, ActivityInstance activityInstance, ActivityExecutor executor)
   at System.Activities.RuntimeArgument.TryPopulateValue(LocationEnvironment targetEnvironment, ActivityInstance targetActivityInstance, ActivityExecutor executor, Object argumentValueOverride, Location resultLocation, Boolean skipFastPath)
   at System.Activities.ActivityInstance.InternalTryPopulateArgumentValueOrScheduleExpression(RuntimeArgument argument, Int32 nextArgumentIndex, ActivityExecutor executor, IDictionary`2 argumentValueOverrides, Location resultLocation, Boolean isDynamicUpdate)
   at System.Activities.ActivityInstance.ResolveArguments(ActivityExecutor executor, IDictionary`2 argumentValueOverrides, Location resultLocation, Int32 startIndex)
   at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)

Solution

  • Thank You Mr. Maciej Los. Finally I got the right approach from the article you referred, your reply was very helpful..

    Here is the answer if someone needs in future.

     static void Main(string[] args)
            {
                Dictionary<string, object> inputs = new Dictionary<string, object>();            
                inputs.Add("userName", "Test User");         
    
                // Using DynamicActivity for this sample so that we can have an
                // InArgument, and also do everything without XAML at all
                DynamicActivity codeWorkflow = new DynamicActivity();
                codeWorkflow.Name = "MyScenario.MyDynamicActivity";
                foreach (var key in inputs.Keys)
                {
                    DynamicActivityProperty property = new DynamicActivityProperty();
                    property.Name = key;
                    property.Type = typeof(InArgument<Dictionary<string,object>>);                
                    codeWorkflow.Properties.Add(property);
                }
                codeWorkflow.Implementation = () => new WriteLine
                {
                    Text = new CSharpValue<string>
                    {
                        ExpressionText = "\"hello ! \" + InArguments[\"userName\"].ToString()"
                    },
                };         
                Compile(codeWorkflow);
                WorkflowInvoker.Invoke(codeWorkflow,
                 new Dictionary<string, object>
                    {
                { "InArguments", inputs}
                    });
    
                Console.ReadLine(); 
            }
    

    And compile method is:

    static void Compile(DynamicActivity dynamicActivity)
            {
                TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
                {
                    Activity = dynamicActivity,
                    Language = "C#",
                    ActivityName = dynamicActivity.Name.Split('.').Last() + "_CompiledExpressionRoot",
                    ActivityNamespace = string.Join(".", dynamicActivity.Name.Split('.').Reverse().Skip(1).Reverse()),
                    RootNamespace = null,
                    GenerateAsPartialClass = false,
                    AlwaysGenerateSource = true,
                };
    
                TextExpressionCompilerResults results =
                    new TextExpressionCompiler(settings).Compile();
                if (results.HasErrors)
                {
                    throw new Exception("Compilation failed.");
                }
    
                ICompiledExpressionRoot compiledExpressionRoot =
                    Activator.CreateInstance(results.ResultType,
                        new object[] { dynamicActivity }) as ICompiledExpressionRoot;
                CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(
                    dynamicActivity, compiledExpressionRoot);
            }