July 2005 - Posts

Speaking Of Master Pages

If you are in the Batimore / Washington D.C. area, come out to the next CMAP user group meeting on Tuesday (August 2, 2005).

I’ll be giving a 20 minute presentation on Master Pages in ASP.NET 2.0 as part of the opening act for Brian Noyes. Brian’s feature presentation is also a 2.0 topic: Present Rich Data Interfaces with the DataGridView Control.

User group meetings are a great chance to network, eat free pizza, win prizes, and discuss technology. The setting is comfortable, the screen at the new meeting location is massive, and you won’t leave without learning something.

See the CMAP site for directions and more details.
I hope to see you there.

posted by scott with 1 Comments

Vista Beta 1 On Virtual PC

I wanted to try the Vista beta on a fresh Virtual PC this evening, but setup doesn’t cooperate.

Here is how I worked around it:

When you get to the “Install Windows” screen, press Shift+F10 toopen a command prompt. Type DISKPART at the prompt and use the following commands.

select disk 0 
create partition primary 
select volume 1 
format fs=ntfs label="vista" 

After this I typedEXIT to leave the utility, reset the VPC, and started the installation again.

If everything looks good, I’ll cross my fingers and install on my non-virtual laptop over the weekend.

posted by scott with 32 Comments Rated Excellent [5 out of 5].

The Problem with Test Driven Development

Unit testing fanatics might find the content of this post disturbing. I’m going to point out a fundamental problem with the TDD approach, and I’m not one to just point out problems, so I also offer a solution.

TDD fanatics often wonder aloud why the weary masses have not thrown off the shackles of hack and slash coding, why they have not come running to the glow of green lights and the feeling of confidence the lights imbue. The merits of TDD are so obvious, the fanatics think, that any software developer should instantly evolve into an enlightened one – a test driven developer. Yet, many are left unconverted.

The adoption of TDD is hampered by a glaring problem. The problem begins in the opening description of the methodology, which typically sounds like the following.

The first step is to quickly add a test, basically just enough code to fail.

Do you see the problem?

Let’s take another example. Here is a shot of the NUnit status bar after test execution.

There is the problem again – do you see it yet?

The problem is no ambitious person will wake up in the morning, walk into the shower, and plan ahead for a day of failure. If they did, they wouldn’t be getting into the shower. People who think that way stay lying in bed, daydreaming about the beach and seeing other people in their wet cotton swimwear. Nobody wants to start with a failure.

The word fail is a dirty, dirty word.

You know what we do with dirty, dirty words, don’t you?

We shun dirty, dirty words. We replace them. We turn them into gentle, obfuscated phrases.

Euphemisms In Software Development

As software developers, we are familiar with many euphemisms. For example, instead of saying software has “defects”, we say software has “issues”. Nowadays, no self respecting company will wait until V 1.0 to release a product. A beta release is as good as gold - it just has a some “issues” is all.  

Likewise, AJAX is a new euphemism for “I wish this wasn’t a browser based application”. The A in AJAX stands for asynchronous. Asychronicity sells - not that asynchronicity is a real word, but it sounds sexy and could be the title of a hip dance song.

I could go on and on with these examples, but I hope you, as the reader, have seen the solution I am driving towards.

Failure Is Not An Option

At this time I’m going to borrow an idea from the British education system – the idea of “deferred success”. Instead of saying that a child has “failed” a class, British schoolteachers want to say the child has merely “deferred success”. The word “fail” could scare a child away from future education. A brilliant idea from you bloody Brits.

Let’s apply the concept of deferred success to test driven development.

The first step is to quickly add a test, basically just enough code to defer success.

Doesn’t that statement make you feel success is just around the corner? Why, the word success even appears at the end of the sentence! No nasty f*** words are jumping off the screen, filling developers with a sense of fear and foreboding.

Even NUnit looks better after two changes to StatusBar.cs and a recompile. I need to get in touch with the PM for Team System unit testing ASAP.

