MetadataType alternative in SL

Nov 21, 2011 at 12:41 PM

Hello,

I have implemented lot of custom export attribute, with metadata handling.

Ex : 
[MetadataAttribute]   
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]   
public class ExportIViewModelAttribute : ExportAttribute, IViewModelMetadata { }

All my ViewModels are Singleton (Shared in a MEF point of view).
So now I have to explicitly tell each class I export is shared. 
Ex :
[ExportIViewModel("DestinationSelectorWindow", typeof(DestinationSelectorWindowViewModel), null)]   
[PartCreationPolicy(CreationPolicy.Shared)]
public class MyClass() {}

I'm working with Silverlight, so there isn't MetadataTypeAttribute at all. And it's really boring to put [PartCreationPolicy(CreationPolicy.Shared)] each time I use my attribute...

So I'd like to know if there's a workaround in order to force classes using my ExportIViewModelAttribute to be implicitly shared ? ie : implicitly have the [PartCreationPolicy(CreationPolicy.Shared)] attribute by using a ExportIViewModelAttribute. And then, don't be forced to explicitly give CreationPolicy on each class...

Thanks in advance.

PS : MEF is the most revolutionary and powerful tool I have never seen ! But I have some remarks :
- Why did you name the ExportFactory attribute "Export something" while he is importing ? Why don't rename it ImportFactory ???
- When a Shared instance is imported, why do you keep hard references into MEF ? It should be really great if you provide a WeakReference alternative, and let developers control the referencing of objects. P-l-e-a-s-e !!!!
- Why do you provide the ExportLifeTime object ? IMO, it break the .Net way of managing objects, since it don't provider a real control over instance lifetime. (just disposal is implemented, and any object implementing IDisposable can be disposed in other way than using ExportLifeTime...) What's the real purpose of this class ?
- In MEF 2.0, you should implement methods on CompositionContainer letting developers import ExportFactories<T> and  ExportFactories<T,Tmeta> in the same way we can use container.GetExports<T,Tmeta>(). It really lacks.

Bests,

Raphaël DUCOM

Nov 21, 2011 at 7:43 PM

Hi Raphael,

By default MEF will treat parts without a creation policy as Shared, so you should in most circumstances (unless you’re importing them via ExportFactory) find that you can leave the attribute out and still get the behavior you require.

On your other questions (thanks for raising them!):

- Why did you name the ExportFactory attribute "Export something" while he is importing ? Why don't rename it ImportFactory ???

The objects created by the factory are essentially exports, so we use this as the basis for naming. For example, a Car Factory produces Cars, a Baked Bean Factory produces cans of tasty baked beans – so an ExportFactory produces Exports.


- When a Shared instance is imported, why do you keep hard references into MEF ? It should be really great if you provide a WeakReference alternative, and let developers control the referencing of objects. P-l-e-a-s-e !!!!

MEF considers the meaning of Shared to be ‘a single instance for the life of the container’ – using WeakReference would make it possible for multiple instances of a Shared part to exist through the life of an application, which is not the behavior we intend.


- Why do you provide the ExportLifeTime object ? IMO, it break the .Net way of managing objects, since it don't provider a real control over instance lifetime. (just disposal is implemented, and any object implementing IDisposable can be disposed in other way than using ExportLifeTime...) What's the real purpose of this class ?

When an object is returned from an ExportFactory, it may not implement IDisposable, however the parts that it depends upon (somewhere down the dependency tree) may implement IDisposable and need to be cleaned up. Because of the loose coupling inherent in a MEF application, there is no reliable way for a developer to handle this in all cases. So, MEF does this cleanup for you when ExportLifetimeContext is disposed. As with the above, we accept that there are pros and cons to this, but we’ve chosen a direction we think is the most reliable.


- In MEF 2.0, you should implement methods on CompositionContainer letting developers import ExportFactories<T> and ExportFactories<T,Tmeta> in the same way we can use container.GetExports<T,Tmeta>(). It really lacks.

We are hoping to guide developers away from using CompositionContainer in this fashion (as a Service Locator) so we’re not planning on extending its API in this way.

Hope this clarifies these points.


Regards,
Nick

From: rastakouer [email removed]
Sent: Monday, November 21, 2011 4:42 AM
To: Nicholas Blumhardt
Subject: MetadataType alternative in SL [MEF:280247]

From: rastakouer

Hello,

I have implemented lot of custom export attribute, with metadata handling.

Ex :
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ExportIViewModelAttribute : ExportAttribute, IViewModelMetadata { }

