<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>There Must Be Some Mistake</title>
    <link>http://www.joshlane.net/blog/</link>
    <description>Josh Lane on .NET</description>
    <language>en-us</language>
    <copyright>Josh Lane</copyright>
    <lastBuildDate>Wed, 04 Jun 2008 18:45:54 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.7067.0</generator>
    <managingEditor>jplane@gmail.com</managingEditor>
    <webMaster>jplane@gmail.com</webMaster>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=28115fad-22dc-4e8b-8ca6-8c3e6c8da162</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,28115fad-22dc-4e8b-8ca6-8c3e6c8da162.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,28115fad-22dc-4e8b-8ca6-8c3e6c8da162.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=28115fad-22dc-4e8b-8ca6-8c3e6c8da162</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Task.ContinueWith() [Parallel Extensions June 2008 CTP]
</p>
        <p>
ActivityExecutionStatus.Executing + WorkflowQueue.QueueItemAvailable [Windows Workflow]
</p>
        <p>
(Almost) the same thing.
</p>
        <p>
That is all.
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=28115fad-22dc-4e8b-8ca6-8c3e6c8da162" />
      </body>
      <title>Mmmmmm... continuations</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,28115fad-22dc-4e8b-8ca6-8c3e6c8da162.aspx</guid>
      <link>http://www.joshlane.net/blog/MmmmmmContinuations.aspx</link>
      <pubDate>Wed, 04 Jun 2008 18:45:54 GMT</pubDate>
      <description>&lt;p&gt;
Task.ContinueWith() [Parallel Extensions June 2008 CTP]
&lt;/p&gt;
&lt;p&gt;
ActivityExecutionStatus.Executing + WorkflowQueue.QueueItemAvailable [Windows Workflow]
&lt;/p&gt;
&lt;p&gt;
(Almost) the same thing.
&lt;/p&gt;
&lt;p&gt;
That is all.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=28115fad-22dc-4e8b-8ca6-8c3e6c8da162" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,28115fad-22dc-4e8b-8ca6-8c3e6c8da162.aspx</comments>
      <category>Parallel Extensions</category>
      <category>WF</category>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=83f18a64-224b-4052-a35e-c13045b7be6a</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,83f18a64-224b-4052-a35e-c13045b7be6a.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,83f18a64-224b-4052-a35e-c13045b7be6a.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=83f18a64-224b-4052-a35e-c13045b7be6a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
My side project <a href="http://www.codeplex.com/TextFlow">TextFlow</a> is coming
along nicely... I've still got a lot of work to do there, but it's surprisingly functional
for something I've only been tinkering around with for a few weeks.
</p>
        <p>
TextFlow is (among other things) a language compiler that generates Windows Workflow
programs from a text-based language syntax. Those familiar with WF will know that
ordinarily you create WF programs from code, or using XAML. I like the idea of using
a language syntax as yet another means to define workflows... some potential workflow
authors will be comfortable neither with code or XAML; the graphical WF designer can
help here, but even that requires either Visual Studio, SharePoint Designer (which
has a crippled graphical workflow designer, and is SharePoint-specific to boot), or
you need to host the WF designer in your own app.
</p>
        <p>
