Using collections of custom objects in a workflow

Last week during my Chalk & Talk session at the SDC one of the attendees was having problems with workflow persistence and collections of custom objects. Now I never got to see his code so I am not sure what the problem was but maybe this simple sample will convince him that this should work.

So we need a simple type, I decided to keep thing really simple and use the following:

using System;

namespace WorkflowConsoleApplication1
{
    [Serializable]
    public class Person
    {
        public string Name { get; set; }
    }
}

And we need a simple workflow like this. The two code activities print the contents of the collection and the delay activity is there to make sure everything is persisted to the database so I can stop and restart the application.


image


The code in the workflow is pretty simple as well [:)]

using System;
using System.Collections.Generic;
using System.Workflow.Activities;

namespace WorkflowConsoleApplication1
{
    public sealed partial class Workflow1 : SequentialWorkflowActivity
    {
        public Workflow1()
        {
            InitializeComponent();
        }

        public List<Person> People { get; set; }

        private void printPeople_ExecuteCode(object sender, EventArgs e)
        {
            Console.WriteLine("The people in workflow {0} are:", WorkflowInstanceId);
            foreach (var person in People)
            {
                Console.WriteLine(person.Name);
            }
            Console.WriteLine();
        }
    }
}

And the code in the main program is simple to [:)]. First we need to add the SqlWorkflowPersistenceService the runtime.

using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
    string connStr = @"Data Source=.\sqlexpress;Initial Catalog=WorkflowPersistence;Integrated Security=True";
    SqlWorkflowPersistenceService persistence = new SqlWorkflowPersistenceService(
        connStr, true, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(15));
    workflowRuntime.AddService(persistence);

 


and when we start the workflow we need to add the collection of people like this:

List<Person> people = new List<Person>();
people.Add(new Person() { Name = "Maurice de Beijer" });
people.Add(new Person() { Name = "John Doe" });
people.Add(new Person() { Name = "Arthur Dent" });

Dictionary<string, object> parms = new Dictionary<string, object>();
parms["People"] = people;

WorkflowInstance instance = workflowRuntime.CreateWorkflow(
    typeof(WorkflowConsoleApplication1.Workflow1), parms);
instance.Start();

 


Just to make sure we could see when a workflow was loaded from disk I added the following:

workflowRuntime.WorkflowLoaded += (s, e) =>
{
    Console.WriteLine("Workflow {0} was just reloaded", e.WorkflowInstance.InstanceId);
};

 


And the result is:


image


Just before this run I started the application and stopped it while the delayActivity was waiting so there was an extra record in the persistence database. During this run we can see the workflow being rehydrated and the collection of people being present. So everything works just as expected.


So pretty much the only thing that cab go wrong here is with the serialization. The workflow runtime uses the binary serializer sp all types need to be Serializable. And this includes all other types that are referenced somehow. And the somehow includes event handlers, something people tend to forget as this is not very visible as an object reference.


Hope this helps.


[f1]
[f2}

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>