All my ViewModels are Singleton (Shared in a MEF point of view).
So now I have to explicitly tell each class I export is shared.
Ex :
[ExportIViewModel("DestinationSelectorWindow", typeof(DestinationSelectorWindowViewModel), null)]
[PartCreationPolicy(CreationPolicy.Shared)]
public class MyClass() {}

I'm working with Silverlight, so there isn't MetadataTypeAttribute at all. And it's really boring to put [PartCreationPolicy(CreationPolicy.Shared)] each time I use my attribute...

So I'd like to know if there's a workaround in order to force classes using my ExportIViewModelAttribute to be implicitly shared ? ie : implicitly have the [PartCreationPolicy(CreationPolicy.Shared)] attribute by using a ExportIViewModelAttribute. And then, don't be forced to explicitly give CreationPolicy on each class...

Thanks in advance.

PS : MEF is the most revolutionary and powerful tool I have never seen ! But I have some remarks :
- Why did you name the ExportFactory attribute "Export something" while he is importing ? Why don't rename it ImportFactory ???
- When a Shared instance is imported, why do you keep hard references into MEF ? It should be really great if you provide a WeakReference alternative, and let developers control the referencing of objects. P-l-e-a-s-e !!!!
- Why do you provide the ExportLifeTime object ? IMO, it break the .Net way of managing objects, since it don't provider a real control over instance lifetime. (just disposal is implemented, and any object implementing IDisposable can be disposed in other way than using ExportLifeTime...) What's the real purpose of this class ?
- In MEF 2.0, you should implement methods on CompositionContainer letting developers import ExportFactories<T> and ExportFactories<T,Tmeta> in the same way we can use container.GetExports<T,Tmeta>(). It really lacks.

Bests,

Raphaël DUCOM

Nov 22, 2011 at 1:50 PM
Edited Nov 22, 2011 at 3:12 PM
nblumhardt wrote:

Hi Raphael,

 

By default MEF will treat parts without a creation policy as Shared, so you should in most circumstances (unless you’re importing them via ExportFactory) find that you can leave the attribute out and still get the behavior you require.

Hi,


1)
I have built a "little framework" in order to manage my objects with MEF more easily.

public class SingletonManager<T, TMetadata>
        where T : class
        where TMetadata : IDeclareType
    {
        public SingletonManager(CompositionContainer con)
        {
            con.SatisfyImportsOnce(this);
        }

        [ImportMany(AllowRecomposition = true, RequiredCreationPolicy = CreationPolicy.Shared)]
        public IEnumerable<Lazy<T, TMetadata>> Imported { get; set; }

        public TDeclared InstanceOf<TDeclared>() where TDeclared : class
        {
            return [...] as TDeclared;
        }
	[...]
}

I have a similar class to handle "instance" case (CreationPolicy.NonShared) with ExportFactory.
So I encapsulate all the MEF logic behind some methods, making it "easier" developers to get singletons and instances, and avoiding strange uses of MEF... (and composition errors)

I'm in a case where, when a developer uses a custom [ExportIViewModel], this exports have to be decorated with [PartCreationPolicy(CreationPolicy.Shared)]
In the same way, when using  a custom [ExportIView] attribute, I want this export to be decorated with [PartCreationPolicy(CreationPolicy.NonShared)]

So is there something I can do in order to force the export which are made using my custom export attribute to have an implict CreationPolicy ?

And ... (I repeat), I have to be Silverlight compliant.... 

 

2) I'm not sure to understand the answer you made :

"When an object is returned from an ExportFactory, it may not implement IDisposable, however the parts that it depends upon (somewhere down the dependency tree) may implement IDisposable and need to be cleaned up."

Are you talking of a case where an Exported class have imported Properties ???

Because, in this case, in a non-MEF object, if the "container" object is selected for garbage collection, and have "contained" property members which are not referenced elsewhere, it's the the developer responsibility to correctly dispose the container sub-objects. And in most cases, we never care about, because when having a IDisposable object, we are used to implement the using(...) directive. And event if somebody forget it, I believe the GarbageCollector call the Finalize method in order to free internal IDisposable resources...
And in a non-MEF object, if we have sub-objects which really needs to be disposed, we are used to dispose it recursively...

So I really don't see what do you mean by "cleaning up the dependency tree".... And what case you are handling a developer can't handle in a MEF object, and can handle in a non-MEF object...

3) I don't agree with you about the following assumption :  "using WeakReference would make it possible for multiple instances of a Shared part to exist through the life of an application, which is not the behavior we intend"

