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.
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?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.
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.
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:
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.
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.
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.
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.
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.