Programming Windows Workflow Foundation

Link. February 26, 2007. Comments [1]. Posted in: WinFX | Workflow

I got a review copy of K. Scott Allen's "Programming Windows Workflow Foundation: Practical WF Techniques and Examples using XAML and C#" book and I just finished reading it recently, and wanted to take a moment to mention my opinion about it.

First of all, I'm probably not quite Scott's target audience, seeing how I was already familiar with WF before getting into the book. From my point of view, the book aims to provide a quick introduction to what WF is and how to get started programming it. In that aspect, I think it does a pretty good job.

The book starts by quickly introducing what WF and what it is composed of (the runtime, activities, designer, XAML and so on). Chapter 2 then talks in a bit more detail about how to create and design workflows, covering both the principal aspects of how the VS designer works, as well as writing workflows in code and XAML. But this chapter also goes a bit further and covers using the workflow compiler both from the command line (wfc.exe) as well as programmatically and XAML workflow activation.

Chapter 3 is dedicated to writing sequential workflows, though it also covers basic host <-> workflow communication using the workflow runtime events, workflow parameters and external data services. The latter are taken up in more detail in chapter 4, which covers most of the basic activities in the base activity library.

Chapter 5 introduces how to write custom activities. While the cover here is somewhat light (as expected given the breath of the topic), Scott does quickly cover important topics like activity binding and dependency properties and gives a quick look to readers of how to write custom activity designers and validators. Chapter 6 covers the hosting facilities in WF, including how to correctly use the WorkflowRuntime class, and all the built-in runtime services, including scheduling, persistence and tracking.

Chapter 7 covers State-Machine workflows, including some simple examples of how to interact with the workflow from the host (like quering possible transitions from the current state). Chapter 8 covers host <-> workflow communication in detail, including the use of correlation tokens, role authorization and an explanation of workflow queues. Finally, Chapter 9 covers the rules engine in WF and using code and rule conditions in activities.

As I said earlier, I'm probably not the the target reader for the book. Many of my readers probably won't also, so if you're looking for a comprehensive, in depth look at WF, you'll want to find some other source.

However, if you are not familiar with WF yet, I believe Scott's book is a pretty good place to start. Here's why:

  • The book is short, about 230 pages. Most people should be able to go through the book pretty quickly.
  • Scott's writing is very much to my liking. He's direct, goes straight to the point without any B.S. and he's style is pretty engaging overall, so you won't get easily bored. Chapters are also very reasonably paced and good in length, so you can very easily read it chapter-at-a-time (I hate books with never-ending chapters!).
  • Even though the book is short, Scott still manages to cram a lot of useful information and cover a lot of topics (some in much more detail than I honestly expected) and I think its fair to say he does a good job of putting all the options and facilities in WF in front of his readers.

While on the topic of introducing WF, my good friend Sam Gentile wrote a couple of days an introductory post on WF which is pretty good. Like others, I'm also looking forward to seeing Sam share a bit more of his findings and what he has learned about the platform just as he has in the past with WCF and other technologies.

Look for my take on Dharma Shukla's and Bob Schmidt's "Essential Windows Workflow Foundation" book in a post near you!

Writing a WCF Transport Channel, Part 2

Link. February 19, 2007. Comments [0]. Posted in: WCF | WinFX

The first thing I asked myself when I started writing my custom Windows Communication Framework transport channel was: What exactly do I need to implement? The information on what classes you need to write and what interfaces you need to implement is out there in the documentation and elsewhere (as I pointed out in my previous entry).

However, it still took a bit of time for it to "click" for me. To make it easier to remember, here's a small figure I created outlining what I think are the key concepts in the transport channel model:

I think the figure is pretty self explanatory, but let's add a few comments anyway:

  • The "Configuration Binding Element" is purely a configuration-level entity. That is, it's purpose is to be used in the XML configuration files (or programatically) to configure the transport-part of the binding you'll be using. As such, it's main purpose is to gather some required configuration options and create the transport binding element.
    Confused by the naming of all the element classes? You're not the only one. I think the whole binding element + configuration element part of WCF was horribly named making it unnecessarily confusing.
  • The transport binding element will usually derive from the TransportBindingElement class (or one of its subclasses). One of its primary purposes is to create the Channel Managers for your transport, which are the Channel Factory (IChannelFactory implementation) and the Channel Listener (IChannelListener implementation).
    Your Channel Factory will typically inherit from ChannelFactoryBase<T> and your Channel Listener from ChannelListenerBase<T>.
  •  The actual channels are created from the two channel manager classes. What I mean by "Primarily Send" and "Primarily Receive" is this:
    • Primarily Send channels start by "establishing a connection" to the remote endpoint. In that send, they are proactively opened by the client. These are somewhat analogous to Send-side Adapters in BizTalk Server. This does not mean however, that they only send data, as they can be two way (request/response) channels or even full duplex channels.
    • Primarily Receive channels usually start because a connection was accepted from a remote endoint. These are somewhat analogous to Receive-side adapters in BizTalk Server. Again, they can be two way (reply/response) channels or even full duplex channels.