WF is a somewhat under-utilized and misunderstood technology, IMO. There are several
reasons for this... confusion with Biztalk, lack of prescriptive guidance on implementing
systems using WF, the fact that once you get beyond the graphical designer the sexiness
factor goes way down (but that's precisely when a technology like WF starts to shine).
It's plumbing, and plumbing isn't very sexy.
</p>
        <p>
Another difficulty with WF adoption is audience. WF is plumbing, and is ideally used
to provide higher-order abstractions through which business users can express intent.
But those business users can't express their intent without the abstractions in place;
waiting for programmers to recognize this deficiency on their own and do something
about it is mostly a non-starter. You get what we have today... most higher-order
workflow logic is expressed as low-level control flow in languages like C# or Java.
Enter TextFlow.
</p>
        <p>
TextFlow is (hopefully) one example of these higher-order abstractions. It's intended
to be more approachable and business-user-friendly than writing .NET code (certainly)
or interacting with the workflow designer (hopefully). It's also intended to be more
powerful and general-purpose than the SharePoint Designer.
</p>
        <p>
As I've said, the key characteristic of TextFlow is that it compiles down to a WF
program, instead of a "raw" CLR assembly. What this means is that, when a TextFlow
program is compiled, the output is an in-memory .NET object graph that represents
the logical sequence of actions described by the original syntax. This in-memory graph
can be executed, serialized into XAML, or even displayed in the WF designer.
</p>
        <p>
So one obvious question is "why would you compile to WF, instead of the CLR itself?"
Great question!
</p>
        <h5>Advantages of compiling to WF
</h5>
        <ol>
          <li>
WF allows you to work at a higher level of abstraction when writing your compiler.
For example, control flow is built into WF via a set of pre-canned atomic elements
(activities); if your language syntax has looping or branching constructs (as most
will), its trivial to use <a href="http://msdn2.microsoft.com/en-us/library/ms735819(VS.85).aspx">WhileActivity</a> or <a href="http://msdn2.microsoft.com/en-us/library/ms734698(VS.85).aspx">IfElseActivity</a> (among
others) to realize these. To do the same in MSIL is entirely possible, but arguably
more difficult and tedious (though admittedly well documented). In effect, the WF
"opcodes" (activities) more directly translate to procedural language constructs than
do IL opcodes. 
</li>
          <li>
The CLR is a huge leap forward for language designers and compiler writers because
of the set of built-in services; garbage collection, a unified type system, a ubiquitous
security model, etc. Platforms can leverage these services instead of writing them
over and over again. The WF infrastructure leverages the basic CLR services, but also
provides an array of services above and beyond the CLR that are powerful and easily
leveraged from your own WF-targeting language: 
<ul><li>
inherent support for transactions and <a href="http://msdn2.microsoft.com/en-us/library/aa348712(VS.85).aspx?PHPSESSID=tn8k5p1s508cop8gr43e1f34d2">compensation</a></li><li>
inherent support for long-running workflows, where periods of inactivity (waiting
for human input, etc.) result in automatic serialization of the workflow to a persistent
store 
</li><li>
the ability for workflow execution to load-balance across multiple machines, so that
a single workflow instance might hop from machine to machine during its lifetime 
</li><li>
the ability to pause or cancel running workflows 
</li><li>
the ability to modify the inherent logic of a running workflow</li></ul></li>
          <li>
The extensibility model of WF is a big win for compiler writers, too. The atomic unit
of execution in WF is an Activity; there are <a href="http://msdn2.microsoft.com/en-us/magazine/cc163529.aspx">many
pre-defined Activities</a> shipped with WF, but it's trivial to create your own, too.
In essence, if you're writing a compiler that targets WF, you can extend the set of
opcodes that your compiler supports! Try that with MSIL! Another great thing about
this is that the built-in activities have no special significance to the WF runtime;
they don't leverage any "hidden" APIs that are unavailable to yours, etc.</li>
        </ol>
        <h5>Disadvantages of compiling to WF
</h5>
        <ol>
          <li>
WF doesn't offer much help if you want to expose a user-extensible type system from
your language. As I mentioned above, you can certainly create your own custom Activity
types and execute them in WF; but definition of your Activities is done via traditional
subclassing of the .NET Activity class. WF has no magical CreateNewActivityType()
method to help you here. So, WF is most appropriately targeted by procedural languages
where the emphasis is on control flow and sequences of actions, as opposed to more
pure OO-style languages (for the record, I think targeting WF with an OO language
is possible... you've just got more typing ahead of you :-) ).</li>
          <li>
I hesitate to mention this, because most obsessing over software performance is misguided
and misinformed... but it's true that WF will impose some performance tax on your
code, relative to execution of equivalent logic directly against the CLR. I have no
numbers to quote you (and wouldn't do it even if I did), but it stands to reason that
since WF is in essence a virtual machine running on the CLR, there will be some performance
penalty, even if small. That said... if you're launching the space shuttle or doing
DirectX 3D graphics, you probably shouldn't be running on WF anyway. For true workflow-style
programs that interact with external systems and (gasp!) actual users, whatever performance
penalty may exist is totally dwarfed by the benefits provided by the platform. If
your workflow program sends an email to a user and waits two weeks for a response
before then proceeding with execution, who cares if the email was sent in 50ms or
5 seconds???</li>
          <li>
One final thing to note... to truly take advantage of WF by compiling to it from your
language, you'll obviously need a firm grasp of the semantics and underpinnings of
the WF runtime and ancillary services. And since WF runs atop the CLR, you really
need a similar grasp of the basic CLR services, too. So in all fairness, the barrier
to entry isn't small; but neither is it insurmountable. In fact, I would venture to
say that if you're capable of designing a language and writing a compiler, then grokking
WF isn't going to seem like a big deal.</li>
        </ol>
        <p>
There's more to say, but that's a start. I highly recommend <a href="http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838">Essential
Windows Workflow Foundation</a> by Shukla and Schmidt as the definitive guide to WF
and its underpinnings.
</p>
        <p>
And if you're intrigued by any of this, I invite you to take a closer look at <a href="http://www.codeplex.com/TextFlow">TextFlow</a>...
let me know what you think!
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=83f18a64-224b-4052-a35e-c13045b7be6a" />
      </body>
      <title>Writing a Language Compiler - Why Target WF?</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,83f18a64-224b-4052-a35e-c13045b7be6a.aspx</guid>
      <link>http://www.joshlane.net/blog/WritingALanguageCompilerWhyTargetWF.aspx</link>
      <pubDate>Tue, 11 Mar 2008 13:24:17 GMT</pubDate>
      <description>&lt;p&gt;
My side project &lt;a href="http://www.codeplex.com/TextFlow"&gt;TextFlow&lt;/a&gt; is coming
along nicely... I've still got a lot of work to do there, but it's surprisingly functional
for something I've only been tinkering around with for a few weeks.
&lt;/p&gt;
&lt;p&gt;
TextFlow is (among other things) a language compiler that generates Windows Workflow
programs from a text-based language syntax. Those familiar with WF will know that
ordinarily you create WF programs from code, or using XAML. I like the idea of using
a language syntax as yet another means to define workflows... some potential workflow
authors will be comfortable neither with code or XAML; the graphical WF designer can
help here, but even that requires either Visual Studio, SharePoint Designer (which
has a crippled graphical workflow designer, and is SharePoint-specific to boot), or
you need to host the WF designer in your own app.
&lt;/p&gt;
&lt;p&gt;
WF is a somewhat under-utilized and misunderstood technology, IMO. There are several
reasons for this... confusion with Biztalk, lack of prescriptive guidance on implementing
systems using WF, the fact that once you get beyond the graphical designer the sexiness
factor goes way down (but that's precisely when a technology like WF starts to shine).
It's plumbing, and plumbing isn't very sexy.
&lt;/p&gt;
&lt;p&gt;
Another difficulty with WF adoption is audience. WF is plumbing, and is ideally used
to provide higher-order abstractions through which business users can express intent.
But those business users can't express their intent without the abstractions in place;
waiting for programmers to recognize this deficiency on their own and do something
about it is mostly a non-starter. You get what we have today... most higher-order
workflow logic is expressed as low-level control flow in languages like C# or Java.
Enter TextFlow.
&lt;/p&gt;
&lt;p&gt;
TextFlow is (hopefully) one example of these higher-order abstractions. It's intended
to be more approachable and business-user-friendly than writing .NET code (certainly)
or interacting with the workflow designer (hopefully). It's also intended to be more
powerful and general-purpose than the SharePoint Designer.
&lt;/p&gt;
&lt;p&gt;
As I've said, the key characteristic of TextFlow is that it compiles down to a WF
program, instead of a "raw" CLR assembly. What this means is that, when a TextFlow
program is compiled, the output is an in-memory .NET object graph that represents
the logical sequence of actions described by the original syntax. This in-memory graph
can be executed, serialized into XAML, or even displayed in the WF designer.
&lt;/p&gt;
&lt;p&gt;
So one obvious question is "why would you compile to WF, instead of the CLR itself?"
Great question!
&lt;/p&gt;
&lt;h5&gt;Advantages of compiling to WF
&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
WF allows you to work at a higher level of abstraction when writing your compiler.
For example, control flow is built into WF via a set of pre-canned atomic elements
(activities); if your language syntax has looping or branching constructs (as most
will), its trivial to use &lt;a href="http://msdn2.microsoft.com/en-us/library/ms735819(VS.85).aspx"&gt;WhileActivity&lt;/a&gt; or &lt;a href="http://msdn2.microsoft.com/en-us/library/ms734698(VS.85).aspx"&gt;IfElseActivity&lt;/a&gt; (among
others) to realize these. To do the same in MSIL is entirely possible, but arguably
more difficult and tedious (though admittedly well documented). In effect, the WF
"opcodes" (activities) more directly translate to procedural language constructs than
do IL opcodes. 
&lt;li&gt;
The CLR is a huge leap forward for language designers and compiler writers because
of the set of built-in services; garbage collection, a unified type system, a ubiquitous
security model, etc. Platforms can leverage these services instead of writing them
over and over again. The WF infrastructure leverages the basic CLR services, but also
provides an array of services above and beyond the CLR that are powerful and easily
leveraged from your own WF-targeting language: 
&lt;ul&gt;
&lt;li&gt;
inherent support for transactions and &lt;a href="http://msdn2.microsoft.com/en-us/library/aa348712(VS.85).aspx?PHPSESSID=tn8k5p1s508cop8gr43e1f34d2"&gt;compensation&lt;/a&gt; 
&lt;li&gt;
inherent support for long-running workflows, where periods of inactivity (waiting
for human input, etc.) result in automatic serialization of the workflow to a persistent
store 
&lt;li&gt;
the ability for workflow execution to load-balance across multiple machines, so that
a single workflow instance might hop from machine to machine during its lifetime 
&lt;li&gt;
the ability to pause or cancel running workflows 
&lt;li&gt;
the ability to modify the inherent logic of a running workflow&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;
The extensibility model of WF is a big win for compiler writers, too. The atomic unit
of execution in WF is an Activity; there are &lt;a href="http://msdn2.microsoft.com/en-us/magazine/cc163529.aspx"&gt;many
pre-defined Activities&lt;/a&gt; shipped with WF, but it's trivial to create your own, too.
In essence, if you're writing a compiler that targets WF, you can extend the set of
opcodes that your compiler supports! Try that with MSIL! Another great thing about
this is that the built-in activities have no special significance to the WF runtime;
they don't leverage any "hidden" APIs that are unavailable to yours, etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;Disadvantages of compiling to WF
&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
WF doesn't offer much help if you want to expose a user-extensible type system from
your language. As I mentioned above, you can certainly create your own custom Activity
types and execute them in WF; but definition of your Activities is done via traditional
subclassing of the .NET Activity class. WF has no magical CreateNewActivityType()
method to help you here. So, WF is most appropriately targeted by procedural languages
where the emphasis is on control flow and sequences of actions, as opposed to more
pure OO-style languages (for the record, I think targeting WF with an OO language
is possible... you've just got more typing ahead of you :-) ).&lt;/li&gt;
&lt;li&gt;
I hesitate to mention this, because most obsessing over software performance is misguided
and misinformed... but it's true that WF will impose some performance tax on your
code, relative to execution of equivalent logic directly against the CLR. I have no
numbers to quote you (and wouldn't do it even if I did), but it stands to reason that
since WF is in essence a virtual machine running on the CLR, there will be some performance
penalty, even if small. That said... if you're launching the space shuttle or doing
DirectX 3D graphics, you probably shouldn't be running on WF anyway. For true workflow-style
programs that interact with external systems and (gasp!) actual users, whatever performance
penalty may exist is totally dwarfed by the benefits provided by the platform. If
your workflow program sends an email to a user and waits two weeks for a response
before then proceeding with execution, who cares if the email was sent in 50ms or
5 seconds???&lt;/li&gt;
&lt;li&gt;
One final thing to note... to truly take advantage of WF by compiling to it from your
language, you'll obviously need a firm grasp of the semantics and underpinnings of
the WF runtime and ancillary services. And since WF runs atop the CLR, you really
need a similar grasp of the basic CLR services, too. So in all fairness, the barrier
to entry isn't small; but neither is it insurmountable. In fact, I would venture to
say that if you're capable of designing a language and writing a compiler, then grokking
WF isn't going to seem like a big deal.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
There's more to say, but that's a start. I highly recommend &lt;a href="http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838"&gt;Essential
Windows Workflow Foundation&lt;/a&gt; by Shukla and Schmidt as the definitive guide to WF
and its underpinnings.
&lt;/p&gt;
&lt;p&gt;
And if you're intrigued by any of this, I invite you to take a closer look at &lt;a href="http://www.codeplex.com/TextFlow"&gt;TextFlow&lt;/a&gt;...
let me know what you think!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=83f18a64-224b-4052-a35e-c13045b7be6a" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,83f18a64-224b-4052-a35e-c13045b7be6a.aspx</comments>
      <category>TextFlow</category>
      <category>WF</category>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=ee5e662d-4b4e-410a-9577-52415e916ab5</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,ee5e662d-4b4e-410a-9577-52415e916ab5.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,ee5e662d-4b4e-410a-9577-52415e916ab5.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=ee5e662d-4b4e-410a-9577-52415e916ab5</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Sad to see that <a href="http://blog.wired.com/underwire/2008/03/report-gary-gyg.html">Gary
Gygax has died</a>.
</p>
        <p>
Man, I gave many Sunday afternoons to <a href="http://en.wikipedia.org/wiki/Dungeons_&amp;_Dragons">D&amp;D</a> during
my formative years... Casey, Chris, Zoob, Pete, Kessel, and me had some fun times.
Then Pete got a girlfriend, and that was the beginning of the end.  :-D
</p>
        <p>
I played a few different characters over the course of several campaigns... but my
favorite has always been my first, Bandaar the dwarf fighter. Life was pretty simple
for Bandaar... ale good, battle axe good, orcs bad. He wasn't much of a talker, and
he certainly wasn't the shiniest gem in the pouch (8 for intelligence, around there
for wisdom, IIRC)... but we had good times, me and him.
</p>
        <p>
Here's to you, Gary. Thanks for the memories.
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=ee5e662d-4b4e-410a-9577-52415e916ab5" />
      </body>
      <title>Anyone Got a Wish Spell?</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,ee5e662d-4b4e-410a-9577-52415e916ab5.aspx</guid>
      <link>http://www.joshlane.net/blog/AnyoneGotAWishSpell.aspx</link>
      <pubDate>Wed, 05 Mar 2008 00:25:06 GMT</pubDate>
      <description>&lt;p&gt;
Sad to see that &lt;a href="http://blog.wired.com/underwire/2008/03/report-gary-gyg.html"&gt;Gary
Gygax has died&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Man, I gave many Sunday afternoons to &lt;a href="http://en.wikipedia.org/wiki/Dungeons_&amp;amp;_Dragons"&gt;D&amp;amp;D&lt;/a&gt; during
my formative years... Casey, Chris, Zoob, Pete, Kessel, and me had some fun times.
Then Pete got a girlfriend, and that was the beginning of the end.&amp;nbsp; :-D
&lt;/p&gt;
&lt;p&gt;
I played a few different characters over the course of several campaigns... but my
favorite has always been my first, Bandaar the dwarf fighter. Life was pretty simple
for Bandaar... ale good, battle axe good, orcs bad. He wasn't much of a talker, and
he certainly wasn't the shiniest gem in the pouch (8 for intelligence, around there
for wisdom, IIRC)... but we had good times, me and him.
&lt;/p&gt;
&lt;p&gt;
Here's to you, Gary. Thanks for the memories.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=ee5e662d-4b4e-410a-9577-52415e916ab5" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,ee5e662d-4b4e-410a-9577-52415e916ab5.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=8efac64a-52ec-4098-b1ba-4d0088c4699c</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,8efac64a-52ec-4098-b1ba-4d0088c4699c.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,8efac64a-52ec-4098-b1ba-4d0088c4699c.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=8efac64a-52ec-4098-b1ba-4d0088c4699c</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
My little side project is finally ready for others to poke around with:
</p>
        <p>
TextFlow - <a href="http://www.codeplex.com/TextFlow">www.codeplex.com/TextFlow</a></p>
        <p>
The main idea behind TextFlow is to allowing authoring of WF programs (workflows)
via a language syntax, as opposed to (or, eventually, in addition to) using the drag-and-drop
designer. The designer is great for many users, but there are times when a terse language
syntax would be useful too.
</p>
        <p>
Here's a (mostly) simple Hello World in TextFlow syntax:
</p>
        <p>
          <strong>SET x = 10</strong>
        </p>
        <p>
          <strong>INPARALLEL</strong>
        </p>
        <blockquote>
          <p>
            <strong>START IF x &gt; 100 THEN [HelloWorld] ENDIF END</strong>
          </p>
          <p>
            <strong>START IF x &lt; 100 THEN [GoodbyeWorld] ENDIF END</strong>
          </p>
          <p>
            <strong>
            </strong>
          </p>
        </blockquote>
        <p>
          <strong>ENDPARALLEL</strong>
        </p>
        <p>
This is a slightly gratuitous example that executes a WF ParallelActivity with two
IfElseActivity children; the square bracket syntax allows execution of configured
external activities (in this case, ones that simply display messages of some sort).
You get the idea. The actual generated workflow looks like this:
</p>
        <p>
          <a href="http://www.joshlane.net/blog/content/binary/WindowsLiveWriter/Presenting.TextFlow_13596/image_2.png">
            <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="226" alt="image" src="http://www.joshlane.net/blog/content/binary/WindowsLiveWriter/Presenting.TextFlow_13596/image_thumb.png" width="244" border="0" />
          </a>
        </p>
        <p>
The project includes an authoring tool that let's you toggle between syntax view and
workflow view; workflow view is read-only at this point, but I hope to enable bi-directional
updating eventually.
</p>
        <p>
The code is a definite work in progress... it's not much more than prototype quality
at this point. So don't expect to launch the space shuttle with it anytime soon, but
if you have an interest in any of the following, you might find something worth your
trouble:
</p>
        <p>
- using ANTLR-generated lexers and parsers in C# (if you've only ever used lex and
yacc, you need to see <a href="http://www.antlr.org/works">ANTLRWorks</a>)
</p>
        <p>
- hosting the WF designer in a WinForms app (not sure my code should be reference
material for this :-) )
</p>
        <p>
- a real-world use for .NET 3.5 expression trees (very cool stuff)
</p>
        <p>
I'll be blogging more on this in the coming weeks, as I continue to work on the code.
For further details, visit <a href="http://www.codeplex.com/TextFlow">www.codeplex.com/TextFlow</a>.
</p>
        <p>
Feedback is welcome and appreciated!
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=8efac64a-52ec-4098-b1ba-4d0088c4699c" />
      </body>
      <title>Presenting... TextFlow!</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,8efac64a-52ec-4098-b1ba-4d0088c4699c.aspx</guid>
      <link>http://www.joshlane.net/blog/PresentingTextFlow.aspx</link>
      <pubDate>Sat, 01 Mar 2008 04:03:02 GMT</pubDate>
      <description>&lt;p&gt;
My little side project is finally ready for others to poke around with:
&lt;/p&gt;
&lt;p&gt;
TextFlow - &lt;a href="http://www.codeplex.com/TextFlow"&gt;www.codeplex.com/TextFlow&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
The main idea behind TextFlow is to allowing authoring of WF programs (workflows)
via a language syntax, as opposed to (or, eventually, in addition to) using the drag-and-drop
designer. The designer is great for many users, but there are times when a terse language
syntax would be useful too.
&lt;/p&gt;
&lt;p&gt;
Here's a (mostly) simple Hello World in TextFlow syntax:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;SET x = 10&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;INPARALLEL&lt;/strong&gt;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;START IF x &amp;gt; 100 THEN [HelloWorld] ENDIF END&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;START IF x &amp;lt; 100 THEN [GoodbyeWorld] ENDIF END&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;ENDPARALLEL&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
This is a slightly gratuitous example that executes a WF ParallelActivity with two
IfElseActivity children; the square bracket syntax allows execution of configured
external activities (in this case, ones that simply display messages of some sort).
You get the idea. The actual generated workflow looks like this:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.joshlane.net/blog/content/binary/WindowsLiveWriter/Presenting.TextFlow_13596/image_2.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="226" alt="image" src="http://www.joshlane.net/blog/content/binary/WindowsLiveWriter/Presenting.TextFlow_13596/image_thumb.png" width="244" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
The project includes an authoring tool that let's you toggle between syntax view and
workflow view; workflow view is read-only at this point, but I hope to enable bi-directional
updating eventually.
&lt;/p&gt;
&lt;p&gt;
The code is a definite work in progress... it's not much more than prototype quality
at this point. So don't expect to launch the space shuttle with it anytime soon, but
if you have an interest in any of the following, you might find something worth your
trouble:
&lt;/p&gt;
&lt;p&gt;
- using ANTLR-generated lexers and parsers in C# (if you've only ever used lex and
yacc, you need to see &lt;a href="http://www.antlr.org/works"&gt;ANTLRWorks&lt;/a&gt;)
&lt;/p&gt;
&lt;p&gt;
- hosting the WF designer in a WinForms app (not sure my code should be reference
material for this :-) )
&lt;/p&gt;
&lt;p&gt;
- a real-world use for .NET 3.5 expression trees (very cool stuff)
&lt;/p&gt;
&lt;p&gt;
I'll be blogging more on this in the coming weeks, as I continue to work on the code.
For further details, visit &lt;a href="http://www.codeplex.com/TextFlow"&gt;www.codeplex.com/TextFlow&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Feedback is welcome and appreciated!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=8efac64a-52ec-4098-b1ba-4d0088c4699c" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,8efac64a-52ec-4098-b1ba-4d0088c4699c.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=fdaa0e7c-3e0c-4b57-aa94-7e8cab43cdb2</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,fdaa0e7c-3e0c-4b57-aa94-7e8cab43cdb2.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,fdaa0e7c-3e0c-4b57-aa94-7e8cab43cdb2.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=fdaa0e7c-3e0c-4b57-aa94-7e8cab43cdb2</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Several days ago I mentioned that I'm working on an idea that combines ANTLR and Windows
Workflow to demonstrate "business process authoring for analysts".
</p>
        <p>
