views:

191

answers:

1

Hi,

I am building a Windows Workflow into a .Net webapp. The problem I have is that every time I add or remove or change an activity in the state machine and then re-compile and run it, it no longer matches up to what is in the database for tracking and persistence. Instead of updating the changes, or creating a new version of the workflow in the database it throws an error. Sometimes it an "index out of bounds" error, other times its "Cannot get the member XXXXX."

To get it to work I have to delete the database and re-build it. I believe this works because when the workflow engine looks for the workflow in the database it doesn't find it and thus adds it to the database. This is very frustrating at the stage I am at, where I am building the workflow and it changes many times in a day.

Is there a way I can simply get the workflow engine to update the relevant tables in the database with the changes I have made to the workflow? Or overwrite it with a new version? I have looked at various webpages on setting up the workflow for dynamic updating at runtime but none of these suggestions worked for me. And whilst that is a feature I would like for my workflow, I am not sure if it is really the way to solve the problem I am having. It is not so much that I am creating a new version of the workflow, rather I am building a workflow and want to test the part I have just finished/added and I don't care about previous versions of the workflow and any partially complete workflows in the database.

Thanks.

+1  A: 

I too faced similar problem , everytime Workflow design was change, all the old workflow instances in the DB use to throw error.

To overcome this , I created Tracking profile for each type of workflow. If I changed any workflow, i updated the version of my profile. This worked for me ..Here is the sample code -

For this you need to add tracking service to workflow runtime .

TrackingProfile profile = CreateProfile();

StoreProfileToDB(profile, connString, typeof(ExceptionWF.ParameterExceptionWF),"2.0.0.0");

private static TrackingProfile CreateProfile() { TrackingProfile myProfile = new TrackingProfile();

        ActivityTrackingLocation stateActivityLocation = CreateActivityLocation(typeof(StateActivity));
        AddActivityExecutionStatus(stateActivityLocation);

        ActivityTrackingLocation eventDrivenActLoc = CreateActivityLocation(typeof(EventDrivenActivity));
        AddActivityExecutionStatus(eventDrivenActLoc);

        ActivityTrackPoint actPt = new ActivityTrackPoint();

        actPt.MatchingLocations.Add(stateActivityLocation);
        actPt.MatchingLocations.Add(eventDrivenActLoc);
        myProfile.ActivityTrackPoints.Add(actPt);

        WorkflowTrackPoint workflowTrack = CreateWorkflowTrackPoint();
        myProfile.WorkflowTrackPoints.Add(workflowTrack);

        UserTrackPoint utp = new UserTrackPoint();
        UserTrackingLocation ul = new UserTrackingLocation();
        ul.ActivityType = typeof(HandleExternalEventActivity);
        ul.ArgumentType = typeof(object);
        ul.MatchDerivedArgumentTypes = true;
        ul.MatchDerivedActivityTypes = true;
        utp.MatchingLocations.Add(ul);

        myProfile.UserTrackPoints.Add(utp);
        myProfile.Version = new Version("1.0.0.0");
        return myProfile;
    }

    private static void StoreProfileToDB(TrackingProfile profile, string connString, Type wfType,string version)
    {
        TrackingProfileSerializer serializer = new TrackingProfileSerializer();
        System.IO.StringWriter writer = new System.IO.StringWriter(new StringBuilder());
        serializer.Serialize(writer, profile);
        SqlConnection conn = null;
        try
        {
            if (!String.IsNullOrEmpty(connString))
            {
                conn = new SqlConnection(connString);


                string storedProc = "dbo.UpdateTrackingProfile";
                SqlCommand cmd = new SqlCommand(storedProc, conn);
                cmd.CommandType = System.Data.CommandType.StoredProcedure;

                SqlParameter param = new SqlParameter("@TypeFullName", SqlDbType.NVarChar, 128);
                param.Direction = ParameterDirection.Input;
                param.Value = wfType.FullName;
                cmd.Parameters.Add(param);


                param = new SqlParameter("@AssemblyFullName", SqlDbType.NVarChar, 256);
                param.Direction = ParameterDirection.Input;
                param.Value = wfType.Assembly.FullName;
                cmd.Parameters.Add(param);


                param = new SqlParameter("@Version", SqlDbType.VarChar, 32);
                param.Direction = ParameterDirection.Input;
                //Note that you should increment version number for your
                //TrackingProfile to be able to use new TrackingProfile.
                //Default version is "1.0.0.0, It uses the default profile if not increamented.
                param.Value = version;
                cmd.Parameters.Add(param);

                param = new SqlParameter("@TrackingProfileXml", SqlDbType.NText);
                param.Direction = ParameterDirection.Input;
                param.Value = writer.ToString();
                cmd.Parameters.Add(param);

                conn.Open();
                cmd.ExecuteNonQuery();

            }//if
        }// try
        catch (Exception ex)
        {
            if (ex is SqlException)
            {
                //Check to see if it's a version error
                if (ex.Message.Substring(0, 24) == "A version already exists")
                {
                    EventLogger.Log("A profile with the same version already exists in database");
                }//if
                else
                {
                    EventLogger.Log("Error writing profile to database : " + ex.ToString());
                }
            }
            else
            {
                EventLogger.Log("Error writing profile to database : " + ex.ToString());
            }
        }
        finally
        {
            if (conn != null) { conn.Close(); }
        }
    }
ksa
In addition profile tracking another option is to load the multiple workflow versions into your global assembly cache. The good news is that this won't be a problem in .NET4.0. The bad news release of 4 is going to be sometime next year.
ahsteele
@ksa - are you incrementing the version number by hand? That is, if you change your workflow, before you re-compile you bump up the version number in the source code? I tried doing something like this by comparing the tracking profile in my database, with the one that was just created and if they were different I would up date the profile and increment the version, but I kept on getting db errors that I couldn't solve.@ahsteele - I tried this also, but again failed... not a lot of wins for me last week!I will try again. :-)
iamdudley
Do you mean to say, after changing the profile version, you "Update" the DB, If yes then this the problem. The old workflow instances in your DB will still need the old profile versions. When you change your workflow design, just update the version of profile in code (Since u changed the design or workflow code). The Db should now have to profile versions of same workflow type. Hope this helps.
ksa
I've come back to this because my tracking no longer works at all. I have noticed in the code sample that the profile version in the xml is different from the profile version stored in the Db field. Is this intended? I thought they should be the same.
iamdudley