WCF Configuration Complexity

Link. February 12, 2007. Comments [2]. Posted in: WCF | Web Services | WinFX

Windows Communication Foundation supports a pretty extensive XML configuration schema in your app.config or web.config file to configure both service providers and service consumers as an alternative to using code to set things up.

This is a good thing in most respects. What causes problems for people getting into WCF is that the WCF is too configurable: It supports a huge set of settings and the configuration schema isn't really very intuitive, and it's not particularly hierarchical in nature, which makes its XML syntax complicate things further. One just has to look at the figure here to want to sit down and cry.

Instead of using the XML hierarchical nature to represent a service or client configuration, the WCF configuration schema is based on keys (identifiers) and references, similar to how you'd do it in a relational database. Lets separate the different concepts in the configuration schema and view it as a set of related elements. We'll only concentrate on the core elements here.

The server configuration looks a bit like this:

The core concept here is that a Service contains a set of endpoints. An entire service can reference a set of predefined service behaviors (configured under behaviors/serviceBehaviors), and each endpoint can reference a set of predefined endpoint behaviors (configured under behaviors/endpointBehaviors). Each endpoint can reference a predefined binding configuration, unless it is OK with the default settings for the used binding (which will probably be the case).

A client configuration is somewhat similar:

 

The most important difference here is that a client configuration doesn't specify service behaviors (not needed), but otherwise it is pretty similar.

As I mentioned earlier on, each "reference" shown in the figures above are made using keys. For example, when you define a set of endpoint behaviors, you give it a unique name using the "name" attribute, and then use that name in the "behaviorConfiguration" attribute of the <endpoint/> element to tell WCF that you want to apply those behaviors to this endpoint. Basically, having elements named this way allows you to reuse them: you can apply a given set of endpoint behavior configurations to multiple endpoints and so on.

<services>
   <service name="VoucherServicebehaviorConfiguration="voucherServiceBehaviors">
      <endpoint contract="IVoucherServicebinding="wsHttpBinding
                bindingConfiguration="voucherServiceBinding"/>
      <endpoint contract="IMetadataExchangebinding="mexHttpBindingaddress="mex"/>
   </service>
</services>
<behaviors>
   <serviceBehaviors>
      <behavior name="voucherServiceBehaviors">
         <serviceMetadata httpGetEnabled="true"/>
         <serviceDebug includeExceptionDetailInFaults="true"/>
      </behavior>
   </serviceBehaviors>
</behaviors>

It really isn't all that complicated, though sometimes, the samples out there don't make it easier for a new developer to understand it by giving stuff confusing names. For example, if you name your service behaviors set "ServiceBehaviors" then you end up later on with stuff like:

<service name="myservice" behaviorConfiguration="ServiceBehaviors"/>

which for a new guy is probably more confusing than needed. I'm guilty of doing this in my own code quite a bit, but it's an habit I should really learn to avoid.

Truth be told, service/client, endpoint and even behavior configuration are not that bad. Each one has a fair set of attributes/elements that you can configure, and the number of attributes you'll use normally is more or less manageable. The only reason service/endpoint behaviors might seem complex is because there are a number of them, each with its own options, and because of how the extensibility mechanism for custom behaviors work. I've talked about this last part before, so I won't repeat it here.

Bindings

I'd say that by far the most complicated part of WCF configuration is dealing with Bindings. The built-in bindings in WCF each has a rather large set of configurable options, some common among them, and a lot of others specific to each binding. For example, here's a typical configuration for the WSHttpBinding, which would be a very common choice for WCF services:

<bindings>
   <wsHttpBinding>
      <binding name="voucherServiceBindingcloseTimeout="00:01:00"
          openTimeout="00:01:00receiveTimeout="00:10:00sendTimeout="00:01:00"
          bypassProxyOnLocal="falsetransactionFlow="falsehostNameComparisonMode="StrongWildcard"
          maxBufferPoolSize="524288maxReceivedMessageSize="65536"
          messageEncoding="TexttextEncoding="utf-8useDefaultWebProxy="true"
          allowCookies="false">
         <readerQuotas maxDepth="32maxStringContentLength="8192maxArrayLength="16384"
             maxBytesPerRead="4096maxNameTableCharCount="16384" />
         <reliableSession ordered="trueinactivityTimeout="00:10:00"
             enabled="false" />
         <security mode="None">
            <transport clientCredentialType="WindowsproxyCredentialType="None"
                realm="" />
            <message clientCredentialType="WindowsnegotiateServiceCredential="true"
                establishSecurityContext="true" />
         </security>
      </binding>
   </wsHttpBinding>