In hindsight, that's a pretty bombastic thing to say. So instead, let's just say that
the tool I'm working on could be used by semi-technical folk to author executable
business processes. There are many other fine tools in this space; mine incorporates
a few (IMHO) clever ideas, but I'm not breaking any monumental new ground.
</p>
        <p>
I'm getting closer to having something for public consumption... I'm trying to walk
that line between making it solid enough for folks to actually use of it, without
crossing every T and dotting every I. I'm very eager for feedback and input, but I
want a minimal level of utility before it goes out the door.
</p>
        <p>
So if I've piqued your interest at all, stay tuned.
</p>
        <p>
Oh, and by the way... .NET 3.5 expression trees are FANTASTIC.  Except that they
don't serialize without writing your own surrogate. Bah.
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=fdaa0e7c-3e0c-4b57-aa94-7e8cab43cdb2" />
      </body>
      <title>Getting Closer...</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,fdaa0e7c-3e0c-4b57-aa94-7e8cab43cdb2.aspx</guid>
      <link>http://www.joshlane.net/blog/GettingCloser.aspx</link>
      <pubDate>Mon, 25 Feb 2008 03:43:31 GMT</pubDate>
      <description>&lt;p&gt;
Several days ago I mentioned that I'm working on an idea that combines ANTLR and Windows
Workflow to demonstrate "business process authoring for analysts".
&lt;/p&gt;
&lt;p&gt;
In hindsight, that's a pretty bombastic thing to say. So instead, let's just say that
the tool I'm working on could be used by semi-technical folk to author executable
business processes. There are many other fine tools in this space; mine incorporates
a few (IMHO) clever ideas, but I'm not breaking any monumental new ground.
&lt;/p&gt;
&lt;p&gt;
I'm getting closer to having something for public consumption... I'm trying to walk
that line between making it solid enough for folks to actually use of it, without
crossing every T and dotting every I. I'm very eager for feedback and input, but I
want a minimal level of utility before it goes out the door.
&lt;/p&gt;
&lt;p&gt;
So if I've piqued your interest at all, stay tuned.
&lt;/p&gt;
&lt;p&gt;
Oh, and by the way... .NET 3.5 expression trees are FANTASTIC.&amp;nbsp; Except that they
don't serialize without writing your own surrogate. Bah.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=fdaa0e7c-3e0c-4b57-aa94-7e8cab43cdb2" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,fdaa0e7c-3e0c-4b57-aa94-7e8cab43cdb2.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=adf798c4-9aec-494e-9524-ed710d9e13e5</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,adf798c4-9aec-494e-9524-ed710d9e13e5.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,adf798c4-9aec-494e-9524-ed710d9e13e5.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=adf798c4-9aec-494e-9524-ed710d9e13e5</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In the interest of not scaring off employers of both the "current" and "potential
future" variety, it's perhaps useful for me to follow up and clarify my comments originally
made <a href="http://www.joshlane.net/blog/InterestingTakeOnCodeReuse.aspx">here</a>. 
:-)
</p>
        <p>
