217 lines
8.0 KiB
Plaintext
217 lines
8.0 KiB
Plaintext
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using System.IO;
|
|
using System.ComponentModel.Composition.Hosting;
|
|
using System.ComponentModel.Composition.ReflectionModel;
|
|
using System.Linq;
|
|
using DataPro.Core.Config;
|
|
|
|
namespace DataPro.Core.PluginLib
|
|
{
|
|
/// <summary>
|
|
/// PluginManager class to manage MEF plugins
|
|
/// NOTE: This class has to be thread safe
|
|
/// </summary>
|
|
public class PluginManager
|
|
{
|
|
// reference to singleton plugin manager
|
|
private static PluginManager _pluginManager;
|
|
|
|
/// <summary>
|
|
/// MEF catalog
|
|
/// </summary>
|
|
private AggregateCatalog PluginCatalog { get; set; }
|
|
|
|
/// <summary>
|
|
/// MEF container
|
|
/// </summary>
|
|
private CompositionContainer PluginContainer { get; set; }
|
|
|
|
/// <summary>
|
|
/// Thread lock
|
|
/// </summary>
|
|
private static readonly object ThreadLock = new object();
|
|
|
|
/// <summary>
|
|
/// Constructor that intializes catalog and container
|
|
/// </summary>
|
|
private PluginManager()
|
|
{
|
|
// Create MEF catalog
|
|
PluginCatalog = new AggregateCatalog();
|
|
//PluginCatalog = new AggregateCatalog(new AssemblyCatalog(typeof(MediaTypeNames.Application).Assembly));
|
|
|
|
// Get plugin folder from App.Config;
|
|
var pcsh = (PluginConfigSectionHandler)DataProConfig.GetSection("DataPro.Core.PluginLib.Config");
|
|
if (pcsh == null) throw new Exception("Unable to retrieve plugin config data from DataPro.config (DataPro.Core.PluginLib.Config)");
|
|
|
|
|
|
foreach (FilterHashElement element in pcsh.HashKeys)
|
|
{
|
|
//Why "absolete path"?
|
|
//if (!Path.IsPathRooted(element.Value)) throw new IOException(string.Format("Error in DataPro.Config. {0} must be absolete path", element.Value));
|
|
|
|
var info = new DirectoryInfo(element.Value);
|
|
if (!info.Exists) throw new IOException(string.Format("Plugin directory does not exist: {0}", element.Value));
|
|
|
|
PluginCatalog.Catalogs.Add(new DirectoryCatalog(element.Value));
|
|
}
|
|
|
|
// Create MEF container
|
|
PluginContainer = new CompositionContainer(PluginCatalog);
|
|
|
|
foreach (var catalog in PluginCatalog.Catalogs)
|
|
{
|
|
var directoryCatalog = catalog as DirectoryCatalog;
|
|
if (directoryCatalog == null) continue;
|
|
|
|
var pluginDir = directoryCatalog.FullPath;
|
|
|
|
var files = (new DirectoryInfo(pluginDir)).GetFiles("*.dll");
|
|
|
|
foreach (var assembly in files)
|
|
{
|
|
var assemblyName = string.Format("{0}{1}", pluginDir, assembly.Name);
|
|
|
|
// verift assembly exists and matches requested paramaters
|
|
if (!File.Exists(assemblyName)) continue;
|
|
|
|
var info = AssemblyName.GetAssemblyName(assemblyName);
|
|
|
|
// NOTE: sometimes args.Name only has short assembly name, sometimes full name with public key and version
|
|
//if (info == null || (info.FullName != args.Name && (info.Name != args.Name)))
|
|
//{
|
|
// continue;
|
|
//}
|
|
|
|
// Load assembly
|
|
var asm = Assembly.LoadFrom(assemblyName);
|
|
if (asm == null) continue;
|
|
}
|
|
}
|
|
|
|
}
|
|
public List<Assembly> GetPluginList<T>() where T : class
|
|
{
|
|
var manager = GetPluginManager();
|
|
foreach (var catalog in manager.PluginCatalog.Catalogs)
|
|
{
|
|
var directoryCatalog = catalog as DirectoryCatalog;
|
|
if (directoryCatalog == null) continue;
|
|
return directoryCatalog.Parts.Select(part => ReflectionModelServices.GetPartType(part).Value.Assembly).Distinct().ToList();
|
|
|
|
}
|
|
//return export != null ? export.Value : null;
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Returns MEF plugin of type t
|
|
/// Throws error if no type exported by plugin or more than one plugin has exported type
|
|
/// </summary>
|
|
/// <typeparam name="T">type to get</typeparam>
|
|
/// <returns>reference to type t from MEF plugin</returns>
|
|
public static T GetPlugin<T>() where T : class
|
|
{
|
|
var export = GetPluginManager().PluginContainer.GetExport<T>();
|
|
return export != null ? export.Value : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns MEF plugin of type T from a collection of plugins that export the same type
|
|
/// </summary>
|
|
/// <typeparam name="T">exported type implemented by potentially multiple plugins</typeparam>
|
|
/// <param name="configPluginSetting">string that tells us which specific plugin we want</param>
|
|
/// <returns>type T</returns>
|
|
public static T GetPlugin<T>(string configPluginSetting) where T : class
|
|
{
|
|
var result = new Lazy<T>();
|
|
var manager = GetPluginManager();
|
|
var plugins = manager.PluginContainer.GetExports<T>();
|
|
|
|
//loop through plugins returned and get the specific one we're looking for
|
|
foreach (var item in plugins)
|
|
{
|
|
if (item.Value.ToString() == configPluginSetting)
|
|
{
|
|
result = item;
|
|
break;
|
|
}
|
|
}
|
|
return result.Value;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns list of MEF plugins that export type t
|
|
/// </summary>
|
|
/// <typeparam name="T">type to get</typeparam>
|
|
/// <returns>list of references to type t from MEF plugins</returns>
|
|
public static IEnumerable<Lazy<T>> GetPlugins<T>() where T : class
|
|
{
|
|
var manager = GetPluginManager();
|
|
return manager.PluginContainer.GetExports<T>();
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns static singleton reference to plugin manager class
|
|
/// </summary>
|
|
/// <returns>plugin class</returns>
|
|
public static PluginManager GetPluginManager()
|
|
{
|
|
lock (ThreadLock)
|
|
{
|
|
return _pluginManager ?? (_pluginManager = new PluginManager());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This event triggered if system can't find plugin dependancies
|
|
/// CurrentDomain_AssemblyResolve can search through list of directories instead of just one
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="args"></param>
|
|
/// <returns></returns>
|
|
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
|
{
|
|
foreach (var catalog in PluginCatalog.Catalogs)
|
|
{
|
|
var directoryCatalog = catalog as DirectoryCatalog;
|
|
if (directoryCatalog == null) continue;
|
|
|
|
var pluginDir = directoryCatalog.FullPath;
|
|
|
|
// get name of assembly
|
|
var baseName = args.Name.Split(new[] { ',' })[0];
|
|
var assemblyName = string.Format("{0}\\{1}.dll", pluginDir, baseName);
|
|
|
|
// verift assembly exists and matches requested paramaters
|
|
if (!File.Exists(assemblyName)) continue;
|
|
|
|
var info = AssemblyName.GetAssemblyName(assemblyName);
|
|
|
|
// NOTE: sometimes args.Name only has short assembly name, sometimes full name with public key and version
|
|
if (info == null || (info.FullName != args.Name && (info.Name != args.Name)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Load assembly
|
|
var asm = Assembly.LoadFrom(assemblyName);
|
|
if (asm == null) continue;
|
|
|
|
return asm;
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|