August 2005 - Posts

.NET Is Hard

DonXML and Sahil have been talking about the E-week article “DBAs Bar Door Against Big Bad .Net Wolf”. Both guys have some good insight.

One paragraph in the article struck home with me:

Much of the problem has to do with the fact that .Net is just too hard, Dobson said. "Most IT pro people—I'm talking about the DBAs—did not embrace .Net" when it first came out in 2001, he said.

True, true. Just the other day I was working with a DateTime value in C#, but what I really needed was a string with a plain ol’ U.S. formatted date. After some intense concentration, I typed the following:

string date = someDate.ToShortDateString();

I’m sure many of you have felt that pain. It’s particularly hard with Intellisense always popping up bizzare windows. I couldn’t take the foolishness anymore, so I wrote a T-SQL UDF instead, and used the following: 

SET @date = CONVERT(char,@someDate,131)

I was pretty happy with this version, but during testing I discovered I was getting strange output. It turns out the number 131 tells SQL Server to use Kuwaiti algorithm and the Islamic lunar calendar to produce a date.

Oops!

No problem - I tried 126, 108, 105, and then 6. No luck. Eventually I put in a 101 - and everything worked!! Tee-hee!

I spent the rest of the afternoon etching the T-SQL date format styles into a piece of corkboard using my trusty soldering iron. I'll hang this above my desk to make life even easier.

I won't tell you what happened when I implemented String.Split in T-SQL. I'll leave the wonderful experience as an excercise for the reader.

posted by scott with 6 Comments

Something Moved

I sat down to my desktop this morning and my wrists reminded me I’ve been spending a great deal of time with the mouse and keyboard these last three weeks.

After logging in, I decided it was time for a change.

I stared intently at the taskbar on the bottom of my screen. I began to imagine applications launching, menus opening, commands executing. I could feel the energy start to form around me. I concentrated on synchronizing the patterns in my brain - pouring them into the silicon mind before me. I began to hum the note three steps below a middle c. The aura around me was terrific to behold.

Then it happened.

Something moved!

A window appeared!!!

The window said: “A newer version of MSN Messenger is available”.

Coincidence? I don’t think so.

I believe I just need some more practice….

posted by scott with 5 Comments

Crushed

I’m crushed with some heavy duty projects.

The hours fly by like a compressed binary stream, and I’ve had no time to coalesce ideas into a well-formed post.

I do, however, have a collection of random thoughts I can share. You probably can’t tell the difference between this post and all the rest….

Marketing

On Monday I met the new marketing director. After shaking my hand he looks at me and says: “I never lie to potential clients – I always check with engineering first to know what we have”.

I’m going to take up an office collection to ship him this book.

Visual Basic really is the ugly step sister

I have one directory with 30,000 C# files (don’t ask). The Visual Studio “Find In Files” command just can’t cope.

Fortunately, the MSN search toolbar can cope. The .cs extension is already included as a default type to index, all I needed to do was add the right directory as custom folder to index.

The toolbar does not index .vb files by default.

Car Names

What’s up with car names these days? I saw a “Prius” in a parking lot last week and for some reason my first thought was of a prostate exam.

Yesterday I saw an “Armada”. I’m not sure why I’d buy a vehicle that evokes images of ships being set ablaze and battered by cannonballs, but I do wonder if the driver wears a naval cap while cruising.

Now, back to the grindstone.

posted by scott with 1 Comments

Unit Testing and Refactoring in VS 2005 Beta 2

I started some new work on a .NET 2.0 project recently and decided to dive headfirst into the unit testing features in 2005. The auto-generated tests seem to have a fundamental flaw and I’d recommend avoiding them (at least in beta 2).

It’s easy to put the cursor on an existing class, right-click and select “Create Tests…”. Visual Studio will generate a boatload of code at this point, including a unit test class with a test method for each method and property on the target class.

The stubbed out test methods are setup to work through an accessor class. If you create an Account class, and use the “Create Tests…” option, Visual Studio creates an AccountAccesor class.

The accessor classes will proxy calls to the real object using reflective techniques, i.e. with an Invoke call. This approach allows you to test protected and private members of a class as if they were public members. The merits of testing non-public members of a class are debatable, but the layer of indirection an accessor adds takes all the fun out of refactoring.