In general, I meant what I said... code reuse is usually more trouble than it's worth.
Usually, you're better off not trying too hard to make it work, because you'll probably
fail, and waste a lot of time. Even if you're smart, and certainly if you're not.
</p>
        <p>
I come by this point of view honestly... I've personally failed more often than not
in trying to build "The One Reusable API to Rule Them All". I don't think it's a big
secret that most others fail at this, too. I like to think I've gotten better as I've
aged... but it's still a tough nut to crack.
</p>
        <p>
IMO, the characteristic most often desired in "software that shall be reusable" is
FLEXIBILITY. Truly flexible code that is widely applicable across multiple disparate
problem domains is a thing of beauty... and extremely rare. The fact that any such
code exists isn't the telling point; the fact that it represents an infinitesimally
small percentage of all code ever written is.
</p>
        <p>
Most "flexible" code I've personally witnessed was anything but. I've concluded that
flexibility (and the goal of wide-scale reuse) is wildly overestimated as a desirable
(and achievable) code characteristic for most classes of software.
</p>
        <p>
So I say all this to say, reusable software is hard. It has instant sex appeal for
non-technical manager types (which makes it even more dangerous), which is probably
one reason it perpetuates. And certainly, there exist many fine counter-examples in
the wild (none of this really applies to SDK vendors, obviously).
</p>
        <p>
