Server Controls, UniqueID and Master pages

Published on 27 March 2008

Recently I was updating some ASP.NET pages for a client. They had a set of custom-built server controls that worked very happily, binding data to and from domain objects. I modified some of the ASP.NET pages so that they became Content pages that shared a common Master page. Then suddenly all the Server controls stopped working - they were not processing postbacks properly or firing events. That is, Server Controls that had worked in normal ASP.NET pages suddenly stopped working in Master-Content pages.

Eventually I tracked the problem down to the overridden Render method in the Server Controls, and the id that was rendered to HTML. If you Render your Server Controls like this:
protected override void Render(HtmlTextWriter output) { // . . . output.AddAttribute("id", this.ID); output.AddAttribute("name", this.ID); output.RenderBeginTag("input"); output.RenderEndTag(); // . . . }
... and the control also implements IPostBackDataHandler (with the LoadPostData method and so on), the control will work as long as it is not inside a composite control or a control container.

However, if you put the control inside a control container (such as a ContentPlaceHolder in a Master-Content page), ASP.NET will no longer be able to figure out how to map the Form data that gets posted to the server back to the control. Hence LoadPostData (and RaisePostDataChangedEvent) will not get called.

This bug is easily fixed - the html ID and Name of your control should be rendered using UniqueID, as follows:
protected override void Render(HtmlTextWriter output) { // . . . output.AddAttribute("id", this.UniqueID); output.AddAttribute("name", this.UniqueID); output.RenderBeginTag("input"); output.RenderEndTag(); // . . . }
(In fact, "id" might not be needed at all, but is useful. "name" is the one that maps Form data on postback)

Of course, most documentation stresses that Server Controls should render using UniqueID if they want to catch postback data (Here's the MSDN documentation on Capturing Postback Events in Server Controls). But this might catch people out, because if you use ID instead of UniqueID, your control might happily work for years until you put it into a control container.

See also: MSDN - Developing Custom Controls: Key Concepts