OdeToCode IC Logo

What's Wrong With This Code? (#4)

Tuesday, August 29, 2006 by scott

This program throws an exception at runtime. If you've been burned by this problem before, you'll know what's wrong before you even see the definition for class Bar...

using System;

class Program
{
  
static void Main()
  {
    
Foo foo = new Bar();
  }
}

abstract class Foo
{
  
public Foo()
  {
    Init();
  }

  
protected abstract void Init();
}

class Bar : Foo
{
  
string message;

  
public Bar()
  {
    message =
"Hello!";
  }

  
protected override void Init()
  {
    
Console.WriteLine(message.ToUpper());
  }
}

Weird Thread Behavior

Monday, August 28, 2006 by scott

I stumbled on a forum posting recently that led me to write the following code:

using System;
using System.Threading;

class Program
{
  
static void Main()
  {
    
ThreadStart doNothing = delegate { };

    
ThreadStart createThreads =
      
delegate
      {
        
for (int i = 0; i < 50; i++)
        {
          
Thread t = new Thread(doNothing);
          t.Priority =
ThreadPriority.BelowNormal;
          t.Start();
        }
      };

    
for (int i = 0; i < 2; i++)
    {
      
Thread t = new Thread(createThreads);
      t.Start();
    }

    
Console.ReadLine();
  }
}

This program behaves badly on a single processor machine, and pegs the CPU at 100% for over two minutes. On a multi processor machine, the program finishes all the threading work in the blink of an eye - only a brief CPU spike.

Strangely, if I remove a single line of code:

t.Priority = ThreadPriority.BelowNormal;

… then the program performs just as well on a single processor machine (only a brief spike - comparable to the MP scenario).

Could it be a bug?

My $100 Spending Spree with Windows Workflow

Thursday, August 24, 2006 by scott

The WF discussion that Brian Noyes kicked off continues with excellent points from Jon Flanders and Thomas Restrepo. The following posts are full of information from smart people who know WF very well:

You have to understand a technology to use it effectively…
Workflow Complexity
Workflow Complexity Part 2

Tech evangelist Matt Winkle then asked how to improve WF. In other words - quit bitching and offer us constructive ideas.

If I had a $100 budget to improve WF, I'd divide the money as follows:

$30 on designer improvements. The designer has a number of minor irritations, but one stands out at this very moment. Building declarative rules requires me to navigate a number of modal dialogs, and those dialogs prevent me from getting anywhere else in Visual Studio. When I double-click a .rules file, or ask for a new rule in the properties windows, I want a spiffy designer to appear in the editor. Each time a modal dialog appears in Visual Studio, another star falls from the heavens.

$30 on guidance. Simon Ince threw out the idea of a workflow factory / guidance toolkit. I'd also like to see more content covering common workflow patterns and best practices for hosting, versioning, and scaling.

$30 on "activity packs". Incrementally augment the base activity library with "activity packs". Microsoft could make activity packs available for download as they are developed and in-between major releases of WF. Each activity pack could cover a specific technology domain. Examples: a database activity pack, a WCF activity pack, a file system activity pack, and an XML activity pack. We could download just the activity packs we need.