Now the choice is up to the test driven development community. They can continue to force failure after failure on software developers, or they can choose the kindler, gentler path to test driven development.

I hope my posting will not defer it’s success in convincing them to make the right choice.

posted by scott with 14 Comments Rated Excellent [5 out of 5].

Adapter Patterns and Cross Page Post Backs

It was a quiet weekend morning, and I thought I’d write up a quick blog posting with the above title. About 1400 words later, I realized I had zoomed past post length material into article length, so I put Design Considerations for Cross Page Post Backs in ASP.NET 2.0 in the main OdeToCode article area. Excerpt:

It’s also interesting to note the behavior of the PreviousPage property during a cross page post back. PreviousPage uses lazy evaluation, meaning no previous page will exist until the first time you touch the property. At that point the runtime will load a new instance of the PreviousPage web form and have it start to process the current request. This might sound odd at first, but we’ll see why the approach makes sense.

posted by scott with 37 Comments

String Basics Part II

The sample code in this post demonstrates that the run time maintains a string intern pool. The intern pool allows sharing of string instances. Interning is primarily a memory optimization, but can also be a performance optimization in some unique scenarios.

The runtime will store strings literals in the intern pool. For example:

using System;

 

class Class1

{

    [STAThread]

    static void Main(string[] args)

    {

        string s1 = "bbb";

        string s2 = "bbb";

        Console.WriteLine("{0},{1}", s1, s2);

    }

}

If you look at the IL code for the above program, you might be tempted to think we are dealing with two different string instances. In other words, s1 and s2 will point to different string objects.

  IL_0000:  ldstr      "bbb"

  IL_0005:  stloc.0

  IL_0006:  ldstr      "bbb"

  IL_000b:  stloc.1

This is not the case, as the following program will demonstrate.

using System;

 

class Class1

{       

    [STAThread]

    static void Main(string[] args)

    {          

 

        string s1 = "bbbbbb";

        string s2 = "bbbbbb";

 

        // this expression returns true

        // both string variables reference the

        // same interned string

 

        bool b = Object.ReferenceEquals(s1, s2);

        Console.WriteLine(b);

 

        // create a new string with the same value

        // as the above: "bbbbbb"

 

        string s3 = new string('b', 6);

 

        // this expression returns false

        // even though s3 references "bbbbbb",

        // it's not the same string instance

        // referenced by s1,s2

 

        b = Object.ReferenceEquals(s1, s3);

        Console.WriteLine(b);

 

        // See if "bbbbbb" is already interned by

        // checking the reference returned by Intern

 

        string s4 = String.Intern(s3);

 

        // this expression returns true

        // s4 is pointing to the same object as s1,s2

 

        b = Object.ReferenceEquals(s1, s4);

        Console.WriteLine(b);

    }

}

posted by scott with 2 Comments

String Basics Part I

I’ve used the snippet of code at the end of this article twice in the last week to clear up some misunderstandings about strings in .NET.

System.String is a reference type in .NET. Don’t let anyone mislead you into thinking otherwise. You’ll hear people saying strings “act like value types”, but this doesn’t mean the runtime makes a copy of the string during assignment operations, and it doesn’t make a copy of a string when passing the string as a parameter.

The equality operator and String.Equals method compare the values of two string objects, and you won’t find a property or method on System.String with the ability to modify the contents of a string – only return a new string object. Because of these two behaviors we sometimes say strings have value type semantics (they feel like value types), but strings are reference types in the runtime. An assignment operation does not copy a string, but assigns a reference. The value given to a string parameter in a method call is the reference, not a copy of the string’s value.

using System;

class Class1

{

[STAThread]

static void Main(string[] args)

{

string s1 = "Hello";

string s2 = s1;

// this test will compare the values of the strings

// result will be TRUE since both s1 and s2

// refer to a string with the value "Hello"

bool result = String.Equals(s1, s2);

Console.WriteLine("String.Equals(s1, s2) = {0}", result);

// next we will check identity

// ReferenceEquals will return true if both parameters

// point to the same object

// result will be TRUE -both s1 and s2reference

// the same object.

// strings are reference types

// there is no copy made on assignment (s2 = s1)

result = Object.ReferenceEquals(s1, s2);

Console.WriteLine("Object.ReferenceEquals(s1, s2) = {0}", result);

// now we will make a copy of the string

s2 = String.Copy(s1);

// compare string values again

// result will be TRUE - both s1 and s2

// refer tostrings with the value of "Hello"

result = String.Equals(s1, s2);

Console.WriteLine("String.Equals(s1, s2) = {0}", result);

// check identity again

// result will be FALSE

// s1 and s2 point to different object instancesbecause we forced a copy

result = Object.ReferenceEquals(s1, s2);

Console.WriteLine("Object.ReferenceEquals(s1, s2) = {0}", result);

}

}

posted by scott with 0 Comments

Thoughts From The Drive-Thru

I’m was waiting in the drive-thru lane at the bank today when I picked up the June 2005 issue of Dr. Dobb’s Journal from my backseat. Reading an engrossing article in the car is a fun way to meet new people. When the person behind me honks and shouts “Pay attention, moron! Move forward!”, I know what they are really saying is “I am bored and have nothing to read, will you share?”. You’d be surprised at the conversations that ensue.

One of the articles covered new features in the Linux 2.6 kernel, including the EXPORT_SYMBOL_GPL() macro for use in loadable modules. The macro allows a module to hide it’s API from any module that does not use a GPL-compatible license.

What a great way to punish developers who write Linux software but don’t (or can’t) GPL their work. It’s like a declarative digital rights management system that, like most DRM schemes, inflicts most of it's pain on innocent bystanders.

posted by scott with 3 Comments

Master Pages

My latest article: Master Pages In ASP.NET 2.0. Excerpt:

The master page implementation outlined above has another consequence to watch for. Since the master page injects it's controls and markup into a page’s Controls array, any relative URLs in the master page markup may break. Remember, the browser will request the web form, not the master page, so all of the URLs will be relative to the web form. When the web form and master page are in different directories, relative URLs may point to the wrong location. To help alleviate relative URL problems, ASP.NET will rebase relative URLs for server-side controls. Rebasing will build the correct URL to the resource.

P.S. Every tool ever made to format code into HTML has at least one problem that drives me insane.

posted by scott with 53 Comments

VB.NET versus C# Web Forms

There is a subtle difference in the default ASP.NET 2.0 ASPX files for VB and C#. I mention the difference only because C# is traditionally the ‘explicit’ language while VB.NET is the language with late binding features built-in.

A new VB.NET web form places AutoEventWireup=”false” in it’s @ Page directive. This means your code is responsible for explicitly wiring up Page events.

A new C# web form places AutoEventWireup=”true” in it’s @Page directive. This means the runtime will reflect upon your code to find method names in the form of Page_EventName and attach the methods as event handlers for named event.

Why is this?

VB.NET’s Handles keyword allows you to catch an event in a declarative manner. There is no comparable feature in C#. It’s a nice feature to have.

posted by scott with 1 Comments

MasterType in ASP.NET 2.0

Here is something nice that comes from the new compilation model in ASP.NET 2.0. Let’s say you add a custom property to a master page code-behind file like so:

Partial Class otcMaster
    Inherits System.Web.UI.MasterPage

    Public Property FooterText() As String
        Get
            Return Footer.Text
        End Get
        Set(ByVal value As String)
            Footer.Text = value
        End Set
    End Property

End Class

You can get to the master page for a web form using the inherited Master property, which returns a MasterPage reference. To get to a property defined in otcMasterPage though, you might think you need to use a cast.


CType(Master, otcMaster).FooterText ="foo"

Casting to a derived type is just a part of life when using frameworks and statically typed languages, but there is a better way. Use the @ MasterType directive in the ASPX.

<%@ MasterType VirtualPath="~/otc.master"  %>

Now when ASP.NET codegens the page, it puts the following inside a partial class definition. Notice the Shadows keyword (that would be the new keyword in semicolon land [yeah, I’m experimenting with alternative languages]).

Public Shadows ReadOnly Property Master() As otc
    Get
        Return CType(MyBase.Master,otcMaster)
    End Get
End Property

The result is a strongly typed Master Page. We don’t need a cast, we can go right to the Master.FooterText property. Another way to do this is to specify a TypeName in the @MasterType directive.

posted by admin with 8 Comments

Backstage Blogging

This weekend I’m playing in the pit orchestra for a community theater production of Sondheim’s Tony winner “Into The Woods”. The musical is a funny blend of fairy tales into a story of love, lust, and death by angry giant. I enjoy the music and storytelling in this show. My only criticism is the blatant use of a deus ex machina near the end.

Some of my favorite quotes:

   Cinderella: Opportunity is not a lengthy visitor.  

   Cinderella’s prince: I was raised to be charming, not sincere.

   Rapunzel’s prince: Dwarves are very upsetting. 

   Jack’s Mother: Children can be very queer about their animals.

   Witch: I'm not good, I'm not nice, I'm just right.
                I'm the Witch.
                You're the world.

posted by scott with 2 Comments

Research

I should have grown up to be a researcher. Easy money – no stress.

Take this for example: someone made money doing a survey that discovers the vast majority of men at a nude beach don’t object to seeing nude females.

Well, duh.

As a follow up, the survey team will find out if the majority of people in a steak house restaurant object to seeing medium rare prime rib.

Here is another interesting study: IQ Dips More on Email Than Pot. The study claims that distractions from emails and instant messages make people

brb



Where was I?


Oh, right.

I was wondering how one could measure a change in IQ during periods of high-tech intrusiveness. IQ isn’t like blood pressure, as far as I know – but then I see a lot of email, so maybe I’m getting dumb. Who cares? Let’s chat!

Even if your research doesn’t pan out – just make something up. There is good money in fake numbers.

I’d like to start publishing my own research white papers. I’ve decided to start analyzing raw data at my disposal – like the log files for OdeToCode. Here is a break down of RSS readers hitting the site since July 1.

Name % of hits
SharpReader 38.1%
RssBandit 23.6%
NewsGator 17.2%
OmeaReader 10.4%
RssReader 5.6%
FeedDemon 3.0%
Others < 3%

Based upon these statistics, I’ve concluded that .NET is the only viable platform for building a popular RSS feed reader. I plan to publish these findings alongside some glossy pie charts and sell them to analysts in need of market research.

Who wants to invest?

posted by scott with 9 Comments

Moving ASP.NET Apps from IIS 5.x to 6.0

Here are areas to watch when moving an ASP.NET app from Windows 2000 / XP ( IIS 5.x) to Windows Server 2003 (IIS 6.0). These notes assume you do not configure IIS 6.0 to use IIS 5.0 isolation mode

- Worker Process Changes

Web applications execute inside a worker process to isolate themselves from IIS. The isolation allows IIS to continue running and servicing requests even when your web application is going down in flames. In IIS 5.x the worker process name is aspnet_wp.exe, and the process runs under the ASPNET account. The ASPNET account is a local machine account and has no network access. The best the ASPNET account can do is appear as an anonymous user to a remote machine.

In IIS 6.0, the worker process is w3wp.exe. The process runs under the NETWORK SERVICE account. The NETWORK SERVICE account has access to the machine credentials for outbound connections, and will appear to a remote machine as [DomainName]\[ComputerName]$.

What this means.

