Question

My TFS2012 custom build workflow has many custom parameters, which are defined in my build definition. I want to pass all of them to an exe that runs during build (I'm aware of the option of custom activities, but I can't use it, since I don't want to change the controller's binaries every time).

I managed to take buildDetail.ProcessParameters and buildDetail.buildDefinition.ProcessParameters, write them to files and pass them to my exe, which will parse them (possibly using WorkflowHelpers.DeserializeProcessParameters. However, this means that the exe will need to merge both ProcessParameterss, and I'd like to avoid that.

Is there any way to get the resulting ProcessParameters from within the workflow? I could call WorkflowHelpers.GetProcessParameters(Activity), but how would I get the root activity of the workflow?

Was it helpful?

Solution

I managed to do it by keeping a WorkflowInstanceProxy, as suggested here:

public class WriteProcessParameters : CodeActivity
{
    protected override void Execute(CodeActivityContext context)
    {
        WorkflowInstanceProxy proxy = context.GetExtension<WorkflowInstanceInfo>().GetProxy();
        Activity root = proxy.WorkflowDefinition;
        Dictionary<string, ProcessParameter> processParams = WorkflowHelpers.GetProcessParameters(root);
        // Serialize processParams somehow...
    }

    protected override void CacheMetadata(CodeActivityMetadata metadata)
    {
        base.CacheMetadata(metadata);
        metadata.AddDefaultExtensionProvider<WorkflowInstanceInfo>(() => new WorkflowInstanceInfo());
    }

    private class WorkflowInstanceInfo : IWorkflowInstanceExtension
    {
        private WorkflowInstanceProxy m_proxy;
        public IEnumerable<object> GetAdditionalExtensions() { yield break; }
        public void SetInstance(WorkflowInstanceProxy instance) { this.m_proxy = instance; }
        public WorkflowInstanceProxy GetProxy() { return m_proxy; }
    }
}

That worked in my toy test, but not in an actual workflow (not sure why). So I ended up reading properties, like this:

public InArgument<string> Filename { get; set; }

protected override void Execute(CodeActivityContext context)
{
    var propDescriptors = context.DataContext.GetProperties().Cast<PropertyDescriptor>();
    var props = new Dictionary<string, object>();
    foreach (var propDesc in propDescriptors.OrderBy(p => p.Name))
    {
        object value = propDesc.GetValue(context.DataContext);
        if (value == null)
        {
            var converter = TypeDescriptor.GetConverter(propDesc.PropertyType);
            if (converter.CanConvertTo(propDesc.PropertyType))
            {
                value = converter.ConvertTo(value, propDesc.PropertyType); // Known case: null string
            }
            else
            {
                continue;  // Known case: RunTestParameters
            }
        }
        else
        {
            if (!value.GetType().IsVisible || !value.GetType().IsSerializable)
            {
                continue;
            }
        }

        props.Add(propDesc.Name, value);
    }

    File.WriteAllText(Filename.Get(context), WorkflowHelpers.SerializeProcessParameters(props));
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top