April 2004 - Posts

ASP.NET For Girls Only

Note: this entry has moved.

On 4th May I will be doing a presentation on ASP.NET v1.1 @ Microsoft Argentina. I’ll be covering state management and an overview of custom control development.

 

One particular thing about it it’s the audience… it’s for a user group named “Desarrolladoras.NET” which in english should read “DevGirls.NET” or something like that.

 

I’m looking forward nothing but fun… :-)

 

Posted by vga with 2 comment(s)
Filed under:

Whidbey support for HtmlHead, Intro

Note: this entry has moved.

Very simple questions as “How can I programmatically set my Page’s title from codebehind?” or “How can I handle my Page’s <head> element from codebehind?” were, are and will be asked about every single day in the public newsgroups, forums, etc.

 

This is because v1.x doesn’t include any built-in support for handling the <head> element or any of its children elements.

 

This leads to the common approach of adding the runat=’server’ attribute to the <head> element and then handling it as a HtmlGenericControl. Pretty simple and pretty unfriendly stuff at the same time. In addition, having VS.NET removing the attribute at will just make things more annoying.

 

After looking at all the feedback from newsgroups, forums, etc, it was pretty obvious that something was needed. Because of this, the HtmlHead control was born in the PDC03 bits (and others like HtmlTitle and HtmlLink did appear in the March04 bits). The Page type itself was modified to include these additions and new properties were added: Header (in the PDC03 bits) returns an instance of a type that implements IPageHeader (HtmlHead in this case) and Title (in the March04 bits) just wraps a Header.Title call.

 

So now, this is how you handle this very common need in the Whidbey bits:

 

void Page_Load (object sender, EventArgs e) {

     this.Header.Title = “This is a title”;

     this.Header.LinkedStyleSheets.Add (“classicblue.css”);

     this.Header.Metadata.Add (“author”,”clarius”);
}

 

Pretty simple, ugh? No doubt, this is a good addition. Hopefully all the confusion and how-to questions that plagued the newsgroups about how to deal with this in v1.x won’t be there for v2.0 (now that’s a wish).

 

While playing with this new supported I discovered a few “issues” that I describe in these posts (warning: the following info may be more than you ever wanted to know about <head> and its child elements):

 

Whidbey Support For HtmlHead, Part I – What title will be rendered?

Whidbey support for HtmlHead, Part II – Not only VS.NET messes up your markup

Whidbey support for HtmlHead, Part III – The missing ViewState

 

Posted by vga with 4 comment(s)
Filed under: ,

Whidbey support for HtmlHead, Part III

Note: this entry has moved.

The third interesting observation worth noticing from HtmlHead and co. (that is, HtmlLink, HtmlHead, etc) is that they know nothing about state management… viewstate? what’s that??

 

The PDC03 bits didn’t include any state management code and the March04 bits still haven’t changed this. Bottom line: if you’re planning to dynamically alter the page title, the links or metadata elements you’re definitively out of luck (well… you can always implemented the code yourself…).

 

Let’s take for instance the HtmlTitle control: it’s a very simple (really, very simple) control that derives from HtmlControl overriding only two methods (AddParsedSubObject and Render) and adding a property named Text.

 

The get and set accesors for the HtmlTitle.Text property read and write a private member variable instead of using viewstate as its storage; any changes made will be lost on postback.

                                                            
The same holds true for metadata and links elements, any modifications made at runtime are lost on postback.

 

All this new support for the head and its child elements is really a very welcomed one, but won’t be of much use without state management implemented. Let’s just hope that state management for these controls is already planned but not there only because March04 is not a feature complete build.

 

Posted by vga with 1 comment(s)
Filed under: ,

Whidbey support for HtmlHead, Part II

Note: this entry has moved.

Now its turn to peek at how <meta> child elements are being supported. Let’s take for example the following markup:

 

<head runat=”server”>

     <title>Foo</title>

     <meta name=”one” content=”uno” />

</head>

 

As the <head> element has a proper runat=”server” attribute, it will be parsed as an instance of HtmlHead and you will be able to programmatically play with it at runtime like this:

 

this.Header.Metadata.Add (“two”,”dos”);

 

What output would you expect from the previous code?


This one:

 

<head runat=”server”>

     <title>Foo</title>

     <meta name=”one” content=”uno” />
     <meta name=”two” content=”dos” />

</head>

 

Or this other real funny one:

 

<head runat=”server”>

     <meta name=”one” content=”uno” />
     <title>Foo</title>

     <meta name=”two” content=”dos” />

</head>

 

Of course you should expect the first one, but with the March04 preview bits you’ll get the second one.

 

What causes this strange reordering of the tags? Uff... I mean… once we finally got VS.NET to *never* touch our markup now it’s the HtmlHead control that decides to rearrange them in the previously shown “clever” way of meta-title-meta

 

Let’s try to shed some light on what’s happening here…

 

HtmlHead has associated a control builder, HtmlHeadBuilder. By looking at HtmlHeadBuilder.GetChildControlType we can tell that it only recognizes two different child types: HtmlTitle and HtmlLink. There is no recognition here for the <meta> element, moreover, there is not even a HtmlMeta control (as there are HtmlTitle and HtmlLink ones).

 

This means any <meta> elements that you may specify at design-time will be parsed as a single LiteralControl.

 

