none
Why can't set a Variable<T> from an InArgument<T> inside of CacheMetadata?

    Question

  • I want to set the defaults for the my arguments and variables the way I see fit. But, this throws an exception. Why?

     

    using System;
    using System.Activities;
    using System.Linq.Expressions;
    
    namespace ConsoleApplication5
    {
     class Program
     {
     static void Main(string[] args)
     {
      var wf = new Foo()
      {
      };
    
      WorkflowInvoker.Invoke(wf);
     }
     }
    
     public class Foo : NativeActivity
     {
     public InArgument<int> __in { get; set; }
     public OutArgument<int> __out { get; set; }
    
     public Variable<int> __var { get; set; }
    
     protected override void CacheMetadata(NativeActivityMetadata metadata)
     {
      //provide defaults in this way -> out and variable are equal to in.
      __in = new InArgument<int>(10);
      __var = new Variable<int>(context => __in.Get(context));
      __out = new OutArgument<int>(context => __in.Get(context));
    
      var rout = new RuntimeArgument("__out", typeof(int), ArgumentDirection.Out);
      metadata.Bind(__out, rout);
    
      var rin = new RuntimeArgument("__in", typeof(int), ArgumentDirection.In);
      metadata.Bind(__in, rin);
    
      metadata.AddImplementationVariable(__var);
      metadata.AddArgument(rin);
      metadata.AddArgument(rout);
    
     }
    
     protected override void Execute(NativeActivityContext context)
     {
    
     }
     }
    
    }
    

     

    The exception is:

    System.Activities.InvalidWorkflowException was unhandled

      Message=The following errors were encountered while processing the workflow tree:

    'Foo': The private implementation of activity '1: Foo' has the following validation error:   An error occurred while attempting to extract the target object of type 'System.Activities.InArgument`1[System.Int32]' from the method call expression '1: Foo.__in.Get(context)'.  Note that the expression determining the object of type 'System.Activities.InArgument`1[System.Int32]' must not require the runtime context.  Error: The sub-expression for the object of type 'System.Activities.InArgument`1[System.Int32]' resulted in a location reference that is not visible at this scope.

    'LambdaReference<Int32>': An error occurred while attempting to extract the target object of type 'System.Activities.InArgument`1[System.Int32]' from the method call expression '1: Foo.__in.Get(context)'.  Note that the expression determining the object of type 'System.Activities.InArgument`1[System.Int32]' must not require the runtime context.  Error: The sub-expression for the object of type 'System.Activities.InArgument`1[System.Int32]' resulted in a location reference that is not visible at this scope.

    'LambdaReference<Int32>': Invalid L-value expression.

      Source=System.Activities

      StackTrace:

           at System.Activities.Validation.ActivityValidationServices.ThrowIfViolationsExist(IList`1 validationErrors)

           at System.Activities.Hosting.WorkflowInstance.ValidateWorkflow(WorkflowInstanceExtensionManager extensionManager)

           at System.Activities.Hosting.WorkflowInstance.RegisterExtensionManager(WorkflowInstanceExtensionManager extensionManager)

           at System.Activities.WorkflowApplication.EnsureInitialized()

           at System.Activities.WorkflowApplication.RunInstance(WorkflowApplication instance)

           at System.Activities.WorkflowApplication.Invoke(Activity activity, IDictionary`2 inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout)

           at System.Activities.WorkflowInvoker.Invoke(Activity workflow, TimeSpan timeout, WorkflowInstanceExtensionManager extensions)

           at System.Activities.WorkflowInvoker.Invoke(Activity workflow)

           at ConsoleApplication5.Program.Main(String[] args) in C:\Documents and Settings\Administrator\Desktop\ConsoleApplication2\ConsoleApplication2\Program.cs:line 15

           at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)

           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)

           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)

           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)

           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

           at System.Threading.ThreadHelper.ThreadStart()

      InnerException: 


     

    Tuesday, September 07, 2010 5:37 AM