One of the many benefits of the refactor feature is that you can change the name of a method or class and feel confident that the IDE can manage the aftermath. There is no need to do a global search and replace by hand – the IDE takes care of cleaning up.

Let’s say you want to rename your Account class to CAccount because you miss programming in MFC (in which case I suggest you look for professional help). The refactoring will not change the code in your unit tests, because the unit tests are using the accessor class instead of the real class. The instantiation of the accessor would look something like the following (except it’s actually a lot uglier):

_accountAccessor accessor = new _accountAccessor(target);

Of course, the accessor class needs to create a real instance of the Account class to test, but because it creates an instance in a late bound manner. The Account class type is only referenced as a string, like the following (except it’s actually a lot uglier).

protected static PrivateType m_privateType =

    new PrivateType("AssemblyName", "Namespace.Account");

The refactor feature can't make any changes to your unit tests because it doesn't know where you were using the Account class. The next time you run your tests you'll have a pile of exceptions about missing methods and classes.

You can regenerate just the accessor classes, but you'll still have a mess to clean up by hand.

I’m not sure what the generated tests will look like in the RTM versions of Visual Studio 2005 / Team System (or even what versions will support unit testing), but I’m staying away from the auto-generated tests in beta 2.

Something is fundamentally wrong if a testing feature makes refactoring more difficult ... or am I missing something?

posted by scott with 6 Comments

What AJAX Should Not Be

Continuing on the AJAX theme, I have a couple ideas about what AJAX should not be:

AJAX should not be hard to debug.
The moment I see a developer machine with a packet sniffer in one window and a script debugger in a second window, I know it’s time to fire up Microsoft Project and make some adjustments. A good AJAX implementation will have tracing, logging, and diagnostics built-in.

AJAX should not be hard to test.
Automation == good.
Room full of interned monkeys clicking randomly == bad

AJAX should not be SmartNavigation 2.0
SmartNavigation (obsolete in 2.0) uses a clever trick to make a web application feel like a windows forms application. By POSTing from a hidden IFRAME, the end user doesn’t experience the typical flash and loss of scroll position during post back. Unfortunately, SmartNav only works for trivial web applications. People sink a good deal of time trying to get SmartNav to work before giving up.

If you think about it, AJAX and SmartNavigation have similar goals (and by manipulating the DOM with async results, an eerily similar implementation) - I just hope whatever AJAX becomes turns out better.

P.S. The SetFocus and MaintainScrollPositionOnPostBack members of the Page class in 2.0 will do most of what you wanted to do with SmartNav in 1.x.

AJAX should not confuse the user. Those little animated icons in a web browser are a great way to tell the user: “Thank you for choosing the Internet. Please stay on hold and a server will respond to your request shortly. This request may be monitored for quality purposes. (cue soft jazz by Albert, Herb). Every AJAX design should plan to give visual feedback when processing is underway. AJAX toolkits should make this easy.

Also, AJAX should never annoy the user. There is a good potential of AJAX being the next <blink> tag.

posted by scott with 3 Comments

Thoughts On AJAX

Wally asks: “What is AJAX?”

I hope AJAX will be invisible. I hope developers don’t have to think about AJAX anymore than they think about the inner details of the HTTP protocol. I have no inside information on the ASP.NET team’s Atlas project yet, but I’m hoping to use it like so:

<asp:Image runat="server" ID="MagicImage"

           ImageUrl="32457.png"

           AsyncPostBack="true"

           OnDrag="MagicImage_OnDrag"

/>

The above snippet demonstrates two features:

1. High frequency events like ondrag, which we previously could only handle with client side script, will be available on the server.

2. The presence of an AsyncPostBack property indicating a control initiates a “lightweight” postback.

JavaScript would perform the lightweight postback asynchronously. The script should communicate back to the server with as little payload as possible, but with enough information (viewstate and other form values) to execute the typical page lifecycle.

On the server, life goes on as usual. We respond to events using .NET code, execute queries, data bind controls, set control properties - yadda, yadda. During the MagicImage_OnDrag event, we might set the control’s ImageUrl property to a new value. A new Page property, IsAsyncPostBack, will let us skip code that we know we don’t need to execute during a lightweight postback.