When it is time to render, HtmlHead rendering basically does the following (warning: very-simplistic-pseudo-code-follows):

 

-          Render HtmlHead’s child controls (this will render the LiteralControl containing the <metadata> specified at design-time)

-         Render HtmlTitle (or a blank <title></title> if none is found)

-         Render Metadata items that were added programmatically

 

Remember our <meta> elements specified at design-time were parsed as a single LiteralControl and added to HtmlHead’s control collection. So they will be rendered before any other output of the HtmlHead control.

 

I’m hoping for this funny reordering to go away soon. I believe that modifying HtmlHeadBuilder to recognize childs of type HtmlMetadata (and adding such a control in the meantime) will make everyone (or at least me!) happy.

 

Posted by vga with 2 comment(s)
Filed under: ,

Whidbey support for HtmlHead, Part I

Note: this entry has moved.

Any current page that has more than a <title> element, i.e.:

 

<head>

     <title>Title One</title>

     <title>Titlo Two</title>

</head>

 

Is violating the HTML401 spec which says that only one <title> element is allowed.

 

But spec compliance aside, nothing stops current ASP.NET pages to specify such markup. The end result will be that both elements will be rendered and browsers (FireBird/Fox, poor-old IE, etc) will only take into account the first <title> found.

 

So far so good.

 

Now, while porting your pages to Whidbey you need to add a runat=”server” attribute to the <head> element in order for some of the built-in functionally to work.

 

Which one would you expect to render as the title? “Title One” or “Title Two”?

 

You know that the ASP.NET Team is pushing hard for zero breaking changes, so you would expect “Title One” to render, just in case you have some really ugly javascript code that depends on the page’s title.

 

But… if you try this against the March04 preview the browser will render “Title Two”…

 

So far not so good now.

 

If you look at the rendered markup you’ll notice that only a single <title> element is being rendered now, where on earth did the other <title> element went?

 

The answer lies down in the HtmlHead.AddParsedSubObject method which is coded in a way that when it detects a child of type HtmlTitle it saves a reference to it using a private member variable. It doesn’t check if it has already assigned an HtmlTitle already so when the second HtmlTitle child is processed it just overwrites the first one.

 

When it comes down to rendering the control has saved only one HtmlHead, and it is the last one processed thus we get a different <title> than the one we should get when running the page in v1.x bits.

 

I believe that modifying the HtmlHead.AddParsedSubObject to only save the first HtmlTitle child found and just ignoring any following childs of the same type would be a more friendly approach. (Of course what I really would like is to throw an exception yelling “Hey Joe, you have specified more than one <title> element, go read the spec!” but that could be considered a really breaker :-)  )

Posted by vga with 2 comment(s)
Filed under: ,

Depending hard on being inserted into the control tree

Note: this entry has moved.

This morning while I was waiting for an ASP.NET talk at the MVP Summit I noticed that my weblog was a *bit* outdated… so I decided to blog about one of the 5783 things that I was saving for later.

 

Some controls tend to depend on being added to the control tree in order to work properly before they can be used. For example, it’s common to see code like this in a Control’s Render method:

                                           

base.Page.GetPostBackClientEvent(this, "");

 

this will cause an exception if you use the control in a way like this:

 

MyControl a = new MyControl ();

// MyControl is never inserted into the control tree

// because of this Page property will be null

// MyControl.RenderControl uses Page, bad things will happen

a.RenderControl (writer);   

 

The solution to this is to program the control’s Render method in a more flexible way, that is, considering that the control may not be inserted into the control tree while someone may still want to get its rendering, i.e.:

 

if (base.Page != null)

base.Page.RegisterRequiresPostBack (this);

 

Of course if you’re dealing with a third-party or built-in ASP.NET control you just can’t modify the way the control was coded. So what?

 

Play nice as the CheckBoxList does

 

Insert the control to the control tree just so it gets its properties properly set (Page, ID, etc). This is actually what ASP.NET’s CheckBoxList control does in its public ctor: it instantiates a CheckBox and inserts it into its control tree. It is safe then to call CheckBox.RenderControl because its Page property will be already set, i.e.:

 

MyControl a = new MyControl ();

Controls.Add (a);

a.RenderControl (writer);

 

Or cheat do as the RadioButtonList does

 

UPDATE: I just checked and Control.Page property does has a set accesor, so I believe I may have been confused by the compiler inlining the call to the set accesor.

Instead of adding it to its control tree, RadioButtonList will set the Control.Page property by using code like this:

 

MyControl a = new MyControl ();

a.Page = this.Page

 

Relax a bit, as Whidbey does

                                              

Obviously if its makes sense for some of the functionality of your control to be used even if it’s not inserted into a control tree then by all means you should make that easy for the developers using your control; this means that every time you write code that uses the Page property you should check if it’s non-null.

 

Both CheckBox & RadioButton in v1.x don’t follow this advice. At some point they assume that Page will be always non-null and that’s why any of the previous two detailed solutions will be needed.

 

Luckily Whidbey changes this. The new CheckBox & RadioButton had been modified to relax a bit their dependencies on being inserted into the control tree. They now carefully check Page being a non-null reference before trying to use it.

 

Posted by vga with 3 comment(s)
Filed under: ,
More Posts