In these days I was involved on the migration of lots of my services under the new .NET 3.5 platform (WCF and WF).
Today I've tryed to expose a Windows Workflow as an XML Web Service and now I've a dilemma... :)
OK... let's go from the beginning...
With Windows Workflow is quite simple to expose a WF as an XML Web Service. Start Visual Studio 2008, New Project and choose Sequential Workflow Library:
Then, exactly like WCF, you need to define an interface that will act as the interface to the workflow (I've used VB.NET in my project):
Interface IWS
Function MyMethod(ByVal Input As String) As String
End Interface
Then add two properties that acts as the input and output value of your service. For example:
'Input value
Public Property Input() As String
Get
Return _Input
End Get
Set(ByVal value As String)
_Input = value
End Set
End Property
'Output value
Public Property Output() As String
Get
Return _Output
End Get
Set(ByVal value As String)
_Output = value
End Set
End Property
Now, go to the workflow designer and design a workflow like this:
In this sample, I have a webServiceInputActivity that receives a string value from the caller, than a CodeActivity that makes some works and a webServiceOutputActivity that returns a string value.
These are the properties for the webServiceInputActivity:
and these are the properties for the webServiceOutputActivity:
The CodeActivity must have an ExecuteCode method that makes some work. On my sample I've simply this:
Private Sub WorkingProcess_ExecuteCode(ByVal sender As System.Object, ByVal e As System.EventArgs)
_Output = _Input + " - Processed by WF"
End Sub
Now you've to go to your project, right click on it and select "Publish as Web Service":
Visual Studio adds for you an ASP.NET website to the solution (with an appropriate web.config):
If you run the solution the built-in ASP.NET development server will be launched and the web service page will be opened on your browser. Here you can test the method. Everything is OK.
But what happens if you re-launch the service?
You will obtain this error:
System.InvalidOperationException: The workflow hosting environment does not have a persistence service as required by an operation on the workflow instance ......
This error occours because you don't have a persistence service associated to the workflow (I've spent lots of minutes in order to undertand this ;) ).
If you associate a persistence service (you need to create a SQL Database via the WF SDK scripts, on my pc they're located on C:\Windows\Microsoft.NET\Framework\v3.5\SQL\EN) it works ok.
On your web.config you can see that you've a new row, something like:
<add type="System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" UnloadOnIdle="true" ConnectionString="Initial Catalog=WF_DB;Data Source=.;Integrated Security=SSPI;" />
I've learned from forums that:
If Client(Browser/WebServiceClientProtocol derivative) makes request without cookies, WorkflowRuntime will check to see if that particular operation can activate an worklow instance(i.e if the operation is marked as activation in the workflow) if yes then a new instance will be created and the corresponding cookies will be sent back to client.
If the client supports cookies(i.e Browser by default accepts cookies unless disabled explicitly, WebServiceClientProtocol class doesnt support cookie by default unless you populate "CookieContainer" Property) and makes subsequent request with that cookie, then server will always try to locate the worklow instance attached to it, if the workflow is not in memory(dehydrated/completed/terminated) it will query the persistence service for retrieval.
If persistence service exist and the worklow instance is alive then it will be rehydrated and request will be serviced by it. If the workflow instance is already complted/terminated, and WorkflowInstanceException will be thrown by the persistenceservice(stating wotrkflow couldnot be found .blah blah..).
If persistence service never existed and worklow instance is not available in memory, this is what you will get, basically it means runtime doesnt have instance in-memory and it doesnt know where to get it since there is no persistence service.
So it works first time because new browser session - no cookie - activation request.
Subsequent request with same browser window - cookie is cached by browser - your request contains routing cookie - following request, workflowruntime tries to find instance and fails:) since it is already completed.
Now my question is: is it really never possible to change this default behaviour? Should I always have a persistence database? Can't I have an "atomic transaction", a workflow that runs from start to finish without persistence?
This seems a bit strange to me...