I'm working on heavy SL apps, wich can easily grow up in memory... I'm used to have garbage-collectible singleton instances, implemented using a Lazy<> pattern, and, in order to free memory resources allocated by theses singletons (to garbage a singleton), a just set it's private instance to null... So the Lazy<> generic let me implement thread-safe "finalizable" singleton...

I'm not sure about the non-thread-safety of a weakreference implementation of a Lazy<T,TMeta> : thread-safety is assumed by the Lazy object, and I easily imagine a pattern where the Lazy.Value is a weakreference, and if this weakreference.IsAlive == false, then we create this reference again (in a thread lock of course)...

Something like this does not seems to break the Shared policy rule :

public class WeakLazy<T, TMeta> 
: Lazy<WeakReference<T>, TMeta>
{
        [...]
}

Am I missing a structural constraint ???

4) A really important point :

ExportFactory<T,Tmeta> is not shipped in the WPF version of MEF...
Are you sure to provide it with MEF 2.0 ?
When does MEF 2 will be released ?
(if your answer is "with .Net 5" or a similar one, can you give the release date? )

Right now I'm refactoring my SL apps using MEF, but since these apps will be translated in heavy client apps soon (WPF), I have to give guaranties to my direction about  the portability of MEF.... And this question is really critical for us...

And lastly :  
- does there exists a "stable" alternative ("production ready") of WPF MEF 1.0 which implement the ExportFactory<T,Tmeta> class ?
- does documentation on differences between MEF's SL and WPF  implementation exists somewhere ?



Thanks in advance for your answers !

Bests. 

Nov 22, 2011 at 4:39 PM

Hi Raphael,

To fully respond to your very interesting points we’d need to dig very deeply into MEF and composition, which unfortunately I don’t have time to do here. My apologies if these responses are abbreviated too much; hopefully in any case they will help you get the most out of MEF in the future.

1. Helpers for singletons/factories

MEF is very heavily geared towards dependency injection – that is, it relies on parts receiving their dependencies as imports, rather than having them call a central static method or property like SingletonManager<T>.Instance. Using dependency injection is really critical for getting a good experience from MEF. You’ve probably encountered many already, but there are some new resources available that explain this topic in depth if anyone on your team is interested in the underlying reasoning/mechanics (i.e. Mark Seemann’s book “Dependency Injection in .NET”).

There’s no way to set creation policy via a custom attribute today. When it becomes available, MEF 2 will cover this via RegistrationBuilder. In Silverlight at least for the time being you will need to use the attribute.

2. Responsibility for calling Dispose()

When doing loosely-coupled composition, components often take dependencies (imports) on interfaces rather than implementations. However, it is the concrete type of the import (not the interface) that determines whether there is a Dispose() method to call. Only the container has knowledge of the concrete types involved in a composition, hence the responsibility for disposing instances is given to it.

3. Weak references

Correct part lifetime management in Silverlight depends heavily on using dependency injection for imports, in conjunction with ExportFactory<T> where necessary. This really ties back into your first question. There’s no alternative today to using careful lifetime management with MEF.

Hope this helps.


Regards,

Nick

From: rastakouer [email removed]
Sent: Tuesday, November 22, 2011 5:51 AM
To: Nicholas Blumhardt
Subject: Re: MetadataType alternative in SL [MEF:280247]

From: rastakouer

nblumhardt wrote:

Hi Raphael,

By default MEF will treat parts without a creation policy as Shared, so you should in most circumstances (unless you’re importing them via ExportFactory) find that you can leave the attribute out and still get the behavior you require.

Hi,


1)
I have built a "little framework" in order to manage my objects with MEF more easily.

public class SingletonManager<T, TMetadata>
        where T : class
        where TMetadata : IDeclareType
    {
        public SingletonManager(CompositionContainer con)
        {
            con.SatisfyImportsOnce(this);
        }
 
        [ImportMany(AllowRecomposition = true, RequiredCreationPolicy = CreationPolicy.Shared)]
        public IEnumerable<Lazy<T, TMetadata>> Imported { get; set; }
 
        public TDeclared InstanceOf<TDeclared>() where TDeclared : class
        {
            return [...] as TDeclared;
        }
        [...]
}

I have a similar class to handle "instance" case (CreationPolicy.NonShared) with ExportFactory.
So I encapsulate all the MEF logic behind some methods, making it "easier" developers to get singletons and instances, and avoiding strange uses of MEF... (and composition errors)

I'm in a case where, when a developer uses a custom [ExportIViewModel], this exports have to be decorated with [PartCreationPolicy(CreationPolicy.Shared)]
In the same way, when using a custom [ExportIView] attribute, I want this export to be decorated with [PartCreationPolicy(CreationPolicy.NonShared)]