</bindings>

You just have to look at this to realize that this stuff is just way too much for any normal person to remember. Fortunately, you don't have to configure all those options as there are sensible default values for some of them.

What is complex about all this? It's not just that there are a lot of options to configure; it's that most developers will have no clue what sensible values for many of these parameters are!. Let's be honest about it. Take reader quotas for example. How many people know right of the bat what value they should configure for the maxNameTableCharCount parameter for the service they just created? No? Then let's look at the documentation, by all means:

"This quota limits the total number of characters in strings that are atomized in the NameTable for the reader. When strings are atomized they are inserted into a NameTable and never removed. This can cause the buildup of large amounts of character data in a NameTable. This quota places a limit on how much data can be buffered in the reader's NameTable."

I don't know about you, but after reading that, I feel I got a pretty good explanation of what WCF does with that setting underneath, but I still have no clue as to what to do with it or how to derive a good value to set it to.

My point here is not to trash the WCF documentation, by all means. My point here is that a lot of the configurable options in WCF are fairly obscure, and most people will just leave that to whatever default value is given to it by the infrastructure. Most importantly, a lot of people won't want to understand that, and just leave happily ignorant about them until they run into some fairly obscure error at runtime, ask in the forums, and someone tells them to just change the corresponding obscure setting.

It's fantastic that WCF allows us to configure even very low level options such as these, but I sure which they could've been exposed in a way that was less in my face. This might be a personal choice, but I really don't want to have to deal with some of this options on a day to day basis, and, to be honest, for a lot of them I don't need/want to have to configure them on an endpoint-by-endpoint basis. I may be in the minority though.

Client vs. Server

Another thing that complicates some of this stuff is that in a lot of the configuration there's no difference between client and server options. Take bindings, for example: You esentially configure the same set of options for a binding on the server and client side. However, some of those options are not stuff a client would usually want to configure or even be forced to configure.

Consider reader quotas: On the server side, these are very important as they help protect your server from malicious clients that might want to attack your services by sending very large sets of data embedded in the requests. You'd normally increase these quotas if you know that your service requires you to accept larger requests. That's good.

But, consider the client: Here, reader quotas are normally not something you care about because you're the one initiating the operation, and a client should normally just accept whatever the service responds and deal with it. Sure, it's important for the client to protect itself and it will normally do that by ensuring it is connecting only to trusted services. It's just inconvinient to have to have to manipulate a bunch of settings just because the service is returning more than 64KB of data (which I'd say it's pretty common).

It's important to note, however, that because of the presence of duplex contracts in WCF, some of these settings will also affect how the client behaves as a "service" when getting invoked on the other way around.

Conclusion

The WCF configuration schema allows you very fine grained configuration of your services and clients. That granularity comes with a price, however: a more complex schema and a bit more work for the developer to understand what the available options mean and how to use them correctly.

Long Running Services and WS-RM

Link. February 7, 2007. Comments [3]. Posted in: Architecture | WCF | Web Services | WinFX | Workflow

Harry Pierson posted a story about Windows Communication Foundation and his "epiphany" (my words) on the usefulnes of WS-ReliableMessaging in Web Services. I found several comments here that made me think. Sam Gentile recently commented as well on the importance of WS-RM, and I did a few quick posts there.

Let me first start this discussion that I believe that the basic concept behind reliable messaging (and WS-RM) is indeed very important and very needed in the Web Services World to make it easier to implement reliable services and integrate disparate applications.

That said, I've been frank in the past and say that I believe that the WS-RM spec, as it exists right now, is remarkably lacking. Harry mentioned the core point: It does not demand persistence of the message and conversation state from the endpoints involved in the communication. Thus, as WS-RM currently exists, and how platforms such as WCF implement it, it means you don't really have the guarantee of reliablity. At best, all you have is the illussion of reliability. The only thing you can be sure of is that one of your endpoints is gonna fail, sooner or later.

If there is one thing that I have learned from my work on Application Integration (with and without BizTalk), is that ensuring reliable communication across a distributed application infrastructure is a tough nut to crack. There's a lot of very significant issues that can arise here, depending on the type of problem domain you're solving: Message delivery, delayed deliver, synchronous and asynchronous interchanges, ordered deliver (and even tougher, in-order processing), lost and duplicated messages and so on.

A spec like WS-RM doesn't try to solve all this issues, for obvious reasons, and that really is fine. A lot of these issues cannot be taken into account by themselves, but only in the context of the overall architecture and requirements. In particular, how the individual endpoints are designed can make a huge impact in which of the issues mentioned before are significant and how significant.

Some architectural choices will make some of these problems go away without having to write more code for it. For example, a given service might have a set of messages created in such a way that the operations they represent are idempotent. In that case, duplicated messages should not be a problem, and spending a lot of time to avoid them would not be an efficient use of your development budget, as they are a non issue. In other contexts, for example, missing one or two messages during high load might also not be important because perhaps the contents can be reconstructed from subsequent exchanges.