But I think the world would be a better place if we software types focused on building
for today, and not For All Time To Come. Try it, and use your extra free time to read
up on refactoring and test-driven development... there's your flexibility, cowboy. 
:-)
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=adf798c4-9aec-494e-9524-ed710d9e13e5" />
      </body>
      <title>Errata</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,adf798c4-9aec-494e-9524-ed710d9e13e5.aspx</guid>
      <link>http://www.joshlane.net/blog/Errata.aspx</link>
      <pubDate>Sat, 16 Feb 2008 22:33:05 GMT</pubDate>
      <description>&lt;p&gt;
In the interest of not scaring off employers of both the "current" and "potential
future" variety, it's perhaps useful for me to follow up and clarify my comments originally
made &lt;a href="http://www.joshlane.net/blog/InterestingTakeOnCodeReuse.aspx"&gt;here&lt;/a&gt;.&amp;nbsp;
:-)
&lt;/p&gt;
&lt;p&gt;
In general, I meant what I said... code reuse is usually more trouble than it's worth.
Usually, you're better off not trying too hard to make it work, because you'll probably
fail, and waste a lot of time. Even if you're smart, and certainly if you're not.
&lt;/p&gt;
&lt;p&gt;
I come by this point of view honestly... I've personally failed more often than not
in trying to build "The One Reusable API to Rule Them All". I don't think it's a big
secret that most others fail at this, too. I like to think I've gotten better as I've
aged... but it's still a tough nut to crack.
&lt;/p&gt;
&lt;p&gt;
IMO, the characteristic most often desired in "software that shall be reusable" is
FLEXIBILITY. Truly flexible code that is widely applicable across multiple disparate
problem domains is a thing of beauty... and extremely rare. The fact that any such
code exists isn't the telling point; the fact that it represents an infinitesimally
small percentage of all code ever written is.
&lt;/p&gt;
&lt;p&gt;
Most "flexible" code I've personally witnessed was anything but. I've concluded that
flexibility (and the goal of wide-scale reuse) is wildly overestimated as a desirable
(and achievable) code characteristic for most classes of software.
&lt;/p&gt;
&lt;p&gt;
So I say all this to say, reusable software is hard. It has instant sex appeal for
non-technical manager types (which makes it even more dangerous), which is probably
one reason it perpetuates. And certainly, there exist many fine counter-examples in
the wild (none of this really applies to SDK vendors, obviously).
&lt;/p&gt;
&lt;p&gt;
But I think the world would be a better place if we software types focused on building
for today, and not For All Time To Come. Try it, and use your extra free time to read
up on refactoring and test-driven development... there's your flexibility, cowboy.&amp;nbsp;
:-)
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=adf798c4-9aec-494e-9524-ed710d9e13e5" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,adf798c4-9aec-494e-9524-ed710d9e13e5.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=62351442-f739-4d3f-bc90-f88ebabf51ae</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,62351442-f739-4d3f-bc90-f88ebabf51ae.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,62351442-f739-4d3f-bc90-f88ebabf51ae.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=62351442-f739-4d3f-bc90-f88ebabf51ae</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I understand that "sorry it's been awhile since I posted on my blog" posts are considered
bad form by the blogging elite... oh well.
</p>
        <p>
I started a new job last October, working <a href="http://www.inrule.com">here</a>.
Very interesting company, very interesting work (rules engine technology)... but they
were quite eager to throw me immediately into the deep end of the pool, so I haven't
had time for much of anything since I started. Just now starting to find some energy
for endeavors beyond, like this blog.
</p>
        <p>
I've got an interesting new project idea percolating... I'll be posting more on that
very soon. I also hope to have a <a href="http://www.codeplex.com">CodePlex</a> project
up soon with some prototype code.
</p>
        <p>
As a teaser, think <a href="http://www.antlr.org">ANTLR</a> + <a href="http://netfx3.com/content/WFHome.aspx">Windows
Workflow</a> = "business process authoring for analysts".
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=62351442-f739-4d3f-bc90-f88ebabf51ae" />
      </body>
      <title>Coming Up For Air</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,62351442-f739-4d3f-bc90-f88ebabf51ae.aspx</guid>
      <link>http://www.joshlane.net/blog/ComingUpForAir.aspx</link>
      <pubDate>Sat, 16 Feb 2008 19:04:10 GMT</pubDate>
      <description>&lt;p&gt;
I understand that "sorry it's been awhile since I posted on my blog" posts are considered
bad form by the blogging elite... oh well.
&lt;/p&gt;
&lt;p&gt;
I started a new job last October, working &lt;a href="http://www.inrule.com"&gt;here&lt;/a&gt;.
Very interesting company, very interesting work (rules engine technology)... but they
were quite eager to throw me immediately into the deep end of the pool, so I haven't
had time for much of anything since I started. Just now starting to find some energy
for endeavors beyond, like this blog.
&lt;/p&gt;
&lt;p&gt;
I've got an interesting new project idea percolating... I'll be posting more on that
very soon. I also hope to have a &lt;a href="http://www.codeplex.com"&gt;CodePlex&lt;/a&gt; project
up soon with some prototype code.
&lt;/p&gt;
&lt;p&gt;
As a teaser, think &lt;a href="http://www.antlr.org"&gt;ANTLR&lt;/a&gt; + &lt;a href="http://netfx3.com/content/WFHome.aspx"&gt;Windows
Workflow&lt;/a&gt; = "business process authoring for analysts".
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=62351442-f739-4d3f-bc90-f88ebabf51ae" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,62351442-f739-4d3f-bc90-f88ebabf51ae.aspx</comments>
      <category>WF</category>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=c662f27b-f36f-4dc7-96e4-89914a5fda6c</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,c662f27b-f36f-4dc7-96e4-89914a5fda6c.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,c662f27b-f36f-4dc7-96e4-89914a5fda6c.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c662f27b-f36f-4dc7-96e4-89914a5fda6c</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
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.
</p>
        <p>
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).
</p>
        <p>
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.
</p>
        <p>
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.
</p>
        <p>
Okay, all of this is fine, and frankly already <a href="http://msdn2.microsoft.com/en-us/library/aa349445.aspx">well</a><a href="http://msdn2.microsoft.com/en-us/library/aa349374.aspx">documented</a>. 
The purpose of this post is to highlight a few subtleties.
</p>
        <p>
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.
</p>
        <p>
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.
</p>
        <p>
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.
</p>
        <p>
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.
</p>
        <p>
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.
</p>
        <p>
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.
</p>
        <p>
          <a href="http://www.joshlane.net/public/wfandasp.net.zip">Here's</a> the sample code
I refer to above, that illustrates what I'm describing here (requires VS.NET 2008
beta 2).
</p>
        <p>
