Josh Lane on .NET RSS 2.0
 Monday, October 01, 2007

ASP.NET as WF host is an important and useful scenario for WF adoption, but there are some interesting details that are worth understanding before you tackle this yourself.

The first thing to understand is that WF itself imposes no specific threading model; rather, it must be configured to conform to any specific threading requirements of its host process.  This means that WF can be hosted in a single-threaded console or WinForms app, and also can scale up to be hosted inside ASP.NET, with all of its multithreaded goodness (thankfully hidden under the covers from the average web developer).

But there's the rub... ASP.NET uses the .NET ThreadPool to dispatch request processing.  The default WF scheduler also uses the ThreadPool to execute individual workflows; in combination this would be bad, as it results in 2 ThreadPool threads consumed per web request.  What we need is a way to re-use the ASP.NET thread to also execute the workflow.

Enter ManualWorkflowSchedulerService.  As opposed to the DefaultWorkflowSchedulerService, the manual service grants explicit control over which thread is used to execute a given workflow.  Its usage is a bit goofy... there's an extra call to ManualWorkflowSchedulerService.StartWorkflow() that comes after calling Start() on the workflow object itself.  But it is the thread on which StartWorkflow() is invoked that executes the workflow... so, a necessary evil.

Okay, all of this is fine, and frankly already well documented.  The purpose of this post is to highlight a few subtleties.

When you create an instance of ManualWorkflowSchedulerService, you must specify whether you're using active timers, or not.  The idea here is that, for workflows that might go idle (as a result of DelayActivity, or any other activity that implements IEventActivity), the manual scheduler itself cannot know when to resume such workflows (as the default scheduler can do).  So you have two choices... choosing "active timers" means a separate thread will spin up, periodically check for expired activity wait timers, and resume workflows with expired timers.  Choosing "no active timers" means you must write extra code to check for expired timers, and manually resume them when necessary.

The primary issue with active timers is that, since two threads are now involved, it's not very difficult to create a race condition where your primary ASP.NET processing thread completes before the active timer thread wakes up your idled workflow and allows it to complete its work.  The resulting problems are implementation-specific, but not good regardless.

The way to solve this problem is naturally to use some sort of thread synchronization mechanism to ensure that the main ASP.NET thread waits on the active timer thread to restart your idled workflow.  See the sample code referenced at the end of this post for an illustration of the issue, and one potential solution using thread events.

An important observation here is that ManualWorkflowSchedulerService, used in this way, implies synchronous execution of workflows.  This is counter to the relative "fire-and-forget"-ness of the default scheduler.

On the other hand, if you don't use active timers with the manual scheduler, it is *your* responsibility to detect expired workflow timers, and to then resume the idled workflows (by calling WorkflowInstance.Resume() ).  This generally means spinning up your own secondary thread (might as well just use an active timer) or periodic polling from your main thread (ick).  Again, see the sample code for an illustration of the issue and one possible resolution.

A final note... given the synchronous nature of ASP.NET request processing (setting aside async ASP.NET handlers for the moment) I can't generally recommend the use of async activities in workflows used inside ASP.NET.  By all means, use WF to define processing logic for HTTP requests inside ASP.NET.  Just tread lightly with the use of DelayActivity, HandleExternalEventActivity, etc. inside such workflows.

Here's the sample code I refer to above, that illustrates what I'm describing here (requires VS.NET 2008 beta 2).

Enjoy!

Monday, October 01, 2007 1:07:42 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET | WF
 Friday, June 08, 2007

I couldn't help but chuckle at the installer for the WF-based ASP.NET Pageflow sample.  It first asked me for installation directory, etc. and THEN presented the software license page and asked for my consent.

Um, isn't that supposed to be the other way around?  Does the Pageflow installer need, well, better Pageflow???

NEVERTHELESS... interesting application of WF.  Might be useful on some stuff I happen to be working on right now, in fact.  I'm particularly interested in exploring the new NavigatorWorkflow base workflow type that drives the whole thing.  WF comes with support for sequential workflows as well as state machine-based flows; I knew the support for additional base types existed, but this is the first time I've seen it used in the wild (maybe MOSS 2007 workflows use a custom base type too?  Not sure...).

