Single .dll with MEF - c#

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.

Related

Resolving dynamically registered services by key in .NET Core

I'm migrating a tool to a .net 5 console app. I would like to change my DI system, currently a modified version of TinyIoC, to use if possible the built-in DI. Currently, my tool will load and auto-register any dll it finds in its config file. First-in wins, so a user-provided implementation of one of my interfaces will take precedence over my default one, loaded last.
Additionally, I need to be able to register several variants of a given interface, and have my DI system choose between them based on configuration. Currently, this works with a RegistrationName attribute that I've added to Tiny. When tiny auto-registers everything in a dll, it includes this name in it's registration.
So, for example, I have a IProvider interface, with methods including IDbConnection GetConnection(string connectionString);. I have several default implementations for SQL Server, Postgres, etc. and users can provide other implementations in dlls that I don't know about when compiling my tool.
Here is how I declare my SQL Server provider...
[RegistrationName("System.Data.SqlClient")]
class SqlClient : IProvider
{
Here is how I specify provider in my qfconfig.json...
{
"defaultConnection": "Data Source=localhost;Initial Catalog=Northwind;Integrated Security=True",
"provider": "System.Data.SqlClient"
}
Here is how I ask Tiny for a concrete instance...
// RegistrationName is passed to the Resolve method.
// Tiny returns the implementation whose RegistrationName matches.
_provider = _tiny.Resolve<IProvider>(config.provider);
So I want to keep this possibility, but find a less personal way of doing it.
I fear I've strayed out into the forest on this subject. The docs and tutos that I find all cover much simpler scenarios, where there's one registered implementation of an interface, and everything is explicitly registered in code. Can someone point me back on the road please?
If I understand your use case correctly, you have possible multiple IProvider implementations, but always only need one at runtime, which is based on the the configured value that maps to the RegistrationName attribute.
There's nothing built-in to the MS.DI framework that simplifies such use case, but as you only need to register one at runtime, you can achieve this by iterating the assemblies and finding that specific implementation and register that:
var providers =
from assembly in assemblies
from type in assembly.GetExportedTypes()
where typeof(IProvider).IsAssignableFrom(type)
where !type.IsAbstract
let attr = type.GetCustomAttribute<RegistrationNameAttribute>()
where attr?.Name == config.provider
select type;
services.AddTransient(typeof(IProvider), providers.Single());
This way registration is based on the name, while resolving can be done in a keyless fashion:
serviceProvider.GetRequiredService<IProvider>();
In the case I misunderstood your question, and you need multiple IProvider implementations at runtime, and need to resolve them by their key... well, that's certainly possible, but you will have to write more code. And here's the takeaway from everything that follows, ActivatorUtilities is your friend:
// Find all 'name -> provider' mappings
var providerDefinitions =
from assembly in assemblies
from type in assembly.GetExportedTypes()
where typeof(IProvider).IsAssignableFrom(type)
where !type.IsAbstract
let name = type.GetCustomAttribute<RegistrationNameAttribute>()?.Name
where name != null
select new { name, type };
// Helper method that builds IProvider factory delegates
Func<IServiceProvider, IProvider> BuildProviderFactory(Type type) =>
provider => (IProvider)ActivatorUtilities.CreateInstance(provider, type);
// Create a dictionary that maps the name to a provider factory
Dictionary<string, Func<IServiceProvider, IProvider>> providerFactories =
providerDefinitions.ToDictionary(
keySelector: i => i.name,
elementSelector: i => BuildProviderFactory(i.type));
// Possible use
Func<IServiceProvider, IProvider> factory = providerFactories[config.provider];
IProvider provider = factory(serviceProvider);
ActivatorUtilities.CreateInstance is MS.DI's extension point that allows the creation of unregistered classes, while injecting them with dependencies that are part of the provided IServiceProvider instance.
ActivatorUtilities.CreateInstance comes with a lot of unfortunate subtle downsides, such as the inability to check for cyclic dependencies, which could lead to nasty stack overflow exceptions instead. But this is the best we can achieve with MS.DI. Other DI Containers are more mature and feature rich in this respect.

MEF DirectoryCatalog reads the same dll many times

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.

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;

Creating plugin instances with context using DI

I'm refactoring our application to include Dependency Injection (via constructor injection) and have run into a tricky corner-case:
We currently have ImageViewer objects that when instantiated search the assembly for ImageViewerPlugin (an abstract base class) instances, instantiating them using reflection. This is done in the constructor of the ImageViewer using a method (called in a loop for all concrete plugin types) that is similar to:
private ImageViewerPlugin LoadPlugin(Type concretePluginType)
{
var pluginConstructor = concretePluginType.GetConstructor(
BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public,
null,
new[] { typeof(ImageViewer) },
null);
return (ImageViewerPlugin) pluginConstructor.Invoke(
new object[] { constructorParameter });
}
The ImageViewerPlugin class looks roughly like this:
internal ImageViewerPlugin
{
protected ImageViewer _viewer;
protected ImageViewerPlugin(ImageViewer viewer)
{
_viewer = viewer;
}
}
A concrete implementation looks roughly like this:
internal AnImageViewerPlugin
{
public AnImageViewerPlugin(ImageViewer viewer) : base(viewer)
{
}
}
Each ImageViewer instance has its own collection of ImageViewerPlugin instances.
Now that the application being refactored to use a DI container and constructor injection I'm discovering that these plugins have dependencies (which were previously hidden through the use of global static classes) that need to be resolved by the DI container, but I'm not sure how to do that without using a Service Locator (an anti-pattern).
The most sensible solution seems to be to create these plugin instances using DI. This would allow me to add extra constructor parameters to have the dependencies they rely on injected via constructor injection. But if I do that, how can I pass a specific viewer parameter value while having the rest of the parameter values injected?
I thought an ImageViewerPluginFactory would help to achieve this but can't see how to implement such a factory as each plugin is likely to have a different constructor signature.
How can I solve this scenario? Or am I approaching this totally the wrong way?
So you have an ImageViewer that depends on a collection of ImageViewerPlugin instances, which each depend on n ImageViewer that depends on a collection of ImageViewerPlugin instances, which each depend on n ImageViewer that depends on a collection of ImageViewerPlugin instances, which each depend on an ... well you get the picture :-)
This is a circular reference. Leaving the whole DI container thing aside, how would you create this hierarchy when doing this manually? With constructor injection you can't. It can be seen from the following example:
var plugin = new ImageViewerPlugin( [what goes here?] );
var viewer = new ImageViewer(plugin);
You will have to break this dependency cycle somehow and the general advice is to fall back on property injection in this case:
var plugin = new ImageViewerPlugin();
var viewer = new ImageViewer(plugin);
// Property injection
plugin.Viewer = viewer;
But even more, you should take a good look at the design of the application, since a circular reference often is an indication of a problem in the design. For instance, take a good look what behavior the plugin needs from the viewer and what behavior the viewer needs from the plugins. You might be able to extract this to another class, as follows:
var imageServices = new ImageServices();
var plugin = new ImageViewerPlugin(imageServices);
var viewer = new ImageViewer(imageServices, plugin);
This solves the problem completely, but it depends on your situation whether this is feasible.
With the last solution, registration with Simple Injector would be rather straight forward. When breaking the dependency using property injection, you can make use of the RegisterInitializer(Action) method. It allows you to break the dependency cycle. For instance:
container.RegisterInitializer<ImageViewer>(viewer =>
{
foreach (var plugin in viewer.Plugins)
{
plugin.Viewer = viewer;
}
});

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.

Categories

Resources