Friday, November 10, 2006

ASP.NET 2.0: Ambiguous match exception

Just ran into an ambiguous match exception which seemed to appear out of nowhere. A perfectly good ASP.NET 1.1 website starts throwing the 'Ambiguous Match Exception' when switched to ASP.NEt 2.0. I didn't recompile, or anything. To complicate things a bit, the Ambiguous match exception doesn't state why it is occuring. I guess Microsoft decided to pay tribute to the exception's name ;) Anyways, I figured it out using various blogs. ASP.NET 2.0 uses partial classes, where ASP.NET 1.x uses plain classes. 2.0 will automatically declare all named controls (controls that have an ID) as members of the final class. If a control ID overlaps with a (protected) member already declared in the class the exception occures. Note that this issue doesn't seem to occur using the ASP.NET development server. Check out these links for more info: Peter Johnson's Blog: Ambiguous match found. Advanced .NET Debugging: "Ambiguous match found" in a Web Control - a Possible Bug

Friday, November 3, 2006

ASP.NET 2.0 : Hierarchical datasources

While implementing a virtual file system for a customer I found myself in need of a custom hierarchical datasource. As usual, the MSDN website offered a good sample of such a class. Easy right? Anything but easy as it turns out. The sample code is all wrong. I ended up reading IL code to figure out how the SiteMapDataSource works. Reading IL is not exactly my idea of easy. Turns out the problem is in the way the HierarchicalDataSourceControl and HierarchicalDataSourceView interact. The DataSource control is supposed to be the workhorse of the two. The view is just a container for the results. In the sample however, the converse is true. That set me off in the wrong direction... The easiest thing to do is this:
  1. Create a node class that implement IHierarchyData
  2. Create a control derived from HierarchicalDataSourceControl.
  3. Create a specialized collection to hold your nodes and implement IHierarchicalEnumerable
  4. Implement a HierarchicalDataSourceView
  5. Override the GetHierarchicalView method in the HierarchicalDataSourceControl.

The first four steps are easy. Create the classes and implement the methods, pretty straight foreward. Using generics the collection just requires an implementation for IHierarchicalEnumerable.GetHierarchyData which can be as simple as a type cast since the node class implements IHierarchyData. I'll get back to implementing the nodes later. Implementing the HierarchicalDataSourceView is not that difficult either. It's just a wrapper around your collection. Store a copy of your collection class and return it in the Select method. That's all.

Overriding the GetHierarchicalView method
This is the method that does the actual work in the HierarchicalDataSource. The role of the viewPath parameter is the key to making this work; use it like a query. If you're loading objects from a database like me, the viewpath should be the unique key to the object. In the implementation use the viewPath to decide what to do:

  • If the viewPath is empty, use the root node of your hierarchy. If you want to include the root node in the hierarchy, return the root node itself. If you don't return it's children.
  • If viewPath is not empty, fetch the node pointed to by the viewPath and return it's children. This is crucial! Do not return the node itself, return it's children because when a view is requested for a node, it means the node was already returned in a previous call. If you return the node itself, the datasource will get stuck in an endless loop...

Implementing the nodes
The node implementation is nothing spectacular. Just make sure that the Path property returns something that you can process as a viewPath in your GetHierarchicalView implementation. If you want to bind a TreeView to your HierarchicalDataSourceControl you can use the Type property to hint the icon for the node. For example, when your hierarchy contains files and folders consider returning the mime type of the file so you can display the appropriate icon in the tree. I've compiled a simple ready-to-run sample (VS 2005) that uses a TreeView control to render the files in a given folder on disk.