Thursday, November 30, 2006

The evil designer attribute ;o)

I'm working on a project at the moment where the client want's an "Add-in" for an existing piece of software... it's a COM interop project, .Net 2.0 (and yes, it uses Castle, IoC sits in nicely with the IServiceProvider :) and it hosts a custom designer, and the add-ins must exist in their own directory, outside of the host applications base directory.

At any rate, it's been working just fine so far, but today I was trying to introduce some custom designers... and they weren't being constructed... which highlighted some odd behaviour in the design time support - I have 6 or so assemblies, most are support assemblies, some containing controls and their associated designers, something like this:

public class MyButtonDesigner : ControlDesigner { ..}

[Designer(typeof(MyButtonDesigner))]
public class MyCustomButton : ButtonBase { .. }

And then there is the core assembly which hosts the design surface etc. and contains a number of  COM-visible classes - one of these class in the core assembly is constructed via Com interop by it's Name, and everything starts it's life from there in their Add-in, much like a Main class in a WinForms project.

So the core assembly references the support assemblies, and has no problem creating controls at runtime within these assemblies...

But then...

However, the design time support fails to construct or make use of the custom designers... and doesn't blow up, it just fails silently - personally I hate this kind of behaviour... I like things to fail fast, in your face :)

It appears the custom designer is never constructed because the design time infrastructure fails to locate the assembly it's held within, even though my code has just created an instance of a control from the same said assembly not an instant before... arghh!

To my mind this is madness... I'm not passing a string reference to the type, and the assembly is already loaded, it should be as simple as using the Type in the attribute to create an instance of the designer - looking at the internal implementation of this attribute, I can see where it all goes terribly wrong:

public DesignerAttribute(Type designerType)
{
      this.designerTypeName = designerType.AssemblyQualifiedName;
      this.designerBaseTypeName = typeof(IDesigner).FullName;
}

It's still a puzzle as to why this isn't being resolved... the assembly is already loaded against the current AppDomain - I guess I could mess with the fusion logger to figure it out, there must be some subtle different - but I didn't have the time to waste, so I just cheated, implementing an AppDomain.AssemblyResolve event handler to take care of returning the assembly that's already loaded when matching against a set of pre-loaded assemblies.

I think the silent failure is what annoys me the most, this is something which could be easily introduced and might not be imediately detected when performing a minor update... I'm still not sure how I could write a test to detect it...

Speaking of custom designers... I'm unimpressed by how most custom designers are marked internal... especially for classes that are designed to be subclassed... why the hell is the ButtonBaseDesigner marked internal?

posted @ Thursday, November 30, 2006 10:13:37 AM (New Zealand Daylight Time, UTC+13:00)    Comments [0] | Trackback | Tracked by:
"Business Banks Need to be More Switched On" (Small Business Banking Solution) [Trackback]
Search
FeedCount

Tags...
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation