MEF DirectoryCatalog reads the same dll many times - c#

I had a simple implementation of MEF loading some dlls (plugins) from a directory. This was running well under MEF1 but now I want to use the same functionality with MEF2 and it gives me an IEnumerable that contains the right count of dlls that are in the directory but all the assemblies the same.
For example I have two assemblies: fakeplugin1.dll and fakeplugin2.dll in the directory. They exports FakePlugin1 and FakePlugin2 classes. Now when I call container.ComposeParts() I don't have anything in the list decorated with ImportMany and container.Catalog contains two assemblies in the directory but both of them are FakePlugin1.
Here's the code:
[ImportMany(typeof (IDCPlugin))]
IEnumerable<IDCPlugin> workplaceControllers;
var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory);
var agcatalogue = new AggregateCatalog(catalog);
var container = new CompositionContainer(agcatalogue);
container.ComposeParts();
I am trying to use ExportFactory and RegistrationBuilder but I've just realized that even the base functionality donesn't work as expected.
What am I doing wrong? Has something changed in MEF2 I should know? How to load the two different assemblies? :)
Thanks for your help in advance!
Edit:
It always creates two instances of the first type in the folder (ascending in abc). If I put an other one in the folder it creates three of the same, etc.
Edit:
I have uploaded code to pastebin that gives the same result with MEF2: http://pastebin.com/3fWcujPS

A catalog will contain Import and Export definitions for anything detected. Regardless of if you actually need it.
This is a 'feature' of MEF. You will need to either ImportMany and selectively filter the plugins you require.
So how do you handle multiple plugins gracefully? Try this:
[Export]
public class PluginService
{
public const string BEST_PLUGIN = "BestPlugin";
[ImportMany]
public IEnumerable<Plugin> Plugins{ private get; set; }
[Export(BEST_PLUGIN)]
public Plugin BestPlugin{ get { return GetBestPlugin(); } }
Plugin GetBestPlugin()
{
return Plugins.FirstOrDefault(); //or some other logic for selection
}
}
If your plugins are resource intensive, you may want to consider Lazy initialization.
Lazy<T, TMetadata> is a type provided by MEF to hold indirect
references to exports. Here, in addition to the exported object
itself, you also get export metadata, or information that describes
the exported object. Each Lazy<T, TMetadata> contains an IOperation
object, representing an actual operation, and an IOperationData
object, representing its metadata.
http://msdn.microsoft.com/en-us/library/dd460648.aspx#further_imports_and_importmany
MEF has strong rules on component cardinality (number of things) to ensure that there are never any surprises but this does mean you have to be careful with your deployment.

Related

Single .dll with MEF

With reflection i can load a single dll.
Assembly testAssembly = Assembly.LoadFile(#"c:\Test.dll");
But with MEF all the plugins in the directory are red.
Is there a way with MEF of doing the same ?
I can do this :
public IPlugn Load(string name)
{
return Plugins
.Where(l => l.Name.Equals(name))
.FirstOrDefault();
}
but this is a based on the the whole list of plugins.
Kind regards
Dipke
Catalogs are the mechanism MEF uses to find plugins - and they are very flexible.
You are presumably using a DirectoryCatalog?
If so, you can use the overload of the constructor that takes a search pattern:
var catalog = new DirectoryCatalog("C:\\", "Test.dll");
Alternatively, you can use the AssemblyCatalog, which will allow you to just specify the assembly to use.
var catalog = new AssemblyCatalog(Assembly.LoadFile("C:\\Test.dll"));
Finally, if you want any really specific behaviour (load plugins from a web-service call, or crazy stuff like that), then you can just implement your own ComposablePartCatalog.

C# make class auto-register

I have a number of types for which I need to provide custom functions that talk to the external world.
For example, I may have a Widget, and a Sprocket, and when data from the world that I don't control arrives and says "make a Widget," then I need to call a Widget.Create() function.
If the world says "make a Hammer," then I need to return a "Hammer does not exist" error.
However, the mapping between world-representation and type-name is not 1:1, so I can't simply use reflection to find the type name directly -- I need a table. (In fact, "name" may for example be a specific integer value.)
I understand how I can use a pre-defined table (or Dictionary) that maps from world-representation to class-name.
I also understand how to extend/change this table at runtime if the set of possible classes changes. (Because of rules changes, or dynamically loaded parts of the application, or whatever.)
However, all of that requires duplication -- I have to both implement my class, and then, in some other place in the code, remember to add an instance of "this class has this name in the external world."
This is a bit of a code smell, because sometime in the future I will write a new class (or delete an old class) and forget to update the table, and then spend time debugging why it doesn't work right.
I thought I could use a static member in each class which registers itself in a global table:
public static Registration Me = new Registration(typeid(MyClass), "My Name");
Unfortunately, static fields are not initialized until some function in the class is executed/accessed, so this doesn't run at start-up. (Static constructors have similar limitations, plus even more overhead in the runtime!)
The next idea was to decorate the class with a custom attribute that says "register this class in the table."
[Register("My Name")]
class MyClass : .... {
}
Unfortunately, the "Register" attribute doesn't know what class it is attached to -- only the MyClass class knows that it has the Register attribute. (This is infuriating to me, as it would be SO CONVENIENT if attributes knew where they were attached, in many, many cases. But that's an aside!)
So, the least bad implementation I can think of is to iterate all the types of all the assemblies, using reflection, and check whether they have this attribute, and if they do, register them in the table. This is, shall we say, neither elegant nor efficient.
Is there a better way to auto-register classes without having to update some other source file with a central registry?
You could also iterate over all classes matching some criteria and use RuntimeHelpers.RunClassConstructor to ensure the static initializers all get run.
Something like:
var baseType = typeof(MyType);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(baseType));
foreach (var t in types)
{
RuntimeHelpers.RunClassConstructor(t.TypeHandle);
}
This should ensure all your
public static Registration Me = new Registration(typeid(MyClass), "My Name");
functions get called.
I have checked with other resources (that are quite knowledgeable about the internals of the CLR and IL) and it seems that this is a hole in the CLR and the C# language. There simply is no direct way of making things automatically happen on assembly load or appdomain preparation. Walking the types and finding the types that I'm interested in is the least bad way.
In fact, attributes aren't always created until some piece of code asks for them, so I can't use an attribute constructor with a type argument to auto-register, either!
This is of course not great, because if there are eight different pieces of code that each have their own kind of registration they want to do, each of those pieces have to iterate through all of the types and do the inspection on their own. The only way around that would be to give up on modularity, and make all of the different "things" that happen to types be centralized to a single walk-all-types loop at the start of the app. Third party libraries (including the MEF) still wouldn't go inside this loop, though, so there's just an unavoidable chunk of overhead here, OR an unavoidable piece of duplication -- my choice, as developer.

Plugin Framework for Win-Rt

I was looking at Microsoft.Composition but i don't think that is quite what i want. I have a bunch of UserControls, that are each build into it's own assembly, but they each extend the same interface. What would be the best way to scan a directory, see what UserControl assembly is present and allow the program to use the controls that are present.
I would love to stay away from reflection.
The IDriver is a Interface that all drivers must extend, so we get the driver name, add the driver namespace and use the Activator to create the instance
Type driverType = Type.GetType(string.Format("Win8App.RDriver.Drivers.{0}", driver));
if (driverType != null)
{
return (IDriver)Activator.CreateInstance(driverType);
}
log.Error(string.Format("Could not load driver Win8App.RDriver.Drivers.{0}", driver));
return null;

How to use MEF to allow plugins to override existing functionality?

I'm using MEF to allow users to extend my C# library. It's working great so far, but right now I'm trying to use it in a way I haven't seen it used before.
The primary use case for MEF I've seen so far is this:
Application exposes primitive interface (IPerson)
External library uses MEF and primitive interfaces to extend functionality of main library (e.g. IPoliceman : IPerson, adds functionality)
Application then uses ImportMany to search for correct IPerson depending on what it must do
But I need something like this: Let's say I have a tax calculator that takes a bunch of parameters and returns estimated tax depending on those parameters. I want users to be able to create plugins with MEF that modify how those calculations are done. Only one plugin that does this should be able to be loaded at any one time. Otherwise, how do I decide which alternate implementation to use?
So basically, my question boils down to this: Usually MEF allows adding implementations of classes and methods. How do I use it to allow users to replace an implementation?
Normally when you try to override an export which is already present in the application, you will get a cardinality exception for an [Import(typeof(IFoo)] because MEF expects exactly one matching export to be available.
However, you can put your plugins in a separate export provider and give it priority. Here I do that for a "plugins" subfolder inside the application folder:
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string exeLocation = Path.GetDirectoryName(executingAssembly.Location);
string pluginPath = Path.Combine(exeLocation, "plugins");
var pluginCatalog = new DirectoryCatalog(pluginPath);
var pluginExportProvider = new CatalogExportProvider(pluginCatalog);
var appCatalog = new DirectoryCatalog(exeLocation,"*");
var appExportProvider = new CatalogExportProvider(appCatalog);
var container = new CompositionContainer(
pluginExportProvider, appExportProvider);
pluginExportProvider.SourceProvider = container;
appExportProvider.SourceProvider = container;
The order of the export providers as passed to the composition container determines the priority: if an export is provided by both the plugins and the application parts, then the plugins will get priority.
What you're talking about is actually just a different way of looking at the same problem. The answer is simpler than it sounds - for any behavior that you want a client to be able to override, just put that behavior in a plugin.
There's nothing that says you can't write plugins just because you're the author of the application. Put your TaxCalculator class in a plugin, and expose an interface allowing users to write their own tax calculators. At runtime, if you have more than one loaded, favor the one that isn't yours. Out-of-the-box, you will be using your tax calculator plugin, so it will work exactly the way you expect. If the user creates their own tax calculator plugin and drops it in the right directory, you use it instead, effectively allowing them to "override" your original functionality.
I'm not sure how much sense is going to make, but let me try.
I would make a TaxCalculatorManager class. That class could load all of the ITaxCalculator implementations from MEF. From there, you could have something in the Export attribute that would allow ranking of the implementations. Then when you need to calculate the taxes, you would call TaxCalculatorManager.Calculate which would rank the ITaxCalculator implementations and call Calculate on the winner.
Let me know if you need me to clarify any points.

C# create DLL Plugin that implements interface

I'm writing a simple plugin based program. I have an interface IPlugin which has some methods and functions, and a List<Plugin> in my main program. For the sake of simplicity, lets say its defined like this:
public interface IPlugin
{
public void OnKeyPressed(char key);
}
Everytime a key is pressed, I loop through the Plugin list, and call OnKeyPressed(c) on each of them.
I can create a class like so, and add it to the list...
public class PrintPlugin
{
public void OnKeyPressed(char key)
{
Console.WriteLine(c);
}
}
And then whenever you press a key, its printed out. But I want to be able to load plugins from DLL files. This link was helpful, but it doesn't explain how to have the classes in the DLL implement my IPlugin interface... How can I do that? I really don't want to have to copy the IPlugin.cs file every time I want to make a plugin...
If I am understanding you correctly...
Create 3 Projects:
Project 1: Your main program (the one with List in it)
Project 2: the project with your interface
public interface IPlugin
{
public void OnKeyPressed(char key);
}
Project 3: A sample Plugin
public class PrintPlugin : IPlugin
{
public void OnKeyPressed(char key)
{
Console.WriteLine(c);
}
}
Then Add project 2 as a reference to both project 1 and 3.
This way you share the interface with both your main project and any of your plugins.
I have used this on a couple of projects and it has served me well.
You may want to look into the Managed Extensibility Framework as well. It provide a complete API for writing plugin based programs and covers a lot of concerns such as security if you're ever going to plan to make the plugin API available to third parties.
If you need to load user defined plugins, you should search for new DLLs when the application starts (or any other action). This can be done by using:
1) AppDomain.CurrentDomain.GetAssemblies() method returns the list of loaded assemblies in the current AppDomain
2) Search all DLLs in a folder where plugins should be positioned and check if a certain assembly is in the list. If not, use the Assembly.Load method to load this assembly, find the IPlugin class in it and finally add it to the List object.

Categories

Resources