Enjoy!
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=c662f27b-f36f-4dc7-96e4-89914a5fda6c" />
      </body>
      <title>WF and ASP.NET - A Few Gotchas</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,c662f27b-f36f-4dc7-96e4-89914a5fda6c.aspx</guid>
      <link>http://www.joshlane.net/blog/WFAndASPNETAFewGotchas.aspx</link>
      <pubDate>Mon, 01 Oct 2007 18:07:42 GMT</pubDate>
      <description>&lt;p&gt;
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.
&lt;/p&gt;
&lt;p&gt;
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.&amp;nbsp; 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).
&lt;/p&gt;
&lt;p&gt;
But there's the rub... ASP.NET uses the .NET ThreadPool to dispatch request processing.&amp;nbsp;
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.&amp;nbsp; What we need is a way to re-use the ASP.NET thread to also execute
the workflow.
&lt;/p&gt;
&lt;p&gt;
Enter ManualWorkflowSchedulerService.&amp;nbsp; As opposed to the DefaultWorkflowSchedulerService,
the manual service grants explicit control over which thread is used to execute a
given workflow.&amp;nbsp; Its usage is a bit goofy... there's an extra call to ManualWorkflowSchedulerService.StartWorkflow()
that comes after calling Start() on the workflow object itself.&amp;nbsp; But it is the
thread on which StartWorkflow() is invoked that executes the workflow... so, a necessary
evil.
&lt;/p&gt;
&lt;p&gt;
Okay, all of this is fine, and frankly already &lt;a href="http://msdn2.microsoft.com/en-us/library/aa349445.aspx"&gt;well&lt;/a&gt; &lt;a href="http://msdn2.microsoft.com/en-us/library/aa349374.aspx"&gt;documented&lt;/a&gt;.&amp;nbsp;
The purpose of this post is to highlight a few subtleties.
&lt;/p&gt;
&lt;p&gt;
When you create an instance of ManualWorkflowSchedulerService, you must specify whether
you're using active timers, or not.&amp;nbsp; 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).&amp;nbsp; 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.&amp;nbsp; Choosing "no active timers"
means you must write extra code to check for expired timers, and manually resume them
when necessary.
&lt;/p&gt;
&lt;p&gt;
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.&amp;nbsp; The resulting problems&amp;nbsp;are implementation-specific,
but not good regardless.
&lt;/p&gt;
&lt;p&gt;
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.&amp;nbsp; See the sample code referenced at the end of
this post for an illustration of the issue, and one potential solution using thread
events.
&lt;/p&gt;
&lt;p&gt;
An important observation here is that ManualWorkflowSchedulerService, used in this
way, implies synchronous execution of workflows.&amp;nbsp; This is counter to the relative
"fire-and-forget"-ness of the default scheduler.
&lt;/p&gt;
&lt;p&gt;
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() ).&amp;nbsp; 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).&amp;nbsp; Again, see the sample code for an illustration
of the issue and one possible resolution.
&lt;/p&gt;
&lt;p&gt;
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.&amp;nbsp; By all means, use WF to define
processing logic for HTTP requests inside ASP.NET.&amp;nbsp; Just tread lightly with the
use of DelayActivity, HandleExternalEventActivity, etc. inside such workflows.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.joshlane.net/public/wfandasp.net.zip"&gt;Here's&lt;/a&gt; the sample code
I refer to above, that illustrates what I'm describing here (requires VS.NET 2008
beta 2).
&lt;/p&gt;
&lt;p&gt;
Enjoy!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=c662f27b-f36f-4dc7-96e4-89914a5fda6c" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,c662f27b-f36f-4dc7-96e4-89914a5fda6c.aspx</comments>
      <category>ASP.NET</category>
      <category>WF</category>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=85369993-c903-4953-a9f1-13c5b297e6f4</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,85369993-c903-4953-a9f1-13c5b297e6f4.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,85369993-c903-4953-a9f1-13c5b297e6f4.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=85369993-c903-4953-a9f1-13c5b297e6f4</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">
            <a href="http://www.infoq.com/news/2007/07/worthless-code">http://www.infoq.com/news/2007/07/worthless-code</a>
          </span>
        </p>
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">This parallels
my general take on code reuse...</span>
        </p>
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">
            <strong>Josh's
1st Axiom of Code Reuse</strong>
          </span>
        </p>
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">In order to be
reusable, code must first be good.  Since most code is not good, most code is
not reusable.  This means you.</span>
        </p>
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">
            <strong>Josh's
2nd Axiom of Code Reuse</strong>
          </span>
        </p>
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">Most of the time,
idea reuse is infinitely more beneficial and productive than code reuse.</span>
        </p>
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">
            <strong>Josh's
3rd Axiom of Code Reuse</strong>
          </span>
        </p>
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">Most of the time,
don't bother... it's not worth the trouble.<br /></span>
        </p>
        <p>
          <span style="font-size: 11pt; font-family: 'Calibri','sans-serif';">
          </span> 
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=85369993-c903-4953-a9f1-13c5b297e6f4" />
      </body>
      <title>Interesting take on code reuse...</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,85369993-c903-4953-a9f1-13c5b297e6f4.aspx</guid>
      <link>http://www.joshlane.net/blog/InterestingTakeOnCodeReuse.aspx</link>
      <pubDate>Wed, 25 Jul 2007 15:56:59 GMT</pubDate>
      <description>&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;&lt;a href="http://www.infoq.com/news/2007/07/worthless-code"&gt;http://www.infoq.com/news/2007/07/worthless-code&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;This parallels
my general take on code reuse...&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;&lt;strong&gt;Josh's
1st Axiom of Code Reuse&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;In order to be
reusable, code must first be good.&amp;nbsp; Since most code is not good, most code is
not reusable.&amp;nbsp; This means you.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;&lt;strong&gt;Josh's
2nd Axiom of Code Reuse&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;Most of the time,
idea reuse is infinitely more beneficial and productive than code reuse.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;&lt;strong&gt;Josh's
3rd Axiom of Code Reuse&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;Most of the time,
don't bother... it's not worth the trouble.&lt;br&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-size: 11pt; font-family: 'Calibri','sans-serif';"&gt;&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=85369993-c903-4953-a9f1-13c5b297e6f4" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,85369993-c903-4953-a9f1-13c5b297e6f4.aspx</comments>
      <category>Programming</category>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=be02d6fb-56d4-440e-a231-d096880cd094</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,be02d6fb-56d4-440e-a231-d096880cd094.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,be02d6fb-56d4-440e-a231-d096880cd094.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=be02d6fb-56d4-440e-a231-d096880cd094</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
...and it's incredible.
</p>
        <p>
          <a title="http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/ref=pd_bbs_sr_2/104-2057410-5880735?ie=UTF8&amp;s=books&amp;qid=1183209452&amp;sr=8-2" href="http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/ref=pd_bbs_sr_2/104-2057410-5880735?ie=UTF8&amp;s=books&amp;qid=1183209452&amp;sr=8-2">http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/ref=pd_bbs_sr_2/104-2057410-5880735?ie=UTF8&amp;s=books&amp;qid=1183209452&amp;sr=8-2</a>
        </p>
        <p>
A few Amazon reviewers poo-poo it for being too esoteric and not dealing with "how
to get work done in WF", or something.  This is definitely not a WF cookbook. 
But the explanations behind bookmarking and continuations as the underpinnings of
the WF architecture are fabulous.  Quite simply, if you don't understand
this stuff, you don't understand WF.
</p>
        <p>
The more I dig into this technology, the more fascinated I am.  The service model,
the support for arbitrary execution semantics (but lack of preference for any baked-in
ones), the multiple abstraction levels at which you can participate, the simplicity
and yet power of the bookmark metaphor... it's really excellent stuff.
</p>
        <p>
If you have even a casual interest in "next generation programming models" (as the
tagline goes), read this book.
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=be02d6fb-56d4-440e-a231-d096880cd094" />
      </body>
      <title>Reading 'Essential Windows Workflow Foundation'...</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,be02d6fb-56d4-440e-a231-d096880cd094.aspx</guid>
      <link>http://www.joshlane.net/blog/ReadingEssentialWindowsWorkflowFoundation.aspx</link>
      <pubDate>Sat, 30 Jun 2007 13:33:31 GMT</pubDate>
      <description>&lt;p&gt;
