A funny thing happened to me the other day, on the way to an ASP.NET 4.0 application that uses server-side AJAX and controls from the latest version of the AJAX Control Toolkit. I was building a sample page to show off some of the controls when I got this exception:
The important part of the message was this:
The server tag 'asp:BulletedList' is ambiguous. Please modify the associated registration that is causing ambiguity and pick a new tag prefix.
Ambiguous? That's odd. Here is the highlighted source code, the @Register tag that Visual Studio added to the page for me the first time I added a Toolkit control:
Bizarre, and as I dug into the problem, it got even more bizarre. I realized that in the latest version of the toolkit, Microsoft added a default tag prefix of asp by adding this TagPrefix attribute to AssemblyInfo.cs for the Toolkit:
The last major release of the Toolkit that I found, the one released for ASP.NET 3.5 SP1, didn't have a prefix defined. As a result, it used the default cc1 prefix for a server control.
As a result of the change in the latest version of the Toolkit, the Toolkit controls now use by default the same tag prefix as regular ASP.NET server-side controls. This almost kind of sorta makes sense, now that Microsoft is putting more effort into the Toolkit and is fully supporting it.
But why the message that the ASP.NET BulletedList server control is ambiguous? I had only a single instance of the control on the page, so there was no chance of a naming collision. Besides, that would be a different problem.
Ambiguous? That could really only mean one thing: I had two assemblies referenced in the project that have BulletedList classes defined. But how could that be? This sample application used only Microsoft off-the-shelf parts at this point. Nevertheless, I set out to find the ambiguity. Thankfully, Microsoft makes the Toolkit source code available, so I was able to find the problem.
The AJAX Control Toolkit defines its own BulletedList control. You'll find it in BulletedList.cs in the AjaxControlToolkit project, the ReorderList folder. It is a rather simple code file, as you can see below.
I was a bit confused about why they would include a control with the exact same name as the ASP.NET server control, but the comment you can see in the above figure attempts to explain why:
We create our own BulletedList because the ASP.NET one Takes ListItems rather than regular controls as it's children. \\[sic\\]
I have no idea why this justifies a control with the same name, but at least the author of this part of the Toolkit had a reason.
But the two controls are in different namespaces. The ASP.NET control is part of System.Web.UI and the Toolkit's is in AjaxControlToolkit. So there should be no naming collision, right?
Well, not usually. But therein lies the real problem. By placing two controls on the same page with the same name with the same prefix, it creates an ambiguity at runtime. Both controls are identified with the asp tag prefix, and there are two namespaces associated with that tag prefix. One is built into ASP.NET and the other is defined with the @Register directive that Visual Studio added to the page, using the settings of the AjaxControlToolkit.DLL assembly.
This is not usually a problem, as long as controls you use in the page have unique names. But that condition is violated in the case of BulletedList and Microsoft's decision to change the default tag prefix from cc1 to asp. Fortunately, it results in a reasonably descriptive error message that led me to the problem, albeit a bit indirectly.
Why did Microsoft do this? I've no idea, and I've found over the years that there are rarely any good answers to Why? questions about Microsoft. And so far my inquiries have led to no answers.
Fortunately, there are a couple of fixes, and they are reasonably easy. One fix is to change the TagPrefix attribute of the @Register directive that the Toolkit adds to a page from "asp" to something else. I like "act", which so far has not caused any other collisions. Or, if you use the Toolkit a lot and don't mind changing its source code, look for the AssemblyInfo.cs file in the AjaxControlToolkit project in the source code and change the following line to use something else, then recompile the project and start using the new assembly.
The long-term fix is for Microsoft to fix the problem with the Toolkit source code, so hopefully they'll do that with the next release. In the meantime, I hope my pain eases yours!