Windows Workflow Foundation and ASP.NET

Sunday, February 11, 2007

My latest article shows how to drive an ASP.NET web form using a state machine workflow. The sample is based loosely on the Ordering State Machine smart client sample in the SDK, but adds a few real world requirements.


Comments
Steve Monday, February 12, 2007

I haven't looked at it other than getting it installed on my machine, but the new Web Client Software Factory from the Microsoft Patterns & Practices group contains a Page Flow Application Block

www.codeplex.com/.../View.aspx

Thomas Tuesday, February 13, 2007
System.Workflow.Runtime.Hosting.PersistenceException was unhandled by user code
Message="MSDTC on server 'NAME-2ARH9OD9A9\\SQLEXPRESS' is unavailable."
Source="wfOrderServices"
StackTrace:
bei wfOrderServices.OrderService.VerifyResults(WorkflowResults workflowResults, WorkflowStatus status) in C:\MyProjects\wfOrders\wfOrderServices\OrderService\OrderService.cs:Zeile 151.
bei wfOrderServices.OrderService.CreateOrder(Order order) in C:\MyProjects\wfOrders\wfOrderServices\OrderService\OrderService.cs:Zeile 28.
bei _Default.createOrderButton_Click(Object sender, EventArgs e) in c:\MyProjects\wfOrders\wfOrderWeb\Default.aspx.cs:Zeile 58.
bei System.Web.UI.WebControls.Button.OnClick(EventArgs e)
bei System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
bei System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
bei System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
bei System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
bei System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
scott Tuesday, February 13, 2007
You'll need to turn on the MSDTC (Microsoft Distributed Transaction Coordinator) in your Services MMC.
Xeon Thursday, February 15, 2007
Which version of database server is needed to run wfOrders.sql?
It drops error messages on MSSQL 2000
scott Thursday, February 15, 2007
Xeon:

I generated the script using SQL 2005. I'll update the help file to reflect this requirement, and the requirement to have MSDTC running.
Heng Wang Thursday, February 15, 2007
Hi, I read your ".NET 3.0
ASP.NET and Windows Workflows Foundation".

I download the source code. but I can not build it. Here is the error:

"Build (web): Could not load file or assembly 'PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
"

I even can not get OrderStateMachine.xoml design.
the error:

CreatedInstance failed for type 'UpdateOrderActivity'...

I did checked MSDTC and I changed the two parts of web.config and I did created the database wfOrders.

What I can correct the problem?

thanks
Heng Wang
scott Friday, February 16, 2007
Hi Heng:

Are you sure you have the .NET 3.0 framework installed?

The workflow will not load in the designer until the it's dependencies build. Once everything builds you should be ok.
Xeon Friday, February 16, 2007
Hi Scott,

I've tried with MSSSQL2005 Express and working now, but be aware of MSDTC settings described in Readme, on "3.5 MSDTC Is Not Fully Enabled on Windows" topic.

msdn.microsoft.com/.../sqlreadme/

Regards,
Xeon
scott Friday, February 16, 2007
Thanks for the tip, Xeon. I added that link to the readme file.
serg Friday, February 23, 2007
Hi Scott,
I've tried wfOrders.sql and... take a look:


Server: Msg 170, Level 15, State 1, Line 2
Line 2: Incorrect syntax near 'ROLE'.
Server: Msg 170, Level 15, State 1, Line 2
Line 2: Incorrect syntax near 'ROLE'.
Server: Msg 170, Level 15, State 1, Line 2
Line 2: Incorrect syntax near 'ROLE'.
Server: Msg 170, Level 15, State 1, Line 2
Line 2: Incorrect syntax near 'ROLE'.
Server: Msg 208, Level 16, State 1, Line 1
Invalid object name 'sys.schemas'.
Server: Msg 208, Level 16, State 1, Line 1
Invalid object name 'sys.schemas'.
Server: Msg 208, Level 16, State 1, Line 1
Invalid object name 'sys.schemas'.
Server: Msg 208, Level 16, State 1, Line 1
Invalid object name 'sys.schemas'.
Server: Msg 170, Level 15, State 1, Line 19
Line 19: Incorrect syntax near '('.
Server: Msg 170, Level 15, State 1, Line 7

....... and so on .........
scott Friday, February 23, 2007
Hi Serge:

That seems odd. Is this on SQL 2005?
Luca Sunday, February 25, 2007
Hi scott, i've found your article very useful and extremely clear.
I'm actually get involved in learning and applying workflow in our web application and i'm playing with workflow foundation a bit.