...and it's incredible.
&lt;/p&gt;
&lt;p&gt;
&lt;a title="http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/ref=pd_bbs_sr_2/104-2057410-5880735?ie=UTF8&amp;amp;s=books&amp;amp;qid=1183209452&amp;amp;sr=8-2" href="http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/ref=pd_bbs_sr_2/104-2057410-5880735?ie=UTF8&amp;amp;s=books&amp;amp;qid=1183209452&amp;amp;sr=8-2"&gt;http://www.amazon.com/Essential-Workflow-Foundation-Microsoft-Development/dp/0321399838/ref=pd_bbs_sr_2/104-2057410-5880735?ie=UTF8&amp;amp;s=books&amp;amp;qid=1183209452&amp;amp;sr=8-2&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
A few Amazon reviewers poo-poo it for being too esoteric and not dealing with "how
to get work done in WF", or something.&amp;nbsp; This is definitely not a WF cookbook.&amp;nbsp;
But the explanations behind bookmarking and continuations as the underpinnings of
the WF architecture are fabulous.&amp;nbsp; Quite simply, if you don't&amp;nbsp;understand
this stuff, you don't&amp;nbsp;understand WF.
&lt;/p&gt;
&lt;p&gt;
The more I dig into this technology, the more fascinated I am.&amp;nbsp; The service model,
the support for arbitrary execution semantics (but lack of preference for any baked-in
ones), the multiple abstraction levels at which you can participate, the simplicity
and yet power of the bookmark metaphor... it's really excellent stuff.
&lt;/p&gt;
&lt;p&gt;
If you have even a casual interest in "next generation programming models" (as the
tagline goes), read this book.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=be02d6fb-56d4-440e-a231-d096880cd094" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,be02d6fb-56d4-440e-a231-d096880cd094.aspx</comments>
      <category>WF</category>
    </item>
    <item>
      <trackback:ping>http://www.joshlane.net/blog/Trackback.aspx?guid=786a8c6d-5964-4f67-8b73-e3e5450b1c0e</trackback:ping>
      <pingback:server>http://www.joshlane.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.joshlane.net/blog/PermaLink,guid,786a8c6d-5964-4f67-8b73-e3e5450b1c0e.aspx</pingback:target>
      <dc:creator>Josh</dc:creator>
      <wfw:comment>http://www.joshlane.net/blog/CommentView,guid,786a8c6d-5964-4f67-8b73-e3e5450b1c0e.aspx</wfw:comment>
      <wfw:commentRss>http://www.joshlane.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=786a8c6d-5964-4f67-8b73-e3e5450b1c0e</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Well now, this was a fine how-do-you-do on a Wednesday morning...
</p>
        <p>
          <a title="http://footheory.com/blogs/bennie/archive/2007/05/12/simple-application-extensibility-with-wf-rules.aspx" href="http://footheory.com/blogs/bennie/archive/2007/05/12/simple-application-extensibility-with-wf-rules.aspx">http://footheory.com/blogs/bennie/archive/2007/05/12/simple-application-extensibility-with-wf-rules.aspx</a>
        </p>
        <p>
Holy cow!  Turns out the rules engine that ships with WF is usable in your own
application, even if you're not using workflows at all!  This is incredibly cool. 
A little background for the uninitiated...
</p>
        <p>
          <a href="http://wf.netfx3.com/">Windows Workflow</a> is a technology that
ships with <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;displaylang=en">.NET
3.0</a>.  It enables you to express program logic and control flow visually,
in what looks a bit like a Visio diagram.  It directly enables things like <a href="http://odetocode.com/Blogs/scott/archive/2006/05/23/3675.aspx">continuations</a> and <a href="http://blogs.msdn.com/advancedworkflow/archive/2006/05/19/602116.aspx">passivation</a> in
your software.  It is, in general, a Very Big Deal... though it usually plays
second fiddle to <a href="http://wpf.netfx3.com/">WPF</a> and <a href="http://wcf.netfx3.com/">WCF</a> when
folks start discussing .NET 3.0.
</p>
        <p>
One of the features of WF is a business rules engine that can be used to author
and execute rules against workflows in your application.  The rules work against
internal workflow state, and produce side effects during execution to modify that
state in some meaningful way.  For example, your workflow might expose properties
such as AccountName or OrderAmount, so a simple rule might be (in pseudo-code):
</p>
        <p>
if this.OrderAmount &gt; 100
</p>
        <p>
then this.Discount = 10%
</p>
        <p>
else this.Discount = 0%
</p>
        <p>
The idea is that you express such rules out-of-band from your code, which provides
really nice maintenance and visibility benefits.  Since rules tend to be the
core value of a software system, they're best not buried inside layer after
layer of C# code where only a programmer can maintain them.
</p>
        <p>
You get an out-of-the-box editor with Intellisense for rule authoring.  In addition,
there are standard hooks in WF (through the use of <a href="http://msdn2.microsoft.com/en-us/library/ms733605.aspx">PolicyActivity</a>,
typically) for invoking the rules at runtime.  This all works great assuming
you're authoring and using workflows in your application.
</p>
        <p>
Okay... so here's the neat part.  You can use this rules engine even if you aren't
using workflows.  There's a great <a href="http://wf.netfx3.com/files/folders/rules_samples/entry309.aspx">sample</a> on
the WF community site that demonstrates how to re-host the rules designer in your
own application, as well as how to use alternate storage mechanisms for rules (by
default, rules are saved to a file in your workflow project, and the file is compiled
as a resource).  But, that code is still relying on workflows and custom
policy activities to execute rules.  So the code from this sample is used in
the other sample found at the link I mentioned at the top of this post to demonstrate <em>rule
execution without workflow involved at all</em>.  I also re-purposed the base sample
code to whip up my own demo app.
</p>
        <p>
Here's a screenshot of rule authoring against my own "User" type (which has properties
like Name and Age):
</p>
        <p>
          <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="708" alt="image" src="http://www.joshlane.net/blog/PostImages/WindowsWorkflowRu.WithoutWindowsWorkflow_149D9/image.png" width="852" border="0" />
        </p>
        <p>
Notice the full Intellisense support for my custom type... this makes rule editing
a breeze.
</p>
        <p>
Once you edit and save your rules (storage is just a single table in the SQL
database of your choice), you can then reference the rules (sets of rules, actually) by
name at runtime, for execution.  Here's a code snippet:
</p>
        <div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
          <div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #008000">//
create my user object...</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">User joe = <span style="color: #0000ff">new</span> User();</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">joe.Name = <span style="color: #006080">"Joe"</span>;</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">joe.Age = 35;</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">joe.Valid = <span style="color: #0000ff">false</span>;</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #008000">//
next several lines execute the ruleset called "User2"...</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">RuleSetService svc = <span style="color: #0000ff">new</span> RuleSetService();</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">RuleSet ruleset = svc.GetRuleSet( <span style="color: #0000ff">new</span> RuleSetInfo( <span style="color: #006080">"User2"</span> )
);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">RuleExecution exec</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    = <span style="color: #0000ff">new</span> RuleExecution( <span style="color: #0000ff">new</span> RuleValidation(
joe.GetType(), <span style="color: #0000ff">null</span> ), joe );</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">ruleset.Execute( exec );</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #008000">//
okay, ruleset has executed, let's see what the outcome is...</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">Console.WriteLine( joe.Valid.ToString() );</pre>
          </div>
        </div>
        <p>
And that's it... about 4 lines of code to invoke a ruleset at runtime.  And again...
no workflow in sight.  Not that I have anything against workflows, it's just
nice to know you can use the rules engine by itself if/when needed.
</p>
        <p>
I've uploaded my own sample application <a href="http://www.joshlane.net/blog/code/WFRulesWithoutWorkflow.zip">here</a>. 
Grab it, unzip, restore the database backup, check your config file connection strings,
and party on.  There are 5 VS.NET 2005 projects included... 4 of them are modified
versions of the code found in the previously mentioned WF community site sample, the
other (called "Tester") is my own sample that exercises some rules I created through
the designer.  So just to be clear... most of this is not my own code. 
But that also speaks to the beauty of this approach... most of the heavy lifting is
done for us already, so it's easy to get up and running.
</p>
        <p>
