Feature Request (Contract names)

Jan 28, 2009 at 10:48 PM
I know this may be a bit of a cheeky location to place this request, but it's a fairly fundamental request, so forgive the intrusion...

I would like to see a fairly trivial (to implement) change made to the export/import contract name usage, which in my opinion would be valuable for composite applications (at least it is for mine):

Currently, the export and import attributes when fed a type (the common usage), derives the contract name from the type's name and namespace but does *not* consider or include any other information which identifies the type, so on the following code snippet...:

namespace MyStuff {
interface IMyContract 
{
void DoSomething() 
}
}

[Export(typeof(IMyContract)]
public class MyAddIn : IMyContract
{
public void DoSomething() { // actually doing nothing in this example }
}

In the above example, the contract name derived for the export will be 'MyStuff.IMyContract'.

The problem I have with this is that in a composite application the above is (my contention - very) prone to naming collisions between contract names.  
Now, it's true that the publisher of the contract could choose to do one of the following:
a) define this instead using a more specific namespace to limit chance of name collisions
b) use a string argument for contract name instead and make sure the contract name is specific enough to limit chance of collisions
c) apply a ContractType attribute to the IMyContract type and make sure the contract name argument for this is a specific string.

One of the above is necessary (I would argue) to avoid naming collisions in composite apps because they do not include or make use of the unique identifying information which is already part of .NET - that is publisher public key (or public key token), and version number.

Unfortunately with .NET metadata you must use constants, so I can't state "Export( typeof(IMyContract).AssemblyQualifiedName) )"

So, what I'd like to see provided is one of the following options:

1.) Optional specifiers on the Export and Import attributes that force the use of and inclusion of the publisher public key (or token) and/or the version number from the type's container assembly.
e.g.: '[Export(typeof(IMyContract), UsePublisherKey = true, UseVersion = true)]'
2.) Optional specifiers on the ContractType attribute which force use of type name and inclusion of public key token and/or version number of the type's assembly.
e.g.: '[ContractType(UsePublisherKey = true, UseVersion = true)]'

I know of course, that I could manually include this information in the string, or could come up with a naming scheme for a string which includes this information, but basically... this is a pain.  It means that each time I update the version number of an assembly I have to remember to manually update the version number of the string associated with each and every contract type within the assembly.  It also means I have to use strings (error prone) and have to manually disambiguate...  the point is it's painful.

What do you think?  Is there any chance the MEF team would be interested in supporting one of these options?

Thanks.
Regards,
Phil

Jan 28, 2009 at 10:56 PM
Note, my preference would be for the second option - to allow specification via application of ContractType, that a type's contract name should include the type's assembly public key token and/or version since this would allow users of the contract to continue to use the shorthand 'Import[contractType]' and 'Export[contractType]'.

One other option which might be interesting would be for the MEF framework to allow plug-in of alternative metadata attributes which supply a contract name.  This would allow developers to come up with their own attributes which govern contract naming.  If MEF supported something like this then it wouldn't be necessary to alter the ContractType attribute, instead in this case I could develop my own metadata attribute which supplied the contract name.  It would seem a similar pattern could be used as that already used for strongly typed export metadata.

Regards,
Phil

Jan 28, 2009 at 11:16 PM
Hello Phil, 
Can you share more on your app scenario and what makes this feature particularly important for you? 

Thanks
Jan 29, 2009 at 6:51 AM
Sure - I'm developing a composite application which supports open-ended extensibility.  The application has certain extension points and associated contracts included but also allows addin publishers to define extension points and contracts of their own.  All of which I know is handled inherently by MEF but I have concern over the possibility of contract name collisions between third party publishers and other third party publishes or with ourselves - since our extension points and contracts may be added to over time.

Come to think of it - one critical detail which may help understand why naming collisions are possible: the host application itself hosts the complete addin catalog, so naming collisions between contracts defined by different contract publisher will cause critical problems - an addin publisher who defines a contract and performs an import (using the catalog provided by the host) will have incompatible addins imported if a name collision occurs.