The server responds by grabbing rendered HTML for the controls marked with AsyncPostBack=”true” and piping bits back down the wire. Client side script parses instructions in the results and updates a subset of form fields and controls using the DOM.

All of the JavaScript I’m talking about is baked into the framework. All I need to do is set an AsyncPostBack property, wire up an event handler, and write C# code.

Too simplistic?

posted by scott with 11 Comments

ASP.NET Themes On A Sunday Afternoon

I was looking forward to softball this weekend. I had a feeling the coach would move me from 3rd base to the shortstop position because our regular guy was out this week, and I was right.

In the 3rd inning I fielded a well hit double play ball. I turned to throw to second when *BAM*. It felt like someone hit me in the back of a leg with a steel pipe. My teammates said I just collapsed.

I remember laying in the dirt thinking “so, this is what it feels like to rupture an Achilles tendon”.

Fortunately, the X-Rays came back negative this morning.

The doctor told me to rest with my feet elevated and a computer in my lap. Ok, he didn’t mention the computer part, but that’s how I had planned to spend my Sunday in any case, though I hadn’t planned on ice packs and Ibuprofen.

To make a long story short, I finished “Themes In ASP.NET 2.0” today. I hope you enjoy the article.

posted by scott with 33 Comments

Eureka!

Many experienced developers do not like the new ASP.NET 2.0 project and compilation model at first, including myself. It was new, it was different, and I felt I had lost total control of my code base. In his post “VS 2005 Beta 2 IDE and web projects evaluation - level 200”, Jeffrey Palermo feels the new model is suitable only for the hobbyist, and is leaning towards using class library projects to develop applications in ASP.NET 2.0.

With ASP.NET 1.1, creating a web application as a class library instead of a web project was worth the trouble - if for no other reason than to get away from the infuriatingly fragile dependencies between web projects and IIS. These problems are gone in 2.0, and by taking matters into your own hands you’ll be missing out on more than just designer support.

The Moment

I realized I had the “Eureka!” moment when I could sum up the differences between 1.1 and 2.0 as follows:

In ASP.NET 1.1, the runtime code generation and compilation works for you.

In ASP.NET 2.0, the runtime code generation and compilation works with you.

Subtle difference - big payoff. What does it mean?

In the 1.1 code-behind model, all of the code-behind files compiled at the same time and into a single assembly. At some later point, a request would arrive for an ASPX page. The runtime would parse the ASPX to generate code, compile the code into a temporary assembly, and partner the code-behind class and the web form together via inheritance.

Unfortunately, the partnership doesn’t always work out. In fact, the partnership can end in the ultimate disaster - a runtime error. This can happen when a control declared in the code-behind doesn’t match a control with runat=”server” in the ASPX. This is just one example of why compiling code-behind separately from the web form makes for a fragile alliance between the two parties.

The code generation in 1.1 has no “value add”, as the cool people say. The run-time is merely working for you on an assembly line - punching together pieces to spit out HTML, but with no regard for defective parts.

In 2.0, the runtime will code-gen an ASPX page, then compile the generated code and the page’s associated code-behind at the same time, and into the same assembly. This allows the runtime to work with you, and enhance your code (a “value add”, as the cool people would say).

For example, you can have a strongly typed Master property in your code-behind by adding an @ MasterType directive to the ASPX page. The runtime will add the strongly typed property to the other half of your partial code-behind class with a new (shadows) keyword to hide the base class’s Master property. Instead of fumbling around with type casts and FindControl, we have custom tailored code for the job at hand. The code is more robust. This is what professionals expect from code generation.

Other Examples:

  • No more web controls declared as fields that don’t exist in the ASP X page.
  • Precompilation, including the ability to lock down updates in a production application.
  • Use @ PreviousPage to give your code-behind a strongly typed reference to another web form.
  • Use the @ Reference directive for strongly typed user control references
  • A strongly typed Profile object
  • A strongly typed ApplicationInstance property
  • Only asthetics differentiate inline code and code-behind models.

I’m sure the list could go on, but this is all I’ve covered so far in the huge feature set of 2.0.

Give the new model a chance to work with you, your design will thank you.

posted by scott with 5 Comments

Speaking Of Debugging…

