Windows Workflow Changes Direction
Learn how Windows Workflow Foundation (WF) 4.0 changes everything you thought you knew about workflow. Also, learn why using string primary keys is a bad idea; find out where to get a data grid for Windows Presentation Foundation (WPF); overcome the annoying issue of files not loading at runtime; and copy files into the executable directory.
Technologies mentioned in this article include Visual Basic, Windows Workflow Foundation (WF); Windows Presentation Foundation (WPF), reflection, and C#.
Q I've been hearing that Windows Workflow 4.0 was announced at the Professional Developers Conference (PDC), and that it "changes everything." Is this true, and if so, what does this mean to those of us that have existing workflows?
A Windows Workflow Foundation (WF) 4.0 was unveiled at PDC and is available now as part of the current .NET 4.0 Community Technology Preview (CTP). As such, details aren't complete, so remember that my answer is based on these preliminary announcements.
WF 4.0 represents a bottom-up rewrite with entirely new thinking. The gains are enormous: custom activities take center stage, and authoring them is much simpler; workflows are entirely declarative; and there are three workflow flow styles that you can combine seamlessly. It's possible that you could see a 10-fold improvement in the time required to create and debug workflows, in addition to 10- to 100-fold runtime performance improvements. You'd also have better control over persistence. Additionally, there's support for partial trust, a completely rewritten designer, and a better debugging experience. One of the most important improvements is in the re-hosting experience. This allows you to create activities and to allow power users -- and others -- to build or modify workflows with the constrained set of activities you've created. Yes, this is possible in WF 3.0/3.5, but the necessary code is challenging, not to mention exceedingly difficult to debug.
The improvements to WF 4.0 come at a cost. Microsoft developed two inter-op strategies to help you over this hurdle. WF 3.0/3.5 will remain part of the framework and will run side by side with WF 4.0. This lets you manage the transition at a time that fits your organization's broader goals. The other inter-op strategy is an inter-op activity that allows you to use WF 3.0/3.5 activities in a WF 4.0 workflow. Workflows are a specialization of activities, so you'll probably be able to run entire 3.0/3.5 workflows inside WF 4.0 workflows.
While side-by-side running is essential for timing your conversion, you're likely to skip the inter-op activity in favor of creating consistent WF 4.0 workflows. Outside of the inter-op activity, your workflows, activities, and rules aren't going to transition to WF 4.0 unless Microsoft creates a transition tool. A transition tool that can fully transform your workflows and activities seems unlikely. One of the prime benefits of WF 4.0 is a better strategy for breaking workflows into discrete functional units. Transitioning workflows directly won't improve their design, but rewriting them will. A quick list of significant features Windows Workflow 4.0 doesn't have includes Code Activity, Data Exchange Service (DES) events, DES method calls, a code model (it's declarative only), rules as you know them now, an Initialize event, and dependency properties.
If you're contemplating using WF and can wait until .NET 4.0 is released, I suggest waiting. This is particularly true if you have an existing state-based solution you can nurse along for another year or two. If you do write new workflows in the interim, I've collected a set of preliminary guidelines for preparing workflows to transition (see "Write New Workflows with .NET 4.0 in Mind"). If you've worked with WF 3.0 or 3.5, this is a jaw-dropping list; many of the primary elements you might think of as WF disappear in the transition to WF 4.0.
Another important aspect of your transition strategy concerns long-running workflows. The simplest transition strategy is to allow all workflows to complete in 3.0/3.5 but to begin new workflows in 4.0. If you have aggregate information or if you have long-running workflows, this might not be an acceptable strategy. In this case, you need a strategy to bring down existing workflows and bring them back up in WF 4.0. If you're writing workflows today and believe you'll need this strategy, consider building in events to initiate the process. If you have existing workflows, you might need to alter them later, but it's not yet clear whether Microsoft will provide a tool to help automate the 3.0/3.5 workflow-modification strategy.
If you have deployed workflows, it's almost certain you invested most of your time in understanding and engineering the business process in order to know what workflows to write, and in working through the dozens of quirks and challenges of 3.0/3.5 workflows. Creating the workflows themselves probably took a smaller chunk of time. Certainly, you'll put effort into transitioning your current workflows and redesigning aspects of them to take advantage of new features. But your business engineering work will survive and the simpler model of WF 4.0 -- and the significant input Microsoft received in fixing the issues that plagued WF 3.0/3.5 -- should result in a product with fewer quirks to trip you up.
If you've deployed workflows and believe you'll have a challenging transition, I'd like to know more about your scenario so we can help Microsoft improve the transition experience for you and others.
Q Here's something I've had a hard time understanding: why shouldn't I use string primary keys?
A String primary keys present problems in database integrity, maintainability, and performance. From a maintainability point of view, string primary keys almost always have meaning. Database values with meaning will eventually change and wreak havoc on foreign-key usage. At the least, they change when a data-entry mistake must be corrected. When you make these kinds of changes, you must also update all foreign keys.
Few string columns that have a meaning are truly unique. Social Security numbers are theoretically unique, but data-entry errors and fraudulent usage results in redundant values. This prohibits entry of the second record, regardless of whether the second occurrence is the legal use of the number. Also, federal law restricts usage of Social Security numbers, and many applications cannot legally require submission of a valid Social Security number.
Strings present performance issues because of the inefficiency of string comparisons and clustering issues. Comparing two strings is significantly slower than comparing two integers. Within a database index, there are a large number of comparisons, and primary key indices are used extensively during normal database operations. Slowing down these comparisons hurts overall database performance.
Clustered indexes allow physical organization of an index to improve performance. Successful clustering relies on intrinsic ordering of data and a relatively even spread. Integers provide this ordering and distribution; strings and globally unique identifiers (GUIDs) do not. In the case of GUIDs, just turn off clustering. In the case of strings, replace them with a meaningless integer or GUID primary key and add a secondary index on the meaningful key. The secondary index can be a unique index and allows rapid retrieval on your meaningful string values while still retaining database maintainability, integrity, and performance.
Q I want to switch to Windows Presentation Foundation (WPF), but I need a data grid. I understand WPF doesn't include a data grid, so what do you suggest I use?
A WPF in .NET 3.0 and .NET 3.5 doesn't contain a data grid. However, Microsoft has released the WPF Toolkit, which includes a data grid, calendar control, and date picker. This toolkit requires WPF 3.5 Service Pack 1 (SP1). The included data grid is fairly full featured, but doesn't support grouping. If you're working in .NET 3.0 or 3.5, you'll need to either perform inter-op on the Winforms data grid or use a third-party control. This is another good reason to upgrade to .NET 3.5 SP1.
Q I'm frustrated trying to load an assembly at runtime. Even though IO.File.Exists returns true, I get the error:
System.IO.FileNotFoundException: Could not load file or assembly 'RuntimeLoad.dll' or one of its dependencies. The system cannot find the file specified.
I've simplified my test code to:
Dim dllName = "RuntimeLoad.dll"
Dim assem As Reflection.Assembly = Nothing
assem = Reflection.Assembly.Load(dllName)
Catch ex As Exception
"Assembly failed to load: " & dllName)
A Reflection.Assembly.Load requires the assembly name without the DLL extension. Remove this extension from the string you pass to the Load method, and test again. If this doesn't solve your problem, you should ensure that the file is in the correct location, which is adjacent to the executable. By default, this is at <project directory>/bin/Debug, where <project directory> is the directory containing your project file (.vbproj).
You can also handle loading assemblies at runtime using System.AddIn. The System.AddIn approach is important in some scenarios, but it might be overkill for what you're trying to accomplish.
Q I need to copy some files into the executable directory, but they aren't in the project directory so it doesn't make sense to treat them as resources. We've been trying to do this manually, but we've made many mistakes related to not copying the updated files properly. Is there a way to automate this?
A Visual Studio supports pre- and post-build events, but I think it's easier to modify the project file. The project file is an MSBuild script, capable of managing complicated builds. It also makes it easy to handle straightforward scenarios, such as copying your files.
You can edit project files (.csproj and .vbproj) in Notepad or another editor, but editing them within Visual Studio supplies XML syntax checking and IntelliSense. To open your project file in Visual Studio, right click on the project, and select "Unload Project." Once it is unloaded, right click on it again, and select "Edit <project file name>." The only downside of opening projects this way is that Visual Studio loses its marker to the startup project if you unload that project.
Scroll to the bottom to find the location for one of several well-known targets:
You don't need to understand targets or why this works to put your pre- or post-build code into the correct location. "Copy" is an MSBuild task with the source file location relative to the project directory:
TargetDir is one of many predefined MSBuild properties. You can see some of the most common properties as macros for the pre- and post-build events by typing $( in Help.
Kathleen is a consultant, author, trainer and speaker. She’s been a Microsoft MVP for 10 years and is an active member of the INETA Speaker’s Bureau where she receives high marks for her talks. She wrote "Code Generation in Microsoft .NET" (Apress) and often speaks at industry conferences and local user groups around the U.S. Kathleen is the founder and principal of GenDotNet and continues to research code generation and metadata as well as leveraging new technologies springing forth in .NET 3.5. Her passion is helping programmers be smarter in how they develop and consume the range of new technologies, but at the end of the day, she’s a coder writing applications just like you. Reach her at email@example.com.