Workflow lifecycle management without a "save service"

I am using Windows WF right now for an easy way to declare machines. In fact, I don't even use a state machine, I am using a sequential workflow. Eventually, I will ditch WF in favor of something else, but since I already have the code, I need to get Abort, Suspend and Resume to work.

My application spawns a thread, which then spawns another thread that owns the WorkflowInstance. My GUI has Abort, Pause and Resume buttons and they end up calling the WorkflowInstance Abort, Suspend, and Resume methods respectively.

The problem is that when I do this I get a very large and scary MessageBox that says:

There is no persistence service in the workflow hosting environment as required by the workflow instance operation

along with a nice stack trace and all. Now I looked at these methods in Pro WF by Bruce Bukovics and one of his examples calls these methods and doesn't mention the "persistence" service "was anywhere. However, his examples of calls were within the WorkflowRuntime framework, meaning he calls them in the following way:

using(WorkflowRuntimeManager manager = new WorkflowRuntimeManager(new WorkflowRuntime("WorkflowRuntime")))
{
  manager.WorkflowRuntime.StartRuntime();
  WorkflowInstanceWrapper instance = manager.StartWorkflow(typeof(SharedWorkflows.Workflow1), null);
  instance.Suspend("Manually suspended");
  instance.Resume();
  waitHandle.WaitOne();
}

      

In my application, I implemented WorkflowRuntime as a one-liner because I found there was a huge memory leak when I created the WorkflowRuntime like this. So my code looks like this:

WorkflowInstance instance = WorkflowRuntimeSingleton.Instance.workflow_runtime.CreateWorkflow(typeof(SharedWorkflows.Workflow1), null);
instance.Start();
instance.Suspend("Manually suspended");
instance.Resume();
waitHandle.WaitOne();

      

Now if I call Suspend and Resume as shown above, it works fine. But if I issue a call through my GUI it complains about the persistence service.

Given this information, and I don't want to tune the database just to get these three functions, I would like to know what I need to do to make this work. My best guess at this point is that WF doesn't like being controlled from a separate thread. If so, is there a good way to make the call look like it is being issued from a single thread?

Here are some possible solutions I have come up with, but I'm sure someone has a more convenient and elegant way to do this.

  • Polling WF for interrupt / pause / resume via interface to GUI (seems very lame)
  • Replace WaitOne () with WaitAny () and call the GUI on the object that owns the workflow, set AutoResetEvent. WaitAny () allows execution to continue and then my code can check which button the user pressed. This would need to be wrapped in a loop so that we can wait again until the user hits the Abort button, or until the WF exits.
  • use a boolean flag to basically do what # 2 does.
  • See if anyone on SO knows how to magically make a call to the topic you want :)

Any insight or opinions would really be appreciated!

+1


a source to share


3 answers


There is not much of it to create a persistence database. In fact, it will help solve memory problems as it keeps worker processes suspended for longer than a specified period of time (due to their lack of memory). Here is a link to help you create a database and use it in your workflow: http://msdn.microsoft.com/en-us/library/ms735722(VS.85).aspx

The link mentions changing your app.config. I didn't. Instead, I added the service to the code. Like this:



//Add the persistence service
WorkflowPersistenceService persistenceService = new SqlWorkflowPersistenceService(
    DBConnections.PersistenceService,
    true,
    TimeSpan.MaxValue,
    new TimeSpan(0, 0, 15));
m_WorkflowRuntime.AddService(persistenceService);

      

EDIT: Another helpful link

+5


a source


SQL Server Compact will not work because CE does not support stored procedures that are part of the default persistence DB creation script and are called by the SQL persistence service. CE is for embedding a motor in an application. The DB file will be used with something like SQL Server Express, where the engine runs in a separate process, but you can specify the DBF file rather than connecting to a database already attached to the engine.



As per your question / answer, you don't seem to expect a workflow created with one instance of the app to be called by another instance (shared workflows). Another possibility is not to use the SQL version of the save service. There is an example (may not be complete, not sure) of a workflow continuity service that relies on direct serialization of a workflow to a file at http://msdn.microsoft.com/en-us/library/ms741725.aspx . I don't know if it supports all your needs, but since it includes source, you can customize it.

+1


a source


I am posting this as an answer to get some decent formatting. I followed Gabriel's answer and I have the scariest time to set up the database. I have a few questions regarding this.

All links mention creating a database using Microsoft SQL Server Query Analyzer, which I don't have. Instead, I went to Server Explorer in VS2008 by right clicking Data Connections -> Create New SQL Server Database. I used Windows Authentication and selected my computer using the servers choke.

I want to be able to run this code on multiple systems using the same database file. Why can't I specify localhost here?

Regarding the above question, if I create a new database using Data Connections -> Add Connection instead, I can create a local database file that I can include in my solution and presumably go from PC to PC. This is probably the right way to go, but

What's the difference between using "Microsoft SQL Server Compact 3.5" and "Microsoft SQL Server Database File"? Both allow me to create a file. I like the Compact choice better because I don't need to use a password, but I don't know if that requires another special service to be installed on the other computer that doesn't need the database file parameter.

Moving on, I have to execute a SQL query to create a table for the workflow persistence store. According to the linked pages, this is the location:

%WINDIR%\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\<language>\SqlPersistence_Schema

      

Since I don't have a Query Analyzer, I figured that running a query from VS2008 should work well enough. If I copy and paste the SQL into the query box, I get this error dialog:

Query Definitions Differ

The following errors were encountered while parsing the contents of the SQL pane:
The Set SQL construct or statement is not supported.

      

and then:

SQL Execution Error.

Executed SQL statement: -- Copyright (c) Microsoft Corporation. All rights reserved.

SET NOCOUNT ON

--
-- ROLE state_persistence_users
--
declare @localized_string_AddRole_Failed nvarchar(256)
set @localized_string_AddRole_Failed = N'Failed adding the "state_per...
Error Source: .Net SqlClient Data Provider
Error Message: Incorrect syntax near the keyword 'if'.
Incorrect syntax near 'GO'.
Incorrect syntax near the keyword 'CREATE'.
Incorrect syntax near the keyword 'IF'.
Incorrect syntax near 'GO'.
Incorrect syntax near the keyword 'CREATE'.
Incorrect syntax near the keyword 'CREATE'.
Incorrect syntax near the keyword 'DBCC'.
Incorrect syntax near ')'.

      

Does anyone know of any other ways that I can try to create a persistence store?

0


a source







All Articles