I’ll be in the SmartClient track at VSLive! 2005 Orlando to give a presentation on Debugging in Visual Studio 2005. There are too many fantastic speakers and topics at this conference to list here, so I’ll just point you to the agenda.

With new features like Visualizers, DataTips, and Tracepoints, the 2005 debugger is better than ever. This presentation will be one hour of fun.

posted by scott with 0 Comments

Page Controllers and Stand-alone Code Migration

The recently unveiled “Common ASP.NET 2.0 Conversion Issues and Solutions” document is a must read for anyone who plans to move a 1.x web application to ASP.NET 2.0.

The document explains why one of the thornier areas will be fixing stand-alone (SA) class files that reference types in a code-behind (CB) file. In 1.x you could add stand-alone .cs or .vb files to a web application, and the code inside the files could reference any type in the web project because all the files compiled into the same assembly – the one you find in the bin subdirectory.

In 2.0 the stand-alone files will move to the App_Code directory and compile into a different assembly than the code-behind classes. Because all of the web form and user control assemblies will reference App_Code and not vice versa, you simply can’t reference web form and user control types directly from App_Code (or any class library, because there is no one “web” assembly to reference anymore).

The conversion document linked above points out how this situation causes problems with SA class files using LoadControl and requiring strong typing. The situation is also causing difficulty for people who have architected an application using Page controller patterns and pushed the responsibility for interacting with forms and controls into helper classes. The migration wizard moves the helper classes into App_Code where they cannot see any of the types they need to interact with.

Stubs to the rescue

The recommended solution is to create a stub class. A stub is an abstract base class from which the Page and UserControl code-behind classes will derive. The stub will be usable from a helper class since the stub will also live in  App_Code. In the final, released version of Visual Studio 2005, the migration wizard will generate stub class for you, however, chances are good that a bit of hand written code will give you greater flexibility and be a better fit for your  architecture. Here is one example of how to make the scenario work, even with Beta 2.

Let’s pretend you wrote a user control to let the end-user enter quotes from famous celebrities. A form with the control might look like screen shown here, with two TextBox controls and a button to click.


Now you need to interact with this control from a helper class, but the helper class lives in App_Code. The first step would be to define a stub in App_Code. My suggestion would be to derive from System.Web.UI.UserControl only if the helper class needs to interact with the entity as a control. In other words, if the helper needs to invoke the FindControl method or the touch the Attributes property, derive from a class in System.Web. For example:

using System;

 

public abstract class QuoteInputControlBase :

                      System.Web.UI.UserControl

 

{

    public abstract string Name

    {

        get;

    }

 

    public abstract string Quote

    {

        get;

    }

}

Typically a helper class isn't too interested in the presentation of data, so won't need the Attributes property. Often times a helper class doesn't need to know an object is a UI control at all. In our example we are only interested in getting at the text values inside the control. Since we don’t need to interact with the object as a user control, let’s define an interface instead.

public interface IQuoteInput

{

    string Name

    {

        get;

    }

 

    string Quote

    {

        get;

    }

}

Then in our user control code-behind file, we need only add the interface to our derivation list and provide a suitable implementation, i.e:

using System;

using System.Web.UI;

 

public partial class CelebrityQuoteInputControl :

                     UserControl, IQuoteInput

{               

    public string Name

    {

        get { return NameTextBox.Text; }

    }

 

    public string Quote

    {

        get { return QuoteTextBox.Text; }

    }

 

    protected void Page_Load(object sender, EventArgs e)

    {

        // typical user cotnrol load goo...

    }

 

}   

The helper class now only works on an IQuoteInput, which could be coming from anywhere. All the page controller needs to do is hand off a reference to the user control and away we go.

using System;

 

public class QuoteHelper

{

    public void Init(IQuoteInput input)

    {

        if (input != null)

        {

            name = input.Name;

            quote = input.Quote;

        }

        else

        {

            throw new ArgumentNullException("input");

        }

    }

 

    public void DoSomethingInteresting()

    {

        // ...

    }

 

    string name = string.Empty;

    string quote = string.Empty;

}

Still awake?

I think the new compilation model will force better design into some applications by requiring an approach similar to the above. I never felt comfortable seeing Page and UserControl derived types consumed outside of their own definitions.

P.S. Tom Cruise really did say that.

posted by scott with 13 Comments