So, I would like to eliminate the potential for naming collisions by taking advantage of assembly identity.  Inclusion of the assembly publisher key would avoid conflicts between different publisher's contracts.  Inclusion of the assembly version would allow release of new contracts that are differentiated via this version.  Although there may be arguments for not including version number - since it would allow changes without breaking compatibility in our particular case I intend to enforce contract immutability - that is contract may NOT change once published.  The reasoning for this is the same as (or similar to) the reasoning behind System.AddIn adopting this approach - to allow addin host and addin to version independently providing the contract does not change.  As a note, I did originally look into using System.AddIn for this application but it proved unsuited to developing composite apps which have more than one level of extensibility.

The rationale for some of these decision also relates to the way I have decided to tackle addin packaging and deployment issues - how to deploy addin assemblies and their dependencies post host application install.  Particularly how to avoid file name conflicts and how to ensure that the client of a contract and the supplier (implementer) of a contract are using the exact same contract.  I won't go into that here (as I'm sure I've already veered way off topic) but it makes use of assembly hash to compare contract assemblys whch have matching strong names.

Anyway, apologies if I've not made it any clearer - I'm sometimes not great at explaining.

Did this make it clearer?  as mud? :)

Regards,
Phil

Feb 1, 2009 at 10:44 PM
pspidey,

Sorry if I've missunderstood you, it's been a long day and my reading comprehension isn't at it's peak right now. If I read it correcly you could like for the import/export attributes to use the AssemblyQualifiedName as the contract name when fed a typ?
Feb 2, 2009 at 2:29 PM
Precisely, yes - I'd like to use the assembly qualified name.  I'd like each of the metadata attributes (ContractType, Export and Import) to support this.  If the current behavior where the type's simple name (namespace + type name) is to be preserved as the default for contract names, then this could be achieved through the addition of a flag whose inclusion would force each attribute to use the assembly qualified name.

As an aside, I do wonder a little about the decision not to use assembly qualified name - not saying it's wrong but it shows different design decisions to System.AddIn.

The one other thing which I mentioned is that it occurred to me that if MEF where to allow users to supply alternatives to ContractType then this could be used to plug in your own naming systems, and I could use it in this case to use assembly qualified names.  I guess the same might apply to exports and imports.

Regards,
Phil

Feb 2, 2009 at 2:40 PM
Phil,

First of all I would like to point out that I am not part of the MEF team, nor do I have any influence on the design of the framework. That said, I'm developing a custom programming model for MEF where the definition of imports and exports are based on a provider model. The current implementation supports configuration and a fluent api for defining parts, but after reading your post I started experimenting with adding an attribut provider on it and the initial test looks promising (I'm using assemblyqualifiedname internally of that provider). The project will be released on MEF Contrib within a couple of weeks, as a first preview version.

I would also like to point out that in the current release of MEF, the contract attribute has no impact on the behaviour of the framework - it syntactical sugar for discoverability as I describe here http://www.thecodejunkie.com/2008/12/purpose-of-contracttypeattribute-in-mef.html
Feb 2, 2009 at 9:04 PM
That sounds very interesting code junkie, and I'd certainly like to take a look at it.

I'd still like to see the support for alternative contract naming conventions, particularly assembly qualified names, baked into MEF.

On the contract type attribute, the reason I mention the attribute is that it can also be used to override the contract name for a contract used whenever code uses typeof(contractType) on an import or export.

So, if I have:

[ContractType("Foo's Contract!")]
interface IFoo
{
}

Any import which uses import or export with typeof(IFoo) will use the contract name specified by the type's contract type attribute ("Foo's Contract!") - a nice way of overriding the default name used when supplying a type argument for import and export.

What occurred to me with this is that if MEF instead of checking the type specifically for the ContractTypeAttribute, it checked for attributes which implement an interface (e.g. 'IContractType') I could implement my own attribute class which provides an alternative naming convention.  In this case my attribute class would provide assembly qualified names to MEF.

This sounds like a very attractive option to me since it obviously would allow any developer to come up with their own custom naming scheme for contract names derived from types.

Definitely interested in taking a look at your project though when it's released.

Cheers,
Phil