locked
Access Context in CacheMetadata RRS feed

  • Question

  • Is it possible to get access to the context within the override of CacheMetaData. I need to add Arguments to a custom activity at runtime. So I created a scope activity "WorkflowScope" with a handle "WorkflowScopeHandle". In another activity "AddTodo" I can accee the handle from the context. But I woul need to access the handle/context in CacheMetadata, so I can add arguments dynmically.

    Source for WorkflowScope and WorkflowScopeHandle

    	[Designer(typeof(WorkflowScopeDesigner))]
    	[ContentProperty("Body")]
    	public sealed class WorkflowScope : NativeActivity
    	{
    
    		private Variable<WorkflowScopeHandle> workflowScopeHandle;
    
    		private Collection<TodoListMappingField> todoListMapping;
    		[Browsable(false)]
    		public Collection<TodoListMappingField> TodoListMapping
    		{
    			get
    			{
    				if (todoListMapping == null)
    					todoListMapping = new Collection<TodoListMappingField>();
    				return todoListMapping;
    			}
    			set { todoListMapping = value; }
    		}
    
    		private Collection<Variable> variables;
    		[Browsable(false)]
    		public Collection<Variable> Variables
    		{
    			get
    			{
    				if (this.variables == null)
    				{
    					this.variables = new Collection<Variable>();
    				}
    				return this.variables;
    			}
    		}
    
    				[Browsable(false)]
    		public Activity Body { get; set; }
    
    		public WorkflowScope()
    		{
    			this.workflowScopeHandle = new Variable<WorkflowScopeHandle>();
    		}
    
    		protected override void CacheMetadata(NativeActivityMetadata metadata)
    		{
    			base.CacheMetadata(metadata);
    			metadata.SetVariablesCollection(this.Variables);
    			metadata.AddImplementationVariable(this.workflowScopeHandle);
    
    		}
    
    		protected override void Execute(NativeActivityContext context)
    		{
    			if (this.Body != null)
    			{
    				if (TodoListMapping != null)
    				{
    					WorkflowScopeHandle handle = this.workflowScopeHandle.Get(context);
    					handle.Mapping = this.TodoListMapping;
    					context.Properties.Add(handle.ExecutionPropertyName, handle);
    				}
    				context.ScheduleActivity(this.Body);
    			}
    		}
    	}
    
    
    
    
    	public class WorkflowScopeHandle : Handle
    	{
    		public Collection<TodoListMappingField> Mapping { get; set; }
    	}
    
    

    Source for AddTodo:

    public sealed class AddTodo : CodeActivity<int>
    	{
    		
    		private Dictionary<string, InArgument> todoListFields;
    
    		[Editor(typeof(ArgumentDictionaryEditor), typeof(PropertyValueEditor))]
    		[Browsable(true)]
    		public IDictionary<string, InArgument> TodoListFields
    		{
    			get
    			{
    				if (this.todoListFields == null)
    				{
    					this.todoListFields = new Dictionary<string, InArgument>();
    				}
    				return this.todoListFields;
    			}
    		}
    
    		private Dictionary<string, InArgument> internalTodoListFields = new Dictionary<string,InArgument>();
    
    		
    		protected override void CacheMetadata(CodeActivityMetadata metadata)
    		{
    			Collection<RuntimeArgument> arguments = new Collection<RuntimeArgument>();
    
    					
    
    			// if we have the fields not on the activity itself
    			// get them from the Workflow Scope activity, and create the required runtime arguments
    			//
    			
    			if (this.TodoListFields.Count == 0)
    			{
    				WorkflowScope scope = metadata.Environment.Root as WorkflowScope; 
    
    				foreach (TodoListMappingField mf in scope.TodoListMapping)
    				{
    					Type argumentType = typeof(InArgument<>).MakeGenericType(typeof(string));
    					InArgument argument = (InArgument)Activator.CreateInstance(argumentType);
    					argument.Expression = new VisualBasicValue<string>(mf.ObjectPath);
    
    					RuntimeArgument ra = new RuntimeArgument(mf.DBFieldName, typeof(string), ArgumentDirection.In);
    					metadata.Bind(argument, ra);
    					arguments.Add(ra);
    
    					internalTodoListFields.Add(mf.DBFieldName, argument);
    				}
    			}
    			else
    			{
    				foreach (var field in TodoListFields)
    				{
    	
    					RuntimeArgument ra = new RuntimeArgument(field.Key, typeof(string), ArgumentDirection.In);
    					metadata.Bind(field.Value, ra);
    					arguments.Add(ra);
    
    					internalTodoListFields.Add(field.Key, field.Value);
    				}
    			}
    
    			metadata.SetArgumentsCollection(arguments);
    		}
    
    
    		protected override int Execute(CodeActivityContext context)
    		{
    			
    			<strong>// I need to get the handle in CacheMetadata
    			WorkflowScopeHandle handle = context.GetProperty<WorkflowScopeHandle>();</strong>
    
    				}
    }
    
    Wednesday, August 11, 2010 5:17 PM