$10 on an open source base activity library.WF will really shine in scenarios where domain specific activities are available (look at casey's article with a Speech Server workflow to see the flexibility and power of WF). First, however, a team has to build good looking and well-behaved domain specific activities. As Thomas says in his post - "Creating new activities is easy. Creating good activities can be pretty hard." The WF site already includes a number of custom activities, but activities are the lifeblood of WF, and we can always use more.

Earlier this year, the ASP.NET team released source code for all the built-in ASP.NET 2.0 providers, so this idea isn't unthinkable. Providing source and documentation for the BAL would be a tremendous boon for custom activity development.

My Gripes with Windows Workflow

Friday, August 18, 2006 by scott

Brian Noyes' post "Understanding Windows Workflow and its complexities" has me thinking.

I know a few people who have given up on Windows Workflow altogether. WF imposes its own paradigm. If your way of thinking is different from the WF way of thinking, you are going to live in a house of pain.

Brian's first complaint is about the designer. I've found the designer to be clunky. There are behaviors you come to expect in Visual Studio, like being able to double-click somewhere and have the designer perform some work. The WF designer never acts intuitively. There are also places where the behavior seems inconsistent - some properties permit data binding and some properties do not. It's not until you learn about dependency properties and meta-properties that this behavior make sense.

Brian's third point was about the HandleExternalEvent activity. Setting up communications between a workflow and its host is a tremendous amount of work, and it's easy to get wrong (a working title for my InfoQ article was "How To Screw-up the HandleExternalEvent activity"). The work doesn't payoff until you see an event arrive for a workflow that has been living in a database table for 8 days. The runtime can re-load the correct workflow and still deliver the event! It's amazing to see this happen, but requires a lot of work to get there.

There are some common gotchas in WF programming:

1) Spawned execution contexts. The rule is that an activity executes once and only once. If you write code that forgets this rule, it's going to hurt!

2) Serialization. You don't need database persistence to see exceptions from the BinarySerializer - spawned execution contexts also make a deep copy of activities using serialization. Make sure those custom properties are serializable!

3) Transactions. It's easy to get MSDTC involved in heavy duty transactions with WF. Just using a persistence service and transactional tracking service at the same time will get the DTC involved (unless a special SharedConnectionWorfklowCommitWorkBatchService is added to the runtime). Something makes me nervous when a class name has 46 characters.

WF isn't as easy as it first appears. It's powerful, but requires an investment of time.  

Powershell: Attach Debugger To ASP.NET Worker Process By Name

Thursday, August 17, 2006 by scott

For those who don't like the "Attach To Process" dialog box, just pass the application pool name to this Powershell function:

function debug-wp([string]$name)
{
  if([String]::IsNullOrEmpty($name))
  {
    throw "Usage: debug-wp -Name "<appPoolName>"
  }

  $wplist = get-wmiobject Win32_Process -f "Name='w3wp.exe'"
  foreach($wp in $wplist)
  {
    if($wp.CommandLine -match "-ap `"(.+)`"")
    {
      if($name -eq $matches[1])
      {
        & vsjitdebugger.exe -p $wp.ProcessID
        break
      }
    }
  }

  if($name -ne $matches[1])
  {
    write-host "Could not find AppPool" $name
  }
}

 

Haack for President

Wednesday, August 16, 2006 by scott

Phil Haack's blog has been on fire this month. Here is a sampling:

Open Source Is Free Like A Flower
Tiny Trick For Viewstate Backed Properties
Log4Net and External Configuration file In ASP.NET 2.0
Fun Iterating PagedCollections With Generics and Iterators

All great posts, but the pièces de résistance are "ASP.NET Supervising Controller (Model View Presenter) From Schematic To Unit Tests To Code" and "Tying MVP To the ASP.NET Event Model"

I particularly enjoyed the last post. Some people will freak out at the thought of tying the V in MVP to a specific technology. For the business layer and below, the thought is cause for alarm, but model-view patterns are all about testability these days. The generalizations needed to make a view work for multiple technologies are more of a hindrance than a benefit.

 

What's Wrong With this Code? (#3)

Tuesday, August 15, 2006 by scott

Here is a Visual Basic program with bowling scores in a multi-dimensional array. Two players bowled three games each. The program tries to display the total score for each bowler, but has a small problem. Can you spot it?

Module Module1

  
Sub Main()

    
Dim allScores As Integer(,) = _
        {{101, 128, 143}, {123, 115, 116}}

    
' for each player
    For i As Integer = 0 To allScores.GetUpperBound(0)

      
Dim score As Integer

      ' for each game
      For j As Integer = 0 To allScores.GetUpperBound(1)
        score = score + allScores(i, j)
      
Next

      Console.WriteLine("Player {0} score: {1}", i + 1, score)

    
Next

  End Sub

End
Module