So is there something I can do in order to force the export which are made using my custom export attribute to have an implict CreationPolicy ?

And ... (I repeat), I have to be Silverlight compliant....

2) I'm not sure to understand the answer you made :

"When an object is returned from an ExportFactory, it may not implement IDisposable, however the parts that it depends upon (somewhere down the dependency tree) may implement IDisposable and need to be cleaned up."

Are you talking of a case where an Exported class have imported Properties ???

Because, in this case, in a non-MEF object, if the "container" object is selected for garbage collection, and have "contained" property members which are not referenced elsewhere, it's the the developer responsibility to correctly dispose the container sub-objects. And in most cases, we never care about, because when having a IDisposable object, we are used to implement the using(...) directive. And event if somebody forget it, I believe the GarbageCollector call the Finalize method in order to free internal IDisposable resources...
And in a non-MEF object, if we have sub-objects which really needs to be disposed, we are used to dispose it recursively...

So I really don't see what do you mean by "cleaning up the dependency tree".... And what case you are handling a developer can handle in a MEF object, and not handle in a non-MEF object...

3) I don't agree with you about the following assumption : "using WeakReference would make it possible for multiple instances of a Shared part to exist through the life of an application, which is not the behavior we intend"

I'm working on heavy SL apps, wich can easily grow up in memory... I'm used to have garbage-collectible singleton instances, implemented using a Lazy<> pattern, and in order to free memory resources allocated by theses singletons. In order to garbage a singleton, a just set it's private instance to null... The Lazy<> generic let me implement thread-safe singleton...

I'm not sure about the non-thread-safety of a weakreference implementation of a Lazy<T,TMeta> : thread-safety is assumed by the Lazy object, and I easily imagine a pattern where the Lazy.Value is a weakreference, and if this weakreference.IsAlive == false, then we create this reference again (in a thread lock of course)...

Something like :

public class WeakLazy<T, TMeta> 
: Lazy<WeakReference<T>, TMeta>
{
        [...]
}


Thnaks in advance for your answers !

Bests.

Nov 23, 2011 at 10:23 AM

Thanks for taking time for these answers.

Can you provide an approximation of the MEF 2 release date ?
(I need to know if can plan a WPF release of my product using ExportFactory in early 2012)


I'm scratching my head about what you said : "it relies on parts receiving their dependencies as imports, rather than having them call a central static method or property like SingletonManager<T>.Instance." 

I heavily use this approach, because I embed lot of information in my export's metadata, in order for example to associate an export to a navigation page. So I need to find an export by it's metadata without instantiating it, and then if I need it, I can instantiate it when needed. The "standard" approach of MEF with [Import] creates an instance "de facto", so my "Import Helpers" are the only solution I found to query about metadatas without instantiating types... Maybe I'm going in a wrong direction ?

In all cases, thanks again for your support and for your work on MEF.
I greatly appreciate !

Bests,

Nov 23, 2011 at 3:51 PM

Hi Raphael,

MEF 2 is part of the .NET Framework 4.5 Developer Preview, so the MEF 2 RTM will be aligned with that. I don’t have a date though, sorry.

When you use:

[ImportingConstructor]

public SomePart([ImportMany] IEnumerable<Lazy<IService, IServiceMetadata>> services) { … }

MEF will provide metadata for each part providing IService, but won’t instantiate the underlying classes until the lazy references’ .Value properties are accessed. You can iterate through the list of imports and select which ones you want to use based on metadata this way.

Hope this helps,

Nick

From: rastakouer [email removed]
Sent: Wednesday, November 23, 2011 2:24 AM
To: Nicholas Blumhardt
Subject: Re: MetadataType alternative in SL [MEF:280247]

From: rastakouer

Thanks for taking time for these answers.

Can you provide an approximation of the MEF 2 release date ?
(I need to know if can plan a WPF release of my product using ExportFactory in early 2012)


I'm scratching my head about what you said : "it relies on parts receiving their dependencies as imports, rather than having them call a central static method or property like SingletonManager<T>.Instance."

I heavily use this approach, because I embed lot of information in my export's metadata, in order for example to associate an export to a navigation page. So I need to find an export by it's metadata without instantiating it, and then if I need it, I can instantiate it when needed. The "standard" approach of MEF with [Import] creates an instance "de facto", so my "Import Helpers" are the only solution I found to query about metadatas without instantiating types... Maybe I'm going in a wrong direction ?

In all cases, thanks again for your support and for your work on MEF.
I greatly appreciate !

Bests,