More Stuff I Didn’t Know About WF

  1. All communication from the host to the workflows goes thru the WorkflowQueuingService. Unlike other WF services, the queuing service is not replaceable. Communication from a workflow activity instance to the host goes thru some other service. There is no “default” activity -> host communication service, though WF ships with the ExternalDataExchangeService. You have to manually add the ExternalDataExchangeService to your workflow runtime instance. WF also includes the wca.exe utility which generates strongly typed HandleExternalEvent and CallExternalMethod activities for your workflow. And according to Jon, the External Data Exchange system was added specifically for SharePoint.

  2. The built-in sequential and state machine workflows are customizable. So if you wanted to have a custom designer or validation experience for an otherwise standard sequential or state machine workflow, you can inherit from the standard workflow type and add the custom validation and / or designer support. For example, as I wrote earlier, you can load a workflow from XAML. XAML workflows can’t support the Code Activity. So if you wanted to use the standard sequence designer but disallow the use of the Code Activity, you wouldn’t have to rewrite the sequence activity from scratch.

  3. You can execute workflows across a farm, similar to how you build a web farm. Workflows that get persisted to the persistence service can be loaded on any node in the farm. Of course, like web servers in a farm, you’d have to have the same bits installed on all the machines in the workflow farm. Sounds like an opportunity for something like Application Center for WF.

  4. The built in SQL Persistence Service is a toy. When you start your workflow engine, the SQL Persistence Service will auto-load all the existing persisted workflows into memory, as an “optimization”. So if you have thousands of order workflows persisted in your database and you decide to bring another workflow processing node online, that new workflow processing node will happily load ALL of the outstanding orders that it can find in the database. This service should have been included as a sample like the file based persistence service sample rather than described as “a fully functional persistence service” in the docs.

  5. WF Web Service integration is also a toy. WF leverages basic ASMX for all it’s web service integration, so your only choice for web services – consuming or exposing – is atomic request/response style services. You can have a workflow with multiple operations, but the default ASMX hosting infrastructure squirrels the WF Instance ID in the ASP.NET session, which will time out in twenty minutes (by default). Furthermore, the built in ASMX workflow host doesn’t provide an option to specify the web service namespace, so it ends up with the default namespace. Again, like the SQL Persistence, this should have been included as a sample, not included in the standard activities.

  6. Activities can generate code. In the previous item, I mentioned there’s basic ASMX hosting integration for a workflows. Turns out the WebService Activities generate that hosting code as part of the workflow compilation process. So in other words, if you add a WebService activity to your workflow, the activity will inject the custom ASMX hosting code into your compiled workflow. In this WebService activity case, the injected code isn’t very good, but the fact you can do this at all is very cool.


Transactions are also a toy. You can't call other flows within a transaction nor can you federate multiple workflow instances within a transaction. This is understandable because a transaction context is a box threads enter and leave. You can't -- by default at least -- know what thread(s) will execute your flow and there is no plumbing built into the WF engine to guide threads in or out of Tx contexts. But you can implement a Manual Workflow Scheduler (I think), which bypasses the WorkflowQueuingService you mention. But I haven't tried passing a transaction context in this way. BTW, you can't even use a transaction (or a sleep activity) without attaching a WorkflowPersistenceService because these activities can invoke a dehydration cycle. The SQLPersistenceService is, I think, a level up from being just a toy. The SQLTrackingService was well, thought-out, IMO. But because I was trying to use WF inside a more synchronous scenario, I ended up creating an oxymoronically named "MemoryPersistenceService" so I could use these activities without all the baggage. I REALLY wished WF was more adept with XML data and XML Schema -- especially WRT the rules engine. Also, I'm really disappointed that XAML isn't documented (well) and there isn't a schema for XAML. I'm told on the newsgroups that there is no way to define a normative schema for XAML because you don't know the properties for the contained objects. Fair enough, but a simple wildcard would work, right? In fact the whole XAML angle looks like it got put on the back burner, which is a shame. How cool is it to be able to whip a workflow up using an XMLWriter and then run it? You can do it, but you have to reverse-engineer the format. Despite these nits, I'm a big fan of WF. I like the engine design and it's fast (1ms overhead to execute a 10-step no-op sequental workflow.
Erik - the scheduler service override has absolutely nothing to do with the QueueingService. The WorkflowQueueingService is one service you can't replace (well you might be able to replace it - but it will be a no-op since there aren't any virual methods to override).
I'm not sure I would call WF's transactions a toy. It certainly could be better - the stuff I'm working on right now I'd like to flow the Tx from outside the workflow (i.e. in a WF Service) into the Workflow, but I don't think there's any way to do that. Then again, on the other hand, transactions are really hard and easy to screw up. So maybe having specific boundaries to what you can and can't do in a workflow is a good thing? A MemoryPersistenceService? That's funny...