Enjoy!
</p>
        <img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=786a8c6d-5964-4f67-8b73-e3e5450b1c0e" />
      </body>
      <title>Windows Workflow Rules Engine... Without Windows Workflow!</title>
      <guid isPermaLink="false">http://www.joshlane.net/blog/PermaLink,guid,786a8c6d-5964-4f67-8b73-e3e5450b1c0e.aspx</guid>
      <link>http://www.joshlane.net/blog/WindowsWorkflowRulesEngineWithoutWindowsWorkflow.aspx</link>
      <pubDate>Thu, 21 Jun 2007 05:05:22 GMT</pubDate>
      <description>&lt;p&gt;
Well now, this was a fine how-do-you-do on a Wednesday morning...
&lt;/p&gt;
&lt;p&gt;
&lt;a title="http://footheory.com/blogs/bennie/archive/2007/05/12/simple-application-extensibility-with-wf-rules.aspx" href="http://footheory.com/blogs/bennie/archive/2007/05/12/simple-application-extensibility-with-wf-rules.aspx"&gt;http://footheory.com/blogs/bennie/archive/2007/05/12/simple-application-extensibility-with-wf-rules.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Holy cow!&amp;nbsp; Turns out the rules engine that ships with WF is usable in your own
application, even if you're not using workflows at all!&amp;nbsp; This is incredibly cool.&amp;nbsp;
A little background for the uninitiated...
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://wf.netfx3.com/"&gt;Windows Workflow&lt;/a&gt;&amp;nbsp;is a&amp;nbsp;technology that
ships with &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=10CC340B-F857-4A14-83F5-25634C3BF043&amp;amp;displaylang=en"&gt;.NET
3.0&lt;/a&gt;.&amp;nbsp; It enables you to express program logic and control flow visually,
in what looks a bit like a Visio diagram.&amp;nbsp; It directly enables things like &lt;a href="http://odetocode.com/Blogs/scott/archive/2006/05/23/3675.aspx"&gt;continuations&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/advancedworkflow/archive/2006/05/19/602116.aspx"&gt;passivation&lt;/a&gt; in
your software.&amp;nbsp; It is, in general, a Very Big Deal... though it&amp;nbsp;usually&amp;nbsp;plays
second fiddle to &lt;a href="http://wpf.netfx3.com/"&gt;WPF&lt;/a&gt; and &lt;a href="http://wcf.netfx3.com/"&gt;WCF&lt;/a&gt; when
folks start discussing .NET 3.0.
&lt;/p&gt;
&lt;p&gt;
One of the&amp;nbsp;features of WF is a business rules engine that can be used to author
and execute rules against workflows in your application.&amp;nbsp; The rules work against
internal workflow state, and produce side effects during execution to modify that
state in some meaningful way.&amp;nbsp; For example, your workflow might expose properties
such as AccountName or OrderAmount, so a simple rule might be (in pseudo-code):
&lt;/p&gt;
&lt;p&gt;
if this.OrderAmount &amp;gt; 100
&lt;/p&gt;
&lt;p&gt;
then this.Discount = 10%
&lt;/p&gt;
&lt;p&gt;
else this.Discount = 0%
&lt;/p&gt;
&lt;p&gt;
The idea is that you express such rules out-of-band from your code, which provides
really nice maintenance and visibility benefits.&amp;nbsp; Since rules tend to be the
core value of a software system,&amp;nbsp;they're best not buried&amp;nbsp;inside layer after
layer of C# code where only a programmer can maintain them.
&lt;/p&gt;
&lt;p&gt;
You get an out-of-the-box editor with Intellisense for rule authoring.&amp;nbsp; In addition,
there are standard hooks in WF (through the use of &lt;a href="http://msdn2.microsoft.com/en-us/library/ms733605.aspx"&gt;PolicyActivity&lt;/a&gt;,
typically) for invoking the rules at runtime.&amp;nbsp; This all works great assuming
you're authoring and using workflows in your application.
&lt;/p&gt;
&lt;p&gt;
Okay... so here's the neat part.&amp;nbsp; You can use this rules engine even if you aren't
using workflows.&amp;nbsp; There's a great &lt;a href="http://wf.netfx3.com/files/folders/rules_samples/entry309.aspx"&gt;sample&lt;/a&gt; on
the WF community site that demonstrates how to re-host the rules designer in your
own application, as well as how to use alternate storage mechanisms for rules (by
default, rules are saved to a file in your workflow project, and the file is compiled
as a resource).&amp;nbsp; But, that&amp;nbsp;code is still&amp;nbsp;relying on workflows and custom
policy activities to execute rules.&amp;nbsp; So the code from this sample is used in
the other&amp;nbsp;sample found at the link I mentioned at the top of this post to demonstrate &lt;em&gt;rule
execution without workflow involved at all&lt;/em&gt;.&amp;nbsp; I also re-purposed the base&amp;nbsp;sample
code to whip up my own demo app.
&lt;/p&gt;
&lt;p&gt;
Here's a screenshot of rule authoring against my own "User" type (which has properties
like Name and Age):
&lt;/p&gt;
&lt;p&gt;
&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="708" alt="image" src="http://www.joshlane.net/blog/PostImages/WindowsWorkflowRu.WithoutWindowsWorkflow_149D9/image.png" width="852" border="0"&gt; 
&lt;/p&gt;
&lt;p&gt;
Notice the full Intellisense support for my custom type... this makes rule editing
a breeze.
&lt;/p&gt;
&lt;p&gt;
Once you edit and save your rules (storage is&amp;nbsp;just a single table in the SQL
database of your choice), you can then reference the rules (sets of rules, actually)&amp;nbsp;by
name at runtime, for execution.&amp;nbsp; Here's a code snippet:
&lt;/p&gt;
&lt;div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #008000"&gt;//
create my user object...&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;User joe = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; User();&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;joe.Name = &lt;span style="color: #006080"&gt;"Joe"&lt;/span&gt;;&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;joe.Age = 35;&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;joe.Valid = &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #008000"&gt;//
next several lines execute the ruleset called "User2"...&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;RuleSetService svc = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RuleSetService();&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;RuleSet ruleset = svc.GetRuleSet( &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RuleSetInfo( &lt;span style="color: #006080"&gt;"User2"&lt;/span&gt; )
);&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;RuleExecution exec&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RuleExecution( &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; RuleValidation(
joe.GetType(), &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ), joe );&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;ruleset.Execute( exec );&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #008000"&gt;//
okay, ruleset has executed, let's see what the outcome is...&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;Console.WriteLine( joe.Valid.ToString() );&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
And that's it... about 4 lines of code to invoke a ruleset at runtime.&amp;nbsp; And again...
no workflow in sight.&amp;nbsp; Not that I have anything against workflows, it's just
nice to know you can use the rules engine by itself if/when needed.
&lt;/p&gt;
&lt;p&gt;
I've uploaded my own sample application &lt;a href="http://www.joshlane.net/blog/code/WFRulesWithoutWorkflow.zip"&gt;here&lt;/a&gt;.&amp;nbsp;
Grab it, unzip, restore the database backup, check your config file connection strings,
and party on.&amp;nbsp; There are 5 VS.NET 2005 projects included... 4 of them are modified
versions of the code found in the previously mentioned WF community site sample, the
other (called "Tester") is my own sample that exercises some rules I created through
the designer.&amp;nbsp; So just to be clear... most of this is not my own code.&amp;nbsp;
But that also speaks to the beauty of this approach... most of the heavy lifting is
done for us already, so it's easy to get up and running.
&lt;/p&gt;
&lt;p&gt;
Enjoy!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshlane.net/blog/aggbug.ashx?id=786a8c6d-5964-4f67-8b73-e3e5450b1c0e" /&gt;</description>
      <comments>http://www.joshlane.net/blog/CommentView,guid,786a8c6d-5964-4f67-8b73-e3e5450b1c0e.aspx</comments>
      <category>WF</category>
    </item>
  </channel>
</rss>