When granting permissions to local resources, make sure to pick the correct account. On Windows 2003, the .NET installation will still create the ASPNET account event though the worker process runs as NETWORK SERVICE by default. If you need access to remote resources, like when making a trusted connection to a database, you can grant access to the web server’s machine account if the worker process runs as NETWORK SERVICE.

<processModel> Changes

Under IIS 5.0, the <processModel> section in machine.config controls many of the settings for the worker process (aspnet_wp.exe). Under IIS 6.0, only the following <processModel> settings are used: maxWorkerThreads, maxIoThreads, and responseDeadlockInterval. All other settings, such as idleTimeout are now configured using the IIS 6.0 metabase.

What this means

Except for the three settings above, use the Application Pool settings in the IIS management console to adjust settings for the worker process. This includes changing the identity for the worker process. You’ll need to right click and select the Properties option for the Application Pool your code runs in. You can find out which pool to use by inspecting the “Application settings” under the directory properties tab where your application lives.

ASP.NET is off by default in Windows Server 2003

Most non-critical services are off by default in Server 2003. If you see 404 errors requesting ASPX forms, or the forms display server side markup instead of dynamic content, you need to enable ASP.NET.

What this means.

Use Manage Your Server to enable ASP.NET.

Process Recycling

The default <processModel> setting for the idleTimeout property is Infinite. Once the application has been inactive for an idleTimeout amount of time, the worker process will shut down (never, if idleTimeout is infinite). Remember though, on IIS 6.0 the metabase overrides the <processModel> settings, and the default timeout is 20 minutes. If applications in the pool receive no requests for 20 minutes, the worker process terminates. In-process Session state and Cache are emptied, and connections are closed.

What this means.

If a worker process has to start from scratch, there is quite a bit of work to do. The cache will be empty, the connection pool will be empty, and your web application code needs JIT compiled. All the work means you could see a sluggish response to the one request that starts the application running again. If you have a dedicated server for your application, consider disabling the idle timeout. Also note: if you’ve configured session timeout to be longer than the idle process timeout, then sessions will appear to timeout prematurely.

posted by scott with 6 Comments

The Monad Experiment

When I saw Adam Barr’s “Monad and RSS” posts (Part I, II, III), I thought of something I’ve wanted to have recently: a utility to parse through my OPML file and tell me what feeds were dead or not updated for months.

Monad is the up and coming command line shell in Windows. Adam’s samples made XML in Monad look easy, so I thought I could bang out a quick script…

… then I discovered the pain of umpteen different syndication formats, each with their own quirky implementations. I am now amazed there are any working feed readers in existence. Why does simple stuff always get so difficult?  

Still, I have something that works “okish”. The script tells me about dead and deserted feeds. There are some quirks. For instance, Ted Neward’s <pubDate> element refuses to parse into a DateTime in Monad. I blame it on the JSP extension in Ted’s URL.

The exception handling took some getting used to – but is great to have in script. On the other hand, I kept turning things into strings when I didn’t want strings. I stumbled into the right format to use for namespace-qualified elements, but I do like the way it works. I didn’t want to throw XmlNamespaceManager mumbo jumbo into script.

I’d like to see someone who actually knows Monad take the script and turn it into one of those 5 line masterpieces full of pipe symbols and regular expressions.

$opmldoc = [xml]$(get-content $args[0])

$webclient = new-object System.Net.WebClient

$cutoff = [DateTime]::get_Now().AddDays(-30)

 

foreach($feed in $opmldoc.opml.body.outline)