Answers

  • Hi,

    It is not the right way to use InArgument by hacking context.
    1. please keep activities independent. no activity should access to other activities.
    2. If you want to share data between different activities, you can define a Variable in their parents scope.
    3. If you want passing data in/out of an activity please use InArgument or OutArgument.

    Thanks


    This posting is provided "AS IS" with no warranties, and confers no rights. Microsoft Online Community Support. My Blog:http://xhinker.com
    • Marked as answer by Andrew_Zhu Thursday, August 19, 2010 7:29 AM
    Thursday, August 19, 2010 7:28 AM

All replies

  • Can you use CodeActivityMetadata.AddArgument or NativeActivityMetadata.AddArgument for the purpose? Why do you need to use the activity context?

     

    Wednesday, August 11, 2010 9:39 PM
  • We already use metadata.SetArgumentsCollection(arguments) which I think is the same.  You can see this in the AddTodo class above. The problem is that we need to know what arguments to create. 

    Maybe I should explain the scenario more clearly:

    We need to define a set of parameters which get extracted from the context in the activity "AddTodo". The activity "AddTodo" will be used several times in the Workflow and should use always the same set of parameters. The set of parameters should be configured only once at designtime and get reused every time when "AddTodo" gets executed. So the idea was to create the "WorkflowScope" Activity in which we define the set of paramters. Within the "WorkflowScope" activity we add the set of parameters to the ExecutionProperties, so we can reuse them later in every child activity of type "AddTodo". But the "AddTodo" childactivities, need to define the paramters as InArguments, otherwise the can not extract the values from the environment.

    In the sample code we did a trick: We use metadata.Environment.Root to read the definition of the parameters and added them to the "AddTodo" activity in CacheMetadata. But this works only if the "WorkflowScope" activity is the parent of the "AddTodo" activity.

    Thursday, August 12, 2010 5:02 AM
  • Hi emikelsoft,

    Why don't you try to use your execution property to store this parameters?

    do you want set arguments properties in activities? not that activites use Execution properties?


    Jérémy Jeanson MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    Thursday, August 12, 2010 7:57 AM
  • I can not use execution properties to store the paramerters. The parameters are actualy a dictionary of InArguments, which needs to get passed into my "AddTodo" activity. So I have to define those Arguments in cache metadata.

    Sunday, August 15, 2010 7:20 AM
  • Hi,

    It is not the right way to use InArgument by hacking context.
    1. please keep activities independent. no activity should access to other activities.
    2. If you want to share data between different activities, you can define a Variable in their parents scope.
    3. If you want passing data in/out of an activity please use InArgument or OutArgument.

    Thanks


    This posting is provided "AS IS" with no warranties, and confers no rights. Microsoft Online Community Support. My Blog:http://xhinker.com
    • Marked as answer by Andrew_Zhu Thursday, August 19, 2010 7:29 AM
    Thursday, August 19, 2010 7:28 AM
  • Ok, thanx
    Thursday, August 19, 2010 11:21 AM