I just want to write about a litte change that i've made to your code.

My requirement was to be able to use the WorkflowMediator without coupling it with a specific service(as like OrderService).

To do this the WorkflowMediator must be able to let someone else add two things:
1) add the specific data service
2) add the concrete ContenxtWrapper

The solution I've found was to add a static event to the WorkflowMediator class, add a call to that event in the AddService method and create and event handler for that event where the app starts(global.asax in the web app or in the main entry for console app).

WorkflowMediator class:

static public event eventHandler<WorkflowMediatorEventArgs> ServiceLoading;

protected virtual void AddServices()
{
if (WorkflowMediator.ServiceLoading != null)
{
WorkflowMediator.ServiceLoading(null, new WorkflowMediatorEventArgs(this));
}
}

WorkflowMediatorEventArgs class:

public class WorkflowMediatorEventArgs : EventArgs
{

private WorkflowMediator _workflowMediator;

public WorkflowMediator WorkflowMediator
{
get { return _workflowMediator; }
}

public WorkflowMediatorEventArgs(WorkflowMediator instance)
: base()
{
this._workflowMediator = instance;
}

}

And finally from my console app:

static void Main(string[] args)
{
WorkflowMediator.ServiceLoading += delegate(object source, WorkflowMediatorEventArgs e)
{
e.WorkflowMediator.ContextService = new MyContextWrapper();
e.WorkflowMediator.AddDataService(MyService.Instance);
};
scott Monday, February 26, 2007
Excellent, Luca.

I took one approach in my code for my specific scenario, I'm glad other people are able to extend the code.

Stephan Smetsers Monday, February 26, 2007
Hi,

You really should look at my freeware framework. It enables the use of sequential workflow in ASP.NET with just a few lines of code.

http://www.inchl.nl

demo video:
www.inchl.nl/.../inchl.framework.workflow.wmv

Stephan
Patrick Monday, March 5, 2007
Hi Scott,

I presented your sample to a talk at my local .NET user group last week. Quite some interested generated. I been looking for best practices on integrating WF to applications and I found your sample to be complete esp on the WF transaction. I am looking forward to integrate this code into my project.

BTW, when I enable SharedConnectionWorkflowCommitWorkBatchService service in web.config; my web page post back timeout. Any idea on how to make it work?
Lucia Wednesday, March 7, 2007
Hi,

I keep getting the following message, got any idea why?

Error HRESULT E_FAIL has been returned from a call to a COM component.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Runtime.InteropServices.COMException: Error HRESULT E_FAIL has been returned from a call to a COM component.

Source Error:


Line 149: if (workflowResults.Exception != null)
Line 150: {
Line 151: throw workflowResults.Exception;
Line 152: }
Line 153: else

scott Wednesday, March 7, 2007
Lucia:

I'm not sure what could be happening there. Is there any details in the event log?

gravatar Angie Thursday, October 22, 2009
I read your article ASP.NET and Windows Workflows Foundation in context of real world order tracking example. I thought that was very interesting and provide the complete insight of leveraging workflow in asp.net. One question does came in my mind i was hoping to get you thought on that. How would that work in WEb Farm when you have multiple servers running asp.net application , could you have senario where 2 workflow were started same time by different servers ? I would appreciate if you could provide any insight
Thanks
gravatar Tiago Friday, October 23, 2009
Hi Scott

I read your article, congratulations for it, but I have a trouble to execute the code, I am trying to execute the code in Windows Vista with Visual Studio 2008, but it returned the following message when i execute (F5): It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS. Do you have any idea for correct it?
Thanks
gravatar kmusaied Sunday, November 1, 2009
Can you update the sample code its too old.
gravatar Routin Jean Wednesday, November 4, 2009
Hi,
Thank you for this interesting article. I need a guidance to manage PersistenceException.
Suppose a timeout exception is raised during gateway.UpdateOrder(order); in method wfOrderServices.OrderTransactionService.Commit, then we enter in the method Complete(bool succeeded, ICollection items) with the value false assigned to succeded. I did not changed your code and in this case the persistence mechanism call the store procedure exec InsertInstanceState @uidInstanceID='1C1C1193-9D8E-42ED-A672-4146F9DC5451',@state=0x,@status=3,@unlocked=1,@blocked=0,@info=N'The operation is not valid for the state of the transaction. The operation is not valid for the state of the transaction. Délai d''expiration de transaction'.

The status 3 will remove the workflow instance in the data base.

I would like to avoid this behavior. Do I have to write specific code in the method Complete. How to tell the persistence service not to delete this current instance.

Thanks
gravatar Noel Tuesday, November 10, 2009
I'm in the process of designing a State Machine workflow that doesn't get persisted, due to the lack of versioning capabilities. Data that is currently being stored in the database will drive what state the workflow will be in. Any advice?
gravatar Noel Tuesday, November 10, 2009
I'm in the process of designing a State Machine workflow that doesn't get persisted, due to the lack of versioning capabilities. Data that is currently being stored in the database will drive what state the workflow will be in. Any advice?
gravatar Paul Butler Thursday, November 26, 2009
Hi Scott

I'm working through your example and think it's fantastic - there's not much asp.net state machine stuff out there!! Especially real world type examples - so a big thanks for this. You've been a great help.

I now want to add tracking services to the solution - and because persistence is also in use (and both are hosted in the same SQL database) I've added the SharedConnectionWorkflowCommitWorkBatchService to the web.config - in <Services> under <wfConfiguration>.

Unfortunately Now when I run your example it freezes at the connection.Open(); line in the OrderGateway.cs class and eventually timesout (same issue as Patrick had back in March 2007) - line 101 (whilst attempting to insert a new order). If I comment out the SharedConnectionWorkflowCommitWorkBatchService in the web.config - it all works again - but alas no Tracking - just persistence :(

I've tried moving the Orders table to a separate DB and set a different connection string for the insert - but the same thing happens.

Any suggestions or ideas would be greatly appreciated - I've spent hours trying to get this to work..

Basically I need Tracking and Persistence and the ability to update a table like Orders with state and workflow info - I intend to do this like you through a Custom Activity after each set state activity - and understand I need to run it all in one transaction to keep the data consistent....

Many Thanks in advance - and I appreciate you haven't visited this article for a couple of years!
gravatar scott Thursday, November 26, 2009
Paul:

It has been a long time since I've done any work with WF, but this sounds to me like a problem with MSDTC. See: http://msdn.microsoft.com/en-us/library/aa349366(VS.85).aspx
gravatar Paul Butler Friday, November 27, 2009
Hi Scott

Thanks for coming back after 2 years! I can barely remember code I wrote a few weeks back :)

I read the suggested article - but feel the MSDTC settings are OK

The persistence and tracking is working fine together using the SharedConnectionWorkflowCommitWorkBatchService.

But the insertOrder method in the gateway freezes on the connection.Open() line. If I comment this method out - appart from the return everything works fine - except my order of course doesn't get created.. but I can see the persistence record created and removed as expected and all the tracking data is there afterwards..

I've read that when using the SharedConnectionWorkflowCommitWorkBatchService service DTC isn't used and this service only works with out of the box SQL tracking and Persistence services...

I found these comments from Joel West in this post:
social.msdn.microsoft.com/...

This suggests to me that I may not be able to do this insert within the same transaction - which is a real shame.

Because I'm running out of time and ideas - I think I'm going to have to do this insert outside of the workflow transaction - but this to me is dangerous and doesn't guarantee the data is in sync

Any other ideas or help would be appreciated

Thanks Again for coming back

Kind regards

Paul
gravatar Paul Butler Friday, November 27, 2009
Happy Days!!!

I now have this working - Scott you pointed me in the right direction - it was to do with MSDTC!

I had previously enabled the Network DTC Access on my Vista Client (checking both Allow Inbound and Allow Outbound) - I used the dcomcnfg.exe for this. But I hadn't done this on the remote SQL Server.

The reason the workflow was working OK for Persistence and Tracking - even though DTC was not configured on the SQL Server - was because they were using the SharedConnectionWorkflowCommitWorkBatchService - which apparently handles transactions without using DTC.

The InsertOrder method doesn't appear to work within the SharedConnectionWorkflowCommitWorkBatchService transactional scope - as explained before it just freezes on the connection.open() command

I commented out adding the SharedConnectionWorkflowCommitWorkBatchService in web.config - and now that DTC was configured correctly on the SQL Server - everything worked: Tracking / Persistence / Customer Activity doing DB update(s)/insert(s) - all within the same DTC transaction...

I'm happy it's working - but not sure of the performance issues with this approach as apparently there are benefits in using SharedConnectionWorkflowCommitWorkBatchService when hosting persistence and tracking on the same SQL DB

However, I'll live with this for now as it is doing what I want it to do

Thanks again for your assistance Scott

Kind regards

Paul
shiv Wednesday, January 20, 2010
hi i am using your code ,

it is working fine in my development server
when i have moved it to production server my application and database server are not in the domain i am getting following error

System.Runtime.InteropServices.COMException: Error HRESULT E_FAIL has been returned from a call to a COM component.



gravatar Scott Allen Thursday, January 21, 2010
Shiv: I don't know what could cause that error, sorry.
gravatar zhsu Friday, January 22, 2010
Hi, I have a wf application which is drived from your sample, but i run a problem when raise event and invoke manualworkflowschedulerservice's runworkflow method, it return false sometime and if you invoke it again it maybe success, i don't why
gravatar zhsu Friday, January 22, 2010
i have resolved the problem, thanks, ref: social.msdn.microsoft.com/...
Shiv Monday, February 1, 2010

hi scott

i am getting following eror

when my workflow is intiating
i getting at below line


if (workflowResults.Status != status)
{
if (workflowResults.Exception != null)
{
throw workflowResults.Exception;
}
else
{
string expected = status.ToString();
string actual = workflowResults.Status.ToString();
throw new InvalidOperationException(
String.Format("Workflow {0} expected status {1} actual status {2}",
workflowResults.InstanceId, expected, actual));
}
}



Stack Trace:


[COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component.]
System.Transactions.Oletx.IDtcProxyShimFactory.ReceiveTransaction(UInt32 propgationTokenSize, Byte[] propgationToken, IntPtr managedIdentifier, Guid& transactionIdentifier, OletxTransactionIsolationLevel& isolationLevel, ITransactionShim& transactionShim) +0
System.Transactions.TransactionInterop.GetOletxTransactionFromTransmitterPropigationToken(Byte[] propagationToken) +216

[TransactionManagerCommunicationException: Communication with the underlying transaction manager has failed.]
System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService.System.Workflow.Runtime.IPendingWork.Commit(Transaction transaction, ICollection items) +833
System.Workflow.Runtime.PendingWorkCollection.Commit(Transaction transaction) +158
System.Workflow.Runtime.WorkBatch.Commit(Transaction transaction) +58
System.Workflow.Runtime.VolatileResourceManager.Commit() +43
System.Workflow.Runtime.WorkflowExecutor.DoResourceManagerCommit() +23
System.Workflow.Runtime.Hosting.WorkflowCommitWorkBatchService.CommitWorkBatch(CommitWorkBatchCallback commitWorkBatchCallback) +265
System.Workflow.Runtime.Hosting.DefaultWorkflowCommitWorkBatchService.CommitWorkBatch(CommitWorkBatchCallback commitWorkBatchCallback) +267
System.Workflow.Runtime.WorkflowExecutor.CommitTransaction(Activity activityContext) +137
System.Workflow.Runtime.WorkflowExecutor.Persist(Activity dynamicActivity, Boolean unlock, Boolean needsCompensation) +528

[PersistenceException: Communication with the underlying transaction manager has failed.]
wfFiServices.FIService.VerifyResults(WorkflowResults workflowResults, WorkflowStatus status) in D:\WVS Solutions\WVS1\WVSShiv\WVSFI\wfFiServices\Service\FIService.cs:274
wfFiServices.FIService.WFIIntiated(Fi fi) in D:\WVS Solutions\WVS1\WVSShiv\WVSFI\wfFiServices\Service\FIService.cs:38
WebApplication1._Default.Button1_Click(Object sender, EventArgs e) in D:\WVS Solutions\WVS1\WVSShiv\WVSFI\WebApplication1\Default.aspx.cs:44
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +111
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +110
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1565



Scott Monday, February 1, 2010
Hi Shiv:

It's been a long time since I've worked with WF, but this sounds like a problem with MSDTC.

stackoverflow.com/...

Hope that helps,
gravatar Dzung, Ngo Anh Monday, May 10, 2010
Hi, is there any solution for using Delay activities with ManualScheduleSerice. I cannot receive the HttpContext with background thread.
gravatar Parag Friday, August 20, 2010
Hi Scott,

I am trying to use your code as a reference for developing the Workflow application. The application workflow is one member1 accepts then it goes to member2, if member2 accepts it goes to member3, if member3 rejects it should go to member2 and so on.... I checked your code but I am not getting when you are inserting the Order in the Database. You insert order code is in Commit method. Can you please help me to understand it??
gravatar olonga Monday, August 23, 2010
Scott:
Is it possible to directly ask the workflow runtime to obtain the Order object that is saved/persisted with the workflow instance? That way I don't have to save the order object with every state change..

Thanks,
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!