Answers

  • Hi,

    You can wirte you code in this way:

      public class Foo : NativeActivity {
            private InArgument<int> _in;
            public InArgument<int> __in {
                get {
                    return this._in;
                }
                set{
                    this._in = 10;
                }
            }
            public OutArgument<int> __out { getset; }      
            protected override void CacheMetadata(NativeActivityMetadata metadata) {
                var rin = new RuntimeArgument("__in"typeof(int), ArgumentDirection.In);
                metadata.Bind(__in, rin);
                var rout = new RuntimeArgument("__out"typeof(int), ArgumentDirection.Out);
                metadata.Bind(__out, rout);
                metadata.AddArgument(rin);
                metadata.AddArgument(rout);
            }

            protected override void Execute(NativeActivityContext context) {
                __out.Set(context,__in.Get(context));
            }
        }

    Variables are used for sharing data between activities not for sharing data inside an activity. so it is no need here.

    ->"  __in = new InArgument<int>(10);
      __var = new Variable<int>(context => __in.Get(context));
      __out = new OutArgument<int>(context => __in.Get(context));
    "
    you cannot get the value of InArgument /OutArgument from context before you register those arguments and Variables into context.

    Please note that if you set the default value of InArgument like this:
            private InArgument<int> _in;
            public InArgument<int> __in {
                get {
                    return this._in;
                }
                set{
                    this._in = 10;
                }
            }

    You will not be able to change its value in the workflow instance.

    For more about WF4 data model, please see this article:
    http://blogs.msdn.com/b/flow/archive/2010/04/06/workflow-foundation-4-0-activity-data-model-ii.aspx

    If you want to create workflow in c# code, this link could be helpful:
    http://xhinker.com/post/WF4Authoring-WF4-using-imperative-code(II).aspx

    Hope it helps
    Regards

     


    This posting is provided "AS IS" with no warranties, and confers no rights. Microsoft Online Community Support. My Blog:http://xhinker.com
    Thursday, September 09, 2010 8:03 AM
    Moderator

All replies

  • Hi Josh,

    All you'r looking for can't be code in CacheMetadata. it isn't the job of Metadata.

    To do it you will have to instanicate your items in constructor :

    public Foo()
    {
     // ... code here
    }
    

    Jérémy Jeanson MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    • Proposed as answer by JeremyJeansonMVP Tuesday, September 07, 2010 7:42 AM
    • Unproposed as answer by Josh Stefelgat Tuesday, September 07, 2010 2:28 PM
    Tuesday, September 07, 2010 7:41 AM
  • Thanks for the response, but it does not work in the constructor either! Same exception.
    Tuesday, September 07, 2010 2:28 PM
  • Could you post here your code?


    Jérémy Jeanson MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    Tuesday, September 07, 2010 3:00 PM
  • I am not sure I follow. The entire code is in the post above. I moved the first 3 lines from the CacheMetdata into the constructor and ran it. I still get the same exception. Do you *not* get the same exception when you run it when you put the code in the constructor? Thanks.
    Wednesday, September 08, 2010 12:15 AM
  • Any one? Please... MSFT folks?
    Thursday, September 09, 2010 3:30 AM
  • The exception says that you cannot use ActivityContext in the expression for __var:

    __var = new Variable<int>(context => __in.Get(context));

    Josh, if you need to assign a default value to __in, you can simply write:

    this.__in = new InArgument<int>(ctx => 10);
    

    And if you want __var to hold the value of __in during execution, you need to assign the value of __in to __var in the Execute() method:

    this.__var.Set(context, this.__in.Get(context));
    Thursday, September 09, 2010 7:21 AM
  • Hi,

    You can wirte you code in this way:

      public class Foo : NativeActivity {
            private InArgument<int> _in;
            public InArgument<int> __in {
                get {
                    return this._in;
                }
                set{
                    this._in = 10;
                }
            }
            public OutArgument<int> __out { getset; }      
            protected override void CacheMetadata(NativeActivityMetadata metadata) {
                var rin = new RuntimeArgument("__in"typeof(int), ArgumentDirection.In);
                metadata.Bind(__in, rin);
                var rout = new RuntimeArgument("__out"typeof(int), ArgumentDirection.Out);
                metadata.Bind(__out, rout);
                metadata.AddArgument(rin);
                metadata.AddArgument(rout);
            }

            protected override void Execute(NativeActivityContext context) {
                __out.Set(context,__in.Get(context));
            }
        }

    Variables are used for sharing data between activities not for sharing data inside an activity. so it is no need here.

    ->"  __in = new InArgument<int>(10);
      __var = new Variable<int>(context => __in.Get(context));
      __out = new OutArgument<int>(context => __in.Get(context));
    "
    you cannot get the value of InArgument /OutArgument from context before you register those arguments and Variables into context.

    Please note that if you set the default value of InArgument like this:
            private InArgument<int> _in;
            public InArgument<int> __in {
                get {
                    return this._in;
                }
                set{
                    this._in = 10;
                }
            }

    You will not be able to change its value in the workflow instance.

    For more about WF4 data model, please see this article:
    http://blogs.msdn.com/b/flow/archive/2010/04/06/workflow-foundation-4-0-activity-data-model-ii.aspx

    If you want to create workflow in c# code, this link could be helpful:
    http://xhinker.com/post/WF4Authoring-WF4-using-imperative-code(II).aspx

    Hope it helps
    Regards

     


    This posting is provided "AS IS" with no warranties, and confers no rights. Microsoft Online Community Support. My Blog:http://xhinker.com
    Thursday, September 09, 2010 8:03 AM
    Moderator