So pretty much the worst thing an instructor can do is tell a class something that
is wrong.  I did that last week teaching a WF/WCF “combo” course in Kirkland,
WA.  What is worse is that one of my students blogged about two of them, which
has caused a little controversy.

Here is Harry’s first entry. 

Here is Paul’s response

And Harry’s follow-up. 
To back Harry up – I know after I talks that he doesn’t think WF is a *Toy*. 
He had some realistic reservations about a couple of pieces.

So here is what I got wrong – in earlier builds of WF – the WebServiceInput/WebServiceOuput
activities in combination with the ASMX hosting layer – kept the Workflow InstanceID
in Session (although now I am doubting that – I very clearly remembering seeing that
code with Reflector).  It now uses a “normal” Http Cookie.  The problem
I proposed in class still holds true – which is that because the ASMX hosting layer
doesn’t allow you to change the namespace URI (see Paul’s blog for a manual fix for
this) and because it does still send a “session” based cookie.  Which means if
the client closes (let’s say the client is a Windows Forms application) – the cookie
is lost and the Workflow would be “abandoned” on the server.  Of course if the
client is a workflow – and the client persists the cookies will get persisted as well
– so you can get long-running workflows – but only if the client is a workflow.

So if the cookie gets “lost” there isn’t any other way to “rematch” the workflow to
a new client.  That is also one of what I see as a limitation of the OOB WF/ASMX
integration layer – is that there isn’t any way (OOB that is) to share a workflow
instance among different users.  So one of the details I taught (Session versus
custom cookies) was incorrect – but the general usage model of the OOB WF/ASMX integration
was correct (although I am pretty sure I didn’t use the moniker Harry associated with
it). 

IMO – the OOB WF/ASMX integration layer will be useful in about 25% or so of cases
when someone wants to expose a workflow as a ASMX Web Service.  I think in the
other 75% of cases people will build their own layer that has a little more flexibility.

On to the SqlWorkflowPersistenceService.  Let me be clear – I have extreme respect
for the people who wrote this code (I actually know them personally).   
First of all – here is what Harry blogged that is incorrect (and I am not sure if
explained this incorrectly or not  – but let’s assume that I did) – the OOB persistence
service doesn’t load *all* instances when one host starts – it loads all *running*
workflows (so workflows that are idled stay idled and persisted).  So if two
hosts go down and start back up  – all running instances will get loaded into
the first host that comes back up (no load balancing).

Also to me – the biggest limitation of the OOB persistence and tracking service –
is the fact that if I use them together – and then put my own TransactionScope activity
with database access code – I end up getting a DTC transaction.  For the WF applications
I’ve worked on this was enough for us to want to create a custom tracking and persistence
service.

There are a few more reasons to write a custom persistence service.  I won’t
go into all of them here  – but there are good reasons to write a custom persistence
service with WF – which means the OOB persistence service won’t be used 100% of the
time – which was really my point – I think it is probably usable in about 75% of cases.

So here is my final word on this subject (I hope :)) :

The OOB WF/ASMX integration is useful mostly when there are workflows on both ends-
and when you don’t need to share workflows across users.

The OOB SqlWorkflowPersistenceService is a very usable service if you are doing one
or two hosts and need robustness and load balancing.

WF is not a toy  – Harry never said WF overall was a toy – just the two features
here – he got the wrong information from me and hopefully this blog post has cleared
that up.  Anyone who reads this blog knows that I actually love WF and think
it is by far the best and most interesting part of .NET 3.0.