So given this, why do I make so much fuss about WS-RM if it wasn't meant to be the end-all solution anyway? Because of the way it has been positioned by the marketplace: It is usually portrayed as saying that it "finally solves the reliable messaging problem for Web Services". It doesn't. Unfortunately, the WCF literature hasn't helped clear this misconception and actually has made the problem a bit worse.

The other problem I have with WS-RM is that it does a bare minimum of work to help the reliability issue. And for better or worse, it doesn't do what I consider is a significant element of what that bare minimum should be, which is to require implementations to force endpoint applications to survive restarts/crashes. My bigguest concern is people building solutions assuming that because they used WCF and turned the RM bit on then they are done and their services are reliable, because that's not really true. Reliable services take a lot of work, and flipping a bit is just not gonna do it, but unfortunately in the way it has been sold to the masses, it sure sounds like learning about all those pesky reliability issues isn't needed when "WCF just does it for us" [1]...

That's my opinion, by the way, and I might be wrong. You need to do your own decision about whether the required/supported functionality is enough for your needs, but be aware of what it is that WS-RM brings to the table and be sure you're making an informed decision.

Harry made a really interesting comparison in his post: "If HTTP is basically UDP, then WS-* is trying to be TCP". I won't comment on whether the comparison is valid or not, but I do want to say that if we (as in "the community", or the "developer world" or whatever) just spent several years working on reliable messaging for webservices just to get what the underlying transport protocol, invented more than 20 years ago, already did to start with, then boy, we have really lost the train this time.

What I want to say by this is if we're going to work on creating a significant improvement on the reliable messaging field, then we need to move forward to solve higher level problems with higher level abstractions. Abstractions such as Workflow and Orchestration are significant advances in this field, for example, because they make it easier to write the endpoint applications in such a way that state can be persisted and thus it's easier for them to survive restarts and allow easier retry mechanisms.

That's why I sometimes despair when I see a whole bunch of fuss made about using Workflow Foundation for such tasks such as driving navigation between three pages in a web application: Great way to make something that was already very easy into a significantly more complex solution that brings dubious benefits (in my humble opinion) to the table. There are far more interesting uses for something like WF but hey, that's just me :-)

One last comment Harry made that got my attention was right at the end, when he says "Eventually, I would love to see something that has the programming semantics of SSB and the interoperability of WCF". It sounds to me (though I might be misinterpreting him) that what he wants sure sounds like an interoperable, open queued messaging platform.

Personally, I'm very interested in such a platform as I believe it would be a great asset to implement reliable and interoperable message driven systems. That's the reason I'm watching very closely the development of the Advanced Message Queuing Protocol (AMQP) especification. And, there's no reason why AMQP could not be a great transport protocol for reliable Web Services!

[1] I do want to be very clear that I'm not bashing the WCF team here. Technically speaking, they're within what the WS-RM spec requires of them (and I fault the spec directly for that), and they probably have the best intentions in the world about trying to make it easier for us developers to use these technologies. They also had to make some very tough decisions about what they would support in V1.

WF Tracking Services Explained

Link. February 6, 2007. Comments [0]. Posted in: WinFX | Workflow

Two new articles just got published to MSDN covering the Tracking facilities in Windows Workflow Foundation in great detail.

The first one is "Windows Workflow Foundation: Tracking Services Introduction", by David Gristwood, and provides a high-level introduction to what Tracking is and how it works in WF. It also shows how to instrument (add tracking) to a workflow and a brief example of how to use SqlTrackingQuery on your app to read the information written by the workflow tracking service. Towards the end, the article discusses Tracking Profiles and what they do.

The second article is "Windows Workflow Foundation: Tracking Services Deep Dive" by Ranjesh Jaganathan, and this one focuses on the underpinings of the tracking facilities. One thing I liked here was the whole discussion about how profiles, trackpoints and locations are related to one another, as they provide a clear overview of how it works for anyone wanting to create custom tracking profiles, as well as how to use Extracts in your trackpoints to extract the data you want tracked from your workflow and activity instances.

About

Tomas Restrepo is co-founder of devdeo. His interests include .NET, Connected Systems, PowerShell and, lately, dynamic programming languages. More...

email: tomas@winterdom.com
msn: tomasr@passport.com
twitter: tomas_restrepo

Technorati Profile

devdeo logo

View my profile on LinkedIn

MVP logo

Syndicate

Ads


Links

Categories

Statistics

Total Posts: 999
This Year: 69
This Month: 0
This Week: 1
Comments: 766

Blogroll

Post Archive

Other

Copyright © 2002-2008, Tomas Restrepo.

Powered by: newtelligence dasBlog 1.9.7174.0

Sign In