{

  $date = $null

  $doc = $null

  trap [System.Net.WebException]

  {

    write-host "Web error fetching feed for " $feed.title

    write-host " Error: " $_.Exception.Status

    continue

  }

  trap [System.Exception]

  {

    write-host "Choked on: " $feed.title

    continue

  }

 

  #because of goofy leading chars in msdn feed

  $raw = $webclient.DownloadString($feed.xmlUrl)

  if($raw -ne $null)

  {

    $doc = [xml]$raw.SubString($raw.IndexOf("<"))

  }

 

  #see if this is rss

  if($doc.rss -ne $null)

  {

    if($doc.rss.channel.item[0].pubDate -ne $null)

    {

      # uses <pubDate>

      # sort items by date and pick the most recent

      $date = [DateTime](

                $doc.rss.channel.item |

                sort-object @{ e = { [DateTime]$_.pubDate }; asc=$false}

               )[0].pubDate

    }

 

    if($doc.rss.channel.item[0].{dc:date} -ne $null)

    {

      # uses <dc:date>

      $date = [DateTime](

                $doc.rss.channel.item |

                sort-object @{ e = { [DateTime]$_.{dc:date} }; asc=$false}

               )[0].{dc:date}

    }

 

    # if we still don't have a date, try <lastBuildDate>

    if($date -eq $null)

    {

      $date = [DateTime]$doc.rss.channel.lastBuildDate

    }

  }

 

  # check for RDF

  elseif($doc.{rdf:RDF} -ne $null)

  {

    $date = [DateTime](

               $doc.{rdf:RDF}.item |

               sort-object @{ e = { [DateTime]$_.{dc:date} }; asc=$false}

              )[0].{dc:date}

  }

 

  # check for ATOM

  elseif($doc.feed -ne $null)

  {

    $date = [DateTime](

               $doc.feed.entry |

               sort-object @{ e = { [DateTime]$_.issued }; asc=$false}

              )[0].issued

  }

  if($date -eq $null)

  {

    write-host "Did not parse date from " $feed.title

  }

  elseif($date -lt $cutoff)

  {

    write-host "Stale feed alert!! : " $feed.title

  }

}

posted by scott with 3 Comments

Migrating Base Page Classes Currently Broken

If you derive your web form code-behind pages from a base class to manipulate common controls, your code won’t be happy with beta 2. For instance, deriving a web form from the following class will result in a null reference exception in AppBasePage_Load (commonLabel is null).

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

 

public class AppBasePage : Page

{

    protected override void OnInit(EventArgs e)

    {

        this.Load += new EventHandler(AppBasePage_Load);

    }

 

    void AppBasePage_Load(object sender, EventArgs e)

    {

        commonLabel.Text = "Hello World";

    }

 

    protected Label commonLabel;

}

In 1.x ASP.NET would wire up commonLabel to a server-side control with the same ID. In 2.0 ASP.NET will code-gen a partial class with a commonLabel declaration that hides the base class declaration. The base class object's commonLabel reference will remain null.

According to ScottGu’s “Compatibility Testing” post, this problem should be fixed by the migration wizard in RTM bits. Hopefully the fix will be in a CTP soon  - I'm curious to see if there will be an elegant solution.

posted by scott with 1 Comments

Book Giveaway Winners

The winners of the first OdeToCode book giveaway are: Steve Wright, Rick Nakroshis, and Hermann Klinke. These three gentleman each won a book from Packt Publishing.

Thanks to everyone who entered – we had a great response. If you didn’t win this time, then try again in the next contest...

posted by scott with 0 Comments

Configuration & ASP.NET 2.0

My latest article covers interesting features in the .NET 2.0 configuration API.

In 2.0 you can not only read from configuration files, but you can write to configuration files, too (even on remote machines).

There are permission issues to watch for, and of course any write to a web.config file will cause a web application to restart in a new AppDomain. There is some additional flexibility with both of these issues thanks to the new configSource attribute.

The configSource attribute allows you to move a configuration section to an external file. Combining this feature with restartOnExternalChanges=”false” means you can avoid application restarts when modifying application configurations. You can also set different ACLs on the external files, perhaps giving the ASP.NET worker process write permissions on a file with appSettings, but leaving write permissions to web.config in the hand of Administrators.

It’s also easy to encrypt entire sections of a configuration file, but alas, not the <processModel> section which may contain an account password. Read all the details here.

posted by scott with 30 Comments