Exposing data with CacheMetadata

Before executing an activity, the workflow runtime obtains all of the information about the activity that it needs in order to maintain its execution. The workflow runtime gets this information during the execution of the CacheMetadata method. The default implementation of this method provides the runtime with all of the public arguments, variables, and child activities exposed by the activity at the time it is executed; if the activity needs to give more information to the runtime than this (such as private members, or activities to be scheduled by the activity), this method can be overridden to provide it.

Default CacheMetadata behavior

The default implementation of CacheMetadata for activities that derive from NativeActivity processes the following method types in the following ways:

  • InArgument<T>, OutArgument<T>, or InOutArgument<T> (generic arguments): These arguments are exposed to the runtime as arguments with a name and type equal to the exposed property name and type, the appropriate argument direction, and some validation data.

  • Variable or any subclass thereof: These members are exposed to the runtime as public variables.

  • Activity or any subclass thereof: These members are exposed to the runtime as public child activities. The default behavior can be implemented explicitly by calling AddImportedChild, passing in the child activity.

  • ActivityDelegate or any subclass thereof: These members are exposed to the runtime as public delegates.

  • ICollection of type Variable: All elements in the collection are exposed to the runtime as public variables.

  • ICollection of type Activity: All elements in the collection are exposed to the runtime as public children.

  • ICollection of type ActivityDelegate: All elements in the collection are exposed to the runtime as public delegates.

The CacheMetadata for activities that derive from Activity, CodeActivity, and AsyncCodeActivity also function as above, except for the following differences:

  • Classes that derive from Activity cannot schedule child activities or delegates, so such members are exposed as imported children and delegates; the

  • Classes that derive from CodeActivity and AsyncCodeActivity do not support variables, children, or delegates, so only arguments will be exposed.

Overriding CacheMetadata to provide information to the runtime

The following code snippet demonstrates how to add information about members to an activity’s metadata during the execution of the CacheMetadata method. Note that the base of the method is called to cache all public data about the activity.

protected override void CacheMetadata(NativeActivityMetadata metadata)
{
    base.CacheMetadata(metadata);
    metadata.AddImplementationChild(this._writeLine);
    metadata.AddVariable(this._myVariable);
    metadata.AddImplementationVariable(this._myImplementationVariable);

    RuntimeArgument argument = new RuntimeArgument("MyArgument", ArgumentDirection.In, typeof(SomeType));
    metadata.Bind(argument, this.SomeName);
    metadata.AddArgument(argument);
}

Using CacheMetadata to expose implementation children

In order to pass data to child activities that are to be scheduled by an activity using variables, it is necessary to add the variables as implementation variables; public variables cannot have their values set this way. The reason for this is that activities are intended to be executed more as implementations of functions (which have parameters), rather than encapsulated classes (which have properties). However, there are situations in which the arguments must be explicitly set, such as when using ScheduleActivity, since the scheduled activity doesn't have access to the parent activity's arguments in the way a child activity would.

The following code snippet demonstrates how to pass an argument from a native activity into a scheduled activity using CacheMetadata.

public sealed class ChildActivity : NativeActivity
{
    public WriteLine _writeLine;
    public InArgument<string> Message { get; set; }
    private Variable<string> MessageVariable { get; set; }
    public ChildActivity()
    {
        MessageVariable = new Variable<string>();
        _writeLine = new WriteLine
        {
            Text = new InArgument<string>(MessageVariable),
        };
    }
    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        base.CacheMetadata(metadata);
        metadata.AddImplementationVariable(this.MessageVariable);
        metadata.AddImplementationChild(this._writeLine);
    }
    protected override void Execute(NativeActivityContext context)
    {
        string configuredMessage = context.GetValue(Message);
        context.SetValue(MessageVariable, configuredMessage);
        context.ScheduleActivity(this._writeLine);
    }
}