I am trying to use MEF to simplify the style architecture of an add-in or plug-in. I already did this with the map structure in a very similar way, but I see the same specific problem as I have with the map structure, in which I have to either add the probe directory configuration in app.config or configure the AssemblyResolve event handler to handle plugins, which dynamically invoke code.
Here is a sample MEF code (just a small lab application) that shows how I call a method from the specified interface:
namespace MefLab
{
class Program
{
static void Main(string[] args)
{
MefLoader loader = new MefLoader();
Type type = typeof(IConsoleWriter);
Lazy<object, object> export = loader.Container.GetExports(type, null, null).SingleOrDefault();
var writer = (IConsoleWriter)export.Value;
writer.Write();
Console.ReadKey();
}
}
public class MefLoader
{
public MefLoader()
{
var registrationBuilder = new RegistrationBuilder();
registrationBuilder.ForTypesDerivedFrom<IConsoleWriter>().SetCreationPolicy(CreationPolicy.NonShared).Export<IConsoleWriter>();
var aggregateCatalog = new AggregateCatalog();
var mefLabInfraCatalog = new AssemblyCatalog(typeof(IConsoleWriter).Assembly);
aggregateCatalog.Catalogs.Add(mefLabInfraCatalog);
foreach (string pluginDir in PluginDirctories)
{
DirectoryCatalog dirCatalog = new DirectoryCatalog(pluginDir, registrationBuilder);
aggregateCatalog.Catalogs.Add(dirCatalog);
}
var coreCatalog = new AssemblyCatalog(typeof(MefLoader).Assembly);
aggregateCatalog.Catalogs.Add(coreCatalog);
Container = new CompositionContainer(aggregateCatalog);
}
public CompositionContainer Container { get; set; }
private List<String> _pluginDirectories;
private List<String> PluginDirctories
{
get
{
if (_pluginDirectories == null)
{
_pluginDirectories = new List<string>();
DirectoryInfo di = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Plugins"));
foreach (DirectoryInfo dInfo in di.GetDirectories())
{
_pluginDirectories.Add(dInfo.FullName);
}
}
return _pluginDirectories;
}
}
private List<Assembly> _assemblies;
private List<Assembly> Assemblies
{
get
{
if (_assemblies == null)
{
_assemblies = new List<Assembly>();
foreach (string pluginDir in PluginDirctories)
{
DirectoryInfo di = new DirectoryInfo(pluginDir);
foreach (FileInfo fi in di.GetFiles("*.dll"))
{
Assembly assembly = Assembly.LoadFile(fi.FullName);
_assemblies.Add(assembly);
}
}
DirectoryInfo root = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)));
foreach (FileInfo fi in root.GetFiles("*.dll"))
{
Assembly assembly = Assembly.LoadFile(fi.FullName);
_assemblies.Add(assembly);
}
foreach (FileInfo fi in root.GetFiles("*.exe"))
{
Assembly assembly = Assembly.LoadFile(fi.FullName);
_assemblies.Add(assembly);
}
}
return _assemblies;
}
}
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly resolved = Assemblies.Where(x => x.FullName == args.Name).FirstOrDefault();
return resolved;
}
}
}
This is what I say when I say a plugin that dynamically invokes code.
namespace MefLabDependency.Managers
{
public class EntityConsoleManager : IConsoleWriter
{
public void Write()
{
var domProvider = new CSharpCodeProvider(new Dictionary<String, String>{{ "CompilerVersion", "v4.0" }});
List<string> assemblies = (from Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()
where !assembly.IsDynamic && !string.IsNullOrWhiteSpace(assembly.Location) select assembly.Location).ToList();
var parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
parameters.CompilerOptions = "/optimize";
parameters.TreatWarningsAsErrors = false;
parameters.ReferencedAssemblies.AddRange(assemblies.ToArray());
CompilerResults results = domProvider.CompileAssemblyFromSource(parameters,
@"using System;
using MefLabDependency.Entities;
namespace MefLabDependency.DynamicCode
{
public class EntityBuilder {
public static string GetValue() {
Entity entity = new Entity();
var value = string.Format(@""{2}EntityId: {0}{2}Name: {1}\"", entity.Id, entity.Name, System.Environment.NewLine);
return value;
}
}
}");
Assembly dynamicAssembly = results.CompiledAssembly;
Type dynamicType = dynamicAssembly.GetType("MefLabDependency.DynamicCode.EntityBuilder");
object objValue = dynamicType.InvokeMember("GetValue", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, null);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Dynamic code execution success!{0}", objValue);
}
}
}
... ?! (, ). , , , , , .
, :
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="Plugins\MefDependencyPlugin"/>
</assemblyBinding>
</runtime>
AssemblyResolve , , , ( , , , , ).
, , , . , , MEF StructureMap, ?