Been a long week... I'm a little punchy.  TGIF.  :-)

Friday, June 08, 2007 2:42:16 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET | WF
 Tuesday, January 23, 2007

I'm still mucking around with ASP.NET AJAX (get your 1.0 RTM bits here, y'all) and I needed a client-side "progressbar"-type thingie to display during AJAX postbacks. Note that I don't care much about "10% done... 20% done...", etc. I just wanted to give the user some visual indication that something's happening behind the scenes (especially since the entire page isn't visibly refreshing itself... this being the whole point of UpdatePanel and friends in the first place).

There are bazillions of Javascript progressbar implementations out there, but I wanted one that simply ping-pongs back and forth forever... that way you can show/hide it as needed in client-side code, to indicate background work of some sort.

I stumbled on Sahil Malik's implementation, which wasn't quite what I wanted, but close. He wrote a custom WebControl that allows you to specify percent complete and all that... so I modified it to do what I wanted instead.

For those who may not know, custom WebControls give you complete, well, control over their rendered output... so not only does the control emit the necessary HTML (just a table and a few columns, really) but it also emits the Javascript that does the animation. So the control is self-contained and pretty easy-to-use (IMHO).

Here's a demo, and here's the source. If you're using AJAX, try combining this with UpdatePanel, UpdateProgress and friends... pretty easy to achieve a decent user experience. Cheers.

Tuesday, January 23, 2007 5:55:16 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET | Javascript
 Wednesday, January 17, 2007

Note to self... when using <location> tags in your web.config file, like so:

 

<location path="SomeFile.aspx">
	<system.web>
		<authorization>
			<allow users="*"/>
		</authorization>
	</system.web>
</location>

DO NOT use root-relative paths (AKA "tilde" paths) to specify the path attribute value... otherwise you spend several hours trying to figure out why your location-specific configuration overrides aren't being honored at runtime.

Or so I've heard. <sigh>

Wednesday, January 17, 2007 9:30:16 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET
 Thursday, January 11, 2007

I've been digging into the ASP.NET AJAX bits over the last few days... impressive stuff. As a developer who will have his static typing pried from his cold dead fingers, I *especially* appreciate the high "enabled functionality per lines of hand-written Javascript" ratio.  :-)

As an aside, I know it's very trendy to fawn all over Ruby and Javascript and the like, and I appreciate the movement toward dynamic language-like features in C# 2.0/3.0. But there's still TONS of useful work being done in crusty ol' statically typed languages. Let's not burn our "Learn C++ in 7 Minutes" books just yet.

Well, okay... maybe *those* books. But you see my point.

Anyway... back to AJAX. There are several ways to utilize the framework; the easiest is to drop an UpdatePanel and ScriptManager on your ASP.NET page, then add some child controls to the UpdatePanel. You then have the ability to update these child controls without refreshing the entire page. Note that you still end up doing a server POST (via written-for-you Javascript) to refresh the state of those controls, but that same Javascript gets the results of the postback and modifies the browser DOM to update the child controls of the UpdatePanel with their new state. The effect is that portions of your page are updated without doing a full browser refresh. Slick.

Where this really gets interesting is that you can combine UpdatePanel with some interesting client-side animations to indicate to the user that updates are occuring/have occured. Again, the amount of Javascript you have to write is, in many cases, none!

As a test, I wanted to use the MultiView control to display views (groups of controls) on a page. I wanted view switching to not require a page refresh (meaning, use UpdatePanel), and I also wanted some sort of neato (read: annoying and distracting) animation effect to occur each time the user switches views.

Here's what I came up with.  Interestingly, the "fade out" effect doesn't seem to work very well from the server (worked fine locally on the ASP.NET dev webserver). Source is here (you'll need this and this along with .NET 2.0 to run it): 

I imagine this is all very pedestrian to the AJAX long-timers, but I thought it was cool.

Thursday, January 11, 2007 4:36:16 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
AJAX | ASP.NET
Disclaimer

Don't blame my employer(s)... all of this is my fault.

© Copyright 2008 Josh Lane
Sign In
Locations of visitors to this page
DasBlog theme 'Business' created by Christoph De Baene (delarou)