I've had a few questions about MEF recently, but here's the big one -- is it really all-or-nothing, as it appears to be?
My basic application structure is simply an app, several shared libraries that are intended to be singletons, and several different plugins (which may implement different interfaces). The app loads the plugins, and both the app and all plugins need to access the shared libraries.
My first go at MEF was fairly successful, although I made some stupid mistakes along the way because I was trying so many different things, I just got confused at times. But in the end, last night I got my smallish test app running with MEF, some shared libraries, and one plugin.
Now I'm moving onto the target app, which I already described. And it's the multiple plugins part that has be a bit worried.
My existing application already supports multiple plugins with different interfaces by using Reflection. I need to be able to uniquely identify each plugin so that the user can select one and get the expected behavior exposed by that plugin. The problem is that I don't know how to do this yet... but that's the topic of a different question.
Ideally, I'd be able to take my existing plugin loader and use it as-is, while relying on MEF to do the shared library resolution. The problem is, I can't seem to get MEF to load them (i.e. I get a CompositionException when calling ComposeParts()) unless I also use MEF to load the plugin. And if I do this, well... then I need to know how to keep track of them as they get loaded so the user can select one from a list of plugins.
What have your experiences been with trying to mix and match these approaches?
MEF is designed to let you easily load plugin assemblies. If you have control over the plugins (by which I mean that you can add MEF export attributes) then there is no need to keep your own plugin loader which uses reflection. MEF does all that for you.
That being said, "mixing and matching" MEF with other technologies is certainly possible. It sounds like your problem is that if you use your own plugin loader, you don't add those plug-ins to the MEF container. As a result, you get a CompositionException for parts which try to import the selected plug-in.
To add a plugin that you loaded with your own code to the MEF container, you can use the ComposeExportedValue like this:
container.ComposeExportedValue<IPlugin>(selectedPlugin);
edit: I see what you mean now by "all or nothing". Your problem is that in order to be able to import parts with MEF, you also need to construct the object with MEF. This problem then cascades to the object which normally created that object, etc. all the way to the application root.
To avoid this "all or nothing" effect, you can compromise by exposing the MEF container as a global variable (i.e. static field). That way, classes can access the MEF container and pull exports from it, e.g. by calling Program.Container.GetExportedValue<MyDependency>() in the constructor.
edit2: If you have an object that was not constructed by MEF, then there are two ways to add it to the container.
The first is to call container.ComposeExportedValue<IMyContractType>(myObject);.
The second is to return the object in a property getter, and then mark the property itself with an [Export(typeof(SomeType))] attribute.
Related
I am currently using a library (SuperWebSocket) which is a websocket server library that use a bootstrap which know which instances to load from a configuration file. I have implemented a bootstrap class for this (however the instances arent loaded using IoC). Also the commands from this server are loaded from assemblies reflection. I wanted to use this server in conjonction with my DAL and service layer which use IoC. My main problem is that i can't find a way to put this Console Application (Server) and cooperation with the lib in an IoC scenario without having to end up using the ServiceLocator.
Normally the kernel (Ninject) should be located at the composition root (Look like to be the best practice from many around..) which is rather not possible to do in this case or at least i didn't found how so that why i am here. Also the commands are loaded from assemblies reflection. I could implement a CommandLoader however this is still a problem cause they all inherit from the same interface (Multibinding maybe?). I could make custom interface for each of them but i still can't find a way to load them automatically. Even if i found a way to load them, i still have to be able to get service from attributes which is not easy to do.
Any suggestions ?
If I understand your question correctly then the library is the entry point for all work done. In this situation it depends on the framework what to do. Here are some things you can do the first things are the preferred ones:
Inspect the library and find some way to hook into the framework to intercept the creation of your objects.
Call kernel.Inject(this) after an object is created by the library. Have a look at the Ninject.Web extension. There we added some base classes e.g. NinjectWebPage for WebPage. This new base class calls kernel.Inject after creation. New web pages can now be derived from that base class and use property injection to get dependencies.
Use the ServiceLocator pattern in the objects created by the libray. But just at this level. Anything deeper should use dependency injection.
I have a Silverlight 4 library L which has a dependency that is to be provided at run-time via a plugin P.
I am using a DeploymentCatalog along the lines of the example provided by MEF documentation and all is well: the XAP of the plugin P is correctly downloaded asynchronously and the import is satisfied.
However, I cannot control the details on the Silverlight application A that will be using library L and I cannot exclude that A itself might want to use MEF: therefore it's possible that at some point A might issue a CompositionHost.SatisfyImports(...) CompositionHost.Initialize(catalog) call for its own purposes which I understand can only be invoked once.
Am I missing something here or partitioning the application across multiple XAPs can only be achieved if one has complete control of the Silverlight application and libraries?
Stefano
CompositionHost.SatisfyImports can be called many times. CompositionHost.Initialize can only be called once. As a library, it is not a good idea to call that method because the application may do so. Since you need to create and use a DeploymentCatalog, it's probably better if you don't use CompositionHost at all in your library, since you want to avoid calling the Initialize method, which would be the way to hook the CompositionHost to the DeploymentCatalog.
You can create your own CompositionContainer hooked up to the DeploymentCatalog and call GetExports or SatisfyImports on the container you created. CompositionHost is pretty much just a wrapper around a static CompositionContainer.
It's not usually a good idea to tie yourself to a single dependency injection container in a library, instead you'd usually want to abstract that away using something like the CommonServiceLocator, which leaves the choice of IoC container a preference of whoever is consuming your library.
I only started with MEF in Silverlight a month ago, so I'm definitely not an authority.
The first thing I noticed is that CompositionHost.SatisfyImports has been replaced with CompositionInitializer.SatisfyImports .
Second I could not find any reference to "SatisfyImports can only be invoked once"
My scenario is the following:
I have a BL xap which I use/link to from my application
The BL has some Imports that will be satisfied by calling SatisfyImports from the Application
The BL also has some imports that
cannot/will not be resolved until a
certain custom (third party)
module/xap will be loaded (loaded
when demand that is). When the custom
module becomes available (is loaded)
I solve the missing imports with an
extra call to
CompositionInitializer.SatisfyImports:
E.g:
If DomainSpecificModuleLogic Is Nothing Then
'this is required to trigger recomposition and resolve imports to the ThirdPartyModule
System.ComponentModel.Composition.CompositionInitializer.SatisfyImports(Me)
End If
So I have multiple calls to SatisfyImports (at different moments in time) and no problems due to this -> you do not required control over the whole application, just make sure that when someone accesses an object from your library that uses MEF, you have a call to SatisfyImports
Note: my BL is a singleton, so for sure I am calling SatisfyImports on the same object multiple times.
I've read MEF documentation on Codeplex and I'm trying to figure out how to accomplish my task:
I would like to build an application framework that has standard components that can be used to do some common work (like displaying a list of records from a database). Plugins should be reused many times with different configuration each time. (eg. I have 5 windows in an application where I display record lists, each with different type of entity, different columns, each one should have it's own extension points like for displaying record details that should be satisfied with a different copy of another common plugin).
Is MEF suitable for such a scenario? How should I define contracts? Should I use metadata? Can I define relationships using configuration files?
Yes, you can use MEF. MEF supports NonShared instantiation of objects using the PartCreationPolicy attribute:
[PartCreationPolicy(CreationPolicy.NonShared)]
More information on this here.
Personally I'd do the wiring and configuration after the importing of the component on the target. However I am not sure how generic you want your application to be, if you are making a 'framework' to do certain solutions in I can imagine you want the configuration to be separate. You can go all-over-board and make an ISuperDuperGridConfiguration and import these on the constructor [ImportingConstructor] of your grid plugin. From within your target (where the grids get imported) set the location of the grid to the grid plugin (like main grid, side grid) and use the data stored in ISuperDuperGridConfiguration to further config the grid plugin itself.
However, you can easily go 'too far' with MEF, depending on your goals. We have a completely MEF componentized UI for an application with customized needs for every single customer. Sometimes I have the urge to put single buttons from the ribbon in a MEF extension.
As you can see, depending on your needs, you can and sometimes will go too far.
I don't think you'd need metadata especially in your case, but maybe someone else can share a different opinion on this ;-).
I hope this answers your question, if not please comment so I can highlight more aspects. All in all using MEF has been very positive for us, and we are using it far beyond a 'hello world' so to say. So at least you have that!
I have decided to use MEF for a plugin pattern I have and found MEF easy to pick up and not intrusive at all. I looked at samples and found them very easy to work with.
However, as soon as started implementing, I started struggling with the composition. Let's say I have a Class which has [ImportMany] on one of its properties. All examples I have seen, they create the Container in the class which has imports (let's call it composable) and basically the class composes itself. That might be OK for an example but surely putting knowledge of how the plugin gets populated is too much for the composable to know.
I can happily create a singleton container and access it in my composable but again the composable has to explicitly call Compose() on itself and I am not happy with that either as it is like a dependency injection scenario where the class pro-actively calls the Resolve() on the container. So I do not want to use it for just Service Location.
To make the matters worse I am also using Windsor Castle for DI and I am not sure how MEF and Windsor must work together.
I have really looked around and have not been able to find any guidance and sample on how to do MEF right. Now it might be that I have not looked around or I do not know MEF well enough (which is true) but will value your views from the experience of actually using it in the real world.
Do not do that. I used MEF for my last project and I wish to not do that.
There's a good idea behind it (composition) and I was do that manually for years. I was happy for the first official version in .NET 4.0 but there a re still a lot of design problems.
Unfortunately it's part of Microsoft policy to leave testing and bug finding to end users and feedback the hard-earned bugs and suggestions.
MEF is good if you use the way the example says. As soon as you need a little change you will find there's not enough documentation and nobody will answer you. Here are some of my never resolved issues with MEF and you can find my questions in codeplex.com which never had been answered by the developer team:
1) How to pass parameters to part's constructors (they may say use ExportFactory which is shipped in codeplex version but I wasted a long time on this, and I can say there's not an acceptable solution for that)
2) How to set configurations for parts ? (I ended-up passing configurations to parts through a method which is a bad idea, but the best available)
3) MEF is very slow because it use reflection under the hood. For my case loading 1,000 parts takes 60 seconds.
4) Debugging is awesome. You get unclear messages. You will end-up downloading the full source from codeplex and search your exceptions inside the code.
After all I think if you have other choices, let MEF gets mature and use the next version.
I just shared my own experience.
The recommended pattern is for you to create the container once in your hosting code, and only access it from there to get the "root" part. You would call container.GetExport<Root>() if it's OK for MEF to create the part for you, otherwise you would call container.SatisfyImports(root).
The root part should import the things it needs, and the parts supplying those exports should import what they need, and so on. MEF will create the whole graph and none of the parts need to call into the container directly. The samples often have very few different parts, so it isn't always obvious that the container creation and composition should only occur once, even in more complex applications.
There are situations where you may have object that need their imports satisfied, but can't be created by MEF. An example of this is WPF/Silverlight UI objects that are created by the Xaml parser. In this case you might resort to a service which allows these objects to request that their imports be satisfied.
I don't have much advice for how to use MEF and another DI container in the same application. If there isn't much interaction between the parts of the system composed with MEF and Windsor it might work without much trouble. If you need components from one container to be injected with components from the other container, it won't be as simple. One way would be to have a service that a component would have to call to resolve its dependencies from the other container. The other possibility would be to have the containers themselves linked. You can do this in theory with MEF by writing an ExportProvider that accesses the Windsor container. In practice it would require a very deep level of knowledge about MEF, and it might not be possible to get it to work exactly how you'd like.
My application allows users to write plugins (implementing IPlugin) that they can instantiate at runtime. On startup a directory of plugin .dlls is parsed, registering all the available plugins information. At runtime a GUI is provided that lets users create instances of any of the plugins. This works fine.
But now I see MEF and hope I can do the same, but in a more elegant way codewise.
What I got working so far with MEF: on startup I am doing an import of all plugins in a directory (that export IPlugin) and read out the information like name, category, author, etc... These are encoded as exported metadata attributes to the plugin classes. The import is done lazyly so all the plugins are not instantiated on startup, which is important.
The problem is that now I don't see a way to elegantly instantiate a selected plugin at runtime given the additional complication that the plugins constructor is an importing constructor which is importing a reference to an IPluginHost (which it needs immediately to do some initialization).
Together with a plugininfo I save the respective Export in a dictionary during startup, so when the GUI asks to instantiate a plugin given a specific plugininfo I have access to the Export (where Export.Value is my actual IPlugin). But from there how can I create an instance of the plugin and have it composed with the IPluginHost?
I gather I should write my own ExportProvider that serves the IPluginHost whenever someone asks for it, but I don't have access to the assembly or the type of the specific plugin that would let me add it to a Catalog, add the catalog and ExportProvider to a container and call .ComposeParts on that container.
I hope I made my problem clear, if not, let me try a short version of the question:
isn't it a standard usecase for MEF to have a program that lazy-loads plugins on startup to parse the available plugins infos and then at runtime create specific instances given specific plugininfos? would be great to get a codeoutline of the steps involved.
If I understand correctly, you are looking for a way to dynamically create multiple plugin instances, potentially of the same plugin.
You need to declare an import of the type ExportFactory<IPlugin,IPluginMetadata> and then select the correct factory based on the metadata. ExportFactory.CreateExport will take care of any imports required by the IPlugin instances, like the IPluginHost you mentioned.
Note that ExportFactory was only in the silverlight edition of MEF in earlier releases. To get it in the desktop edition, you currently need the latest version from codeplex (MEF 2 - Preview 1). There is also a known problem with importing ExportFactory via the constructor, so use a property.
Have you created a CompositionContainer yet? You can use it to request particular plugin types and get them instantiated. The catalogs will get you part of the way there. You can aggregate multiple catalogs (using the AggregateCatalog) then pass the result to the constructor of the CompositionContainer. When you request your specific IPlugin Type (just keep track of the Type of the export) and you can ask the CompositionContainer to instantiate the plugin for you and it will do the constructor injection for you automatically.