This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1 @@
12

View File

@@ -0,0 +1 @@
12

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DataPro.Core")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DataPro.Core")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("bdf5ad7a-51db-4ad0-8186-d1ead7405848")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,216 @@
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;
}
}
}

View File

@@ -0,0 +1,8 @@
namespace DataPro.Core
{
public static class DataProConstants
{
//public const string CustomConfigPath = @"C:\Program Files\DataPro\bin\DataPro.config";
public const string CustomConfigPath = @"DataPRO.exe.config";
}
}

View File

@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataPro.Core.ServiceManager
{
/// <summary>
/// Service manager allows a component to publish an implementation of a singleton interface (service) that
/// other components can retrieve reference to without knowing who published it
/// </summary>
public static class ServiceManager
{
/// <summary>
/// Stores all published interfaces
/// </summary>
private static readonly Dictionary<Type, object> Services = new Dictionary<Type, object>();
/// <summary>
/// Publishes a service
/// </summary>
/// <typeparam name="T">interface type of service</typeparam>
/// <param name="item">implementation of service</param>
public static void Publish<T>(T item) where T : class
{
if (Services.ContainsKey(typeof(T)))
{
throw new ArgumentException(string.Format("{0}: has already been published", typeof(T).Name));
}
Services.Add(typeof(T), item);
SendServicePublishedEvent(typeof(T), true);
}
/// <summary>
/// Publishes a list of services
/// </summary>
/// <param name="item">class that will implement all the listed interfaces</param>
/// <param name="interfaceList">list of interfaces</param>
/// <param name="skipPublishedInterfaces">true to avoid errors on already published interfaces</param>
public static void Publish(object item, IEnumerable<Type> interfaceList, bool skipPublishedInterfaces)
{
foreach (var t in interfaceList)
{
if (Exists(t))
{
if (!skipPublishedInterfaces)
{
// service already published and caller indicated we should error out
throw new ArgumentException(string.Format("{0}: has already been published", t.Name));
}
}
else
{
// service doesn't exist so publish it
Services.Add(t, item);
SendServicePublishedEvent(t, true);
}
}
}
/// <summary>
/// Returns true if specifed interface has been published, false if not
/// </summary>
/// <typeparam name="T">type of interface to check</typeparam>
/// <returns>true if interface has been published; false if not published</returns>
public static bool Exists<T>() where T : class
{
return Services.ContainsKey(typeof(T));
}
/// <summary>
/// Returns true if specifed interface has been published, false if not
/// </summary>
/// <param name="t">type of interface to check</param>
/// <returns>true if interface has been published; false if not published</returns>
public static bool Exists(Type t)
{
return Services.ContainsKey(t);
}
/// <summary>
/// Returns published service
/// </summary>
/// <typeparam name="T">interface type of service</typeparam>
/// <returns>published service or exception if not currently published</returns>
public static T Get<T>() where T : class
{
if (!Services.ContainsKey(typeof(T)))
{
throw new ArgumentException(string.Format("{0}: has not been published", typeof(T).Name));
}
return Services[typeof(T)] as T;
}
/// <summary>
/// Clears specified service
/// </summary>
/// <typeparam name="T">interface type of service to clear</typeparam>
public static void Clear<T>() where T : class
{
if (Services.ContainsKey(typeof(T)))
{
SendServicePublishedEvent(typeof(T), false);
Services.Remove(typeof(T));
}
}
/// <summary>
/// Clears list of published interfaces
/// </summary>
/// <param name="interfaceList">list of interfaces to unpublish</param>
public static void Clear(IEnumerable<Type> interfaceList)
{
foreach (var t in interfaceList)
{
if (!Services.ContainsKey(t)) continue;
SendServicePublishedEvent(t, false);
Services.Remove(t);
}
}
/// <summary>
/// Sends a IServicePublishedEvent through the Event Manger to let subscribers know when
/// a service is published or unpublished
/// </summary>
/// <param name="type">type of interface</param>
/// <param name="published">true if being published, false if being unpublished</param>
private static void SendServicePublishedEvent(Type type, bool published)
{
EventManager.EventManager.Publish<IServicePublishedEvent>(new ServicePublishedEvent
{
IsPublished = published,
ServiceType = type
});
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataPro.Core.ServiceManager
{
/// <summary>
/// Event fired when a service interface is published\unpublished
/// </summary>
public interface IServicePublishedEvent
{
/// <summary>
/// Returns type of service being published\unpublished
/// </summary>
Type ServiceType { get; }
/// <summary>
/// Returns true if Service is being published, false if being unpublished
/// </summary>
bool IsPublished { get; }
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Configuration;
using System.Linq;
namespace DataPro.Core.Config
{
public static class DataProConfig
{
private static readonly Configuration Config;
// static constructor
static DataProConfig()
{
var dataProConfig = new ExeConfigurationFileMap
{
ExeConfigFilename = DataProConstants.CustomConfigPath
};
Config = ConfigurationManager.OpenMappedExeConfiguration(dataProConfig, ConfigurationUserLevel.None, true);
}
/// <summary>
/// Static variable to hold alternate configuration file
/// </summary>
public static Configuration AltConfig
{
get { return Config; }
}
/// <summary>
/// Static method to retrieve a setting from config file
/// </summary>
/// <param name="key">string</param>
/// <returns>string</returns>
public static string GetAppSetting(string key)
{
var appSetting = Config.AppSettings.Settings.Cast<KeyValueConfigurationElement>().FirstOrDefault(setting => setting.Key == key);
return appSetting == null ? String.Empty : appSetting.Value;
}
/// <summary>
/// Static method to get a section from config file. Used by plugin code to get plugin library section.
/// </summary>
/// <param name="sectionName">string</param>
/// <returns>object</returns>
public static object GetSection(string sectionName)
{
return Config.GetSection(sectionName);
}
}
}

View File

@@ -0,0 +1,84 @@
using System;
namespace DataPro.Core.Settings
{
/// <summary>
/// Event arguments describing change to settings collection
/// </summary>
/// <typeparam name="TKey">key type used in collection</typeparam>
/// <typeparam name="TItem">value type used in collection</typeparam>
public class SettingsChangedEventArgs<TKey, TItem> : EventArgs
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="changeType">type of scenario change</param>
public SettingsChangedEventArgs(ChangeSettingType changeType)
{
ChangeType = changeType;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="changeType">change type</param>
/// <param name="key">key type used in collection</param>
public SettingsChangedEventArgs(ChangeSettingType changeType, TKey key)
{
ChangeType = changeType;
Key = key;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="changeType">change type</param>
/// <param name="key">key type used in collection</param>
/// <param name="item">value type used in collection</param>
public SettingsChangedEventArgs(ChangeSettingType changeType, TKey key, TItem item)
{
ChangeType = changeType;
Key = key;
Item = item;
}
/// <summary>
/// Returns type of scenario change
/// </summary>
public ChangeSettingType ChangeType
{
get;
private set;
}
/// <summary>
/// key associated with changed setting
/// </summary>
public TKey Key
{
get;
private set;
}
/// <summary>
/// Value associated with changed settting
/// </summary>
public TItem Item
{
get;
private set;
}
}
/// <summary>
/// Type of settings changed
/// </summary>
public enum ChangeSettingType
{
Add = 0,
Remove = 1,
Modified = 3,
ClearAll = 4
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataPro.Core.ServiceManager
{
/// <summary>
/// Event fired when a service interface is published\unpublished
/// </summary>
public class ServicePublishedEvent : IServicePublishedEvent
{
/// <summary>
/// Returns type of service being published\unpublished
/// </summary>
public Type ServiceType
{
get;
internal set;
}
/// <summary>
/// Returns true if Service is being published, false if being unpublished
/// </summary>
public bool IsPublished
{
get;
internal set;
}
}
}

View File

@@ -0,0 +1,67 @@
using System.Configuration;
namespace DataPro.Core.PluginLib
{
/// <summary>
/// Support class that parses data from DataPro.Core.PluginLib.Config configuration section
/// </summary>
public class PluginConfigSectionHandler : ConfigurationSection
{
[ConfigurationProperty("PluginFolders")]
public FilterHashKeyCollection HashKeys
{
get { return ((FilterHashKeyCollection)(base["PluginFolders"])); }
}
}
[ConfigurationCollection(typeof(FilterHashElement))]
public class FilterHashKeyCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new FilterHashElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((FilterHashElement)(element)).Key;
}
public FilterHashElement this[int idx]
{
get
{
return (FilterHashElement)BaseGet(idx);
}
}
}
public class FilterHashElement : ConfigurationElement
{
[ConfigurationProperty("key", DefaultValue = "", IsKey = true, IsRequired = true)]
public string Key
{
get
{
return ((string)(base["key"]));
}
set
{
base["key"] = value;
}
}
[ConfigurationProperty("value", DefaultValue = "", IsKey = false, IsRequired = false)]
public string Value
{
get
{
return ((string)(base["value"]));
}
set
{
base["value"] = value;
}
}
}
}

View File

@@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace DataPro.Core.EventManager
{
/// <summary>
/// Delegate used by event listeners
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item"></param>
public delegate void SubscriberCallbackDelegate<in T>(T item) where T : class;
public delegate void DiagnosticCallbackDelegate(EventDiagnosticType eventType, Type t, object eventData, string listener);
/// <summary>
/// Allows components to publish events without knowing who is listening
/// </summary>
public static class EventManager
{
/// <summary>
/// Tracks listeners
/// </summary>
private static readonly Dictionary<Type, List<object>> SubscriberList = new Dictionary<Type, List<object>>();
/// <summary>
/// Tracks diagnostic listeners
/// </summary>
private static readonly List<DiagnosticCallbackDelegate> DiagnosticList = new List<DiagnosticCallbackDelegate>();
/// <summary>
/// Publish an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="eventData">event listener</param>
public static void Publish<T>(T eventData) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T))) return;
var listeners = SubscriberList[typeof(T)];
foreach (var listener in listeners)
{
var metaData = listener as EventMetaData<T>;
if (metaData == null) continue;
var triggerCallback = true;
if (metaData.EventFilter != null)
{
triggerCallback = metaData.EventFilter(eventData);
}
if (triggerCallback)
{
metaData.Callback(eventData);
}
SendDiagnosticEvent(EventDiagnosticType.PublishEvent, typeof(T), eventData, metaData.EventFilter != null ? metaData.EventFilter.Method : null);
}
}
/// <summary>
/// Subscribe to an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
public static void Subscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
{
Subscribe(listener, null);
}
/// <summary>
/// Subscribe to an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
/// <param name="eventFilter">predicate to filter events sent to event listener</param>
public static void Subscribe<T>(SubscriberCallbackDelegate<T> listener, Predicate<T> eventFilter) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T)))
{
SubscriberList.Add(typeof(T), new List<object>());
}
var listeners = SubscriberList[typeof(T)];
var metaData = new EventMetaData<T> { Callback = listener, EventFilter = eventFilter };
listeners.Add(metaData);
SendDiagnosticEvent(EventDiagnosticType.AddListener, typeof(T), null, listener.Method);
}
/// <summary>
/// Allows a subscriber to unsubscribe
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
public static void UnSubscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T))) return;
var listeners = SubscriberList[typeof(T)];
listeners.RemoveAll(p =>
{
var eventMetaData = p as EventMetaData<T>;
return eventMetaData != null && eventMetaData.Callback == listener;
});
SendDiagnosticEvent(EventDiagnosticType.RemoveListener, typeof(T), null, listener.Method);
}
/// <summary>
/// Clears all listeners
/// </summary>
public static void Clear()
{
SubscriberList.Clear();
SendDiagnosticEvent(EventDiagnosticType.RemoveListener, null, null, null);
}
/// <summary>
/// Add diagnostic listener
/// </summary>
/// <param name="listener">event listener</param>
public static void SubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
{
DiagnosticList.Add(listener);
SendDiagnosticEvent(EventDiagnosticType.AddListenerDiagnostic, null, null, listener.Method);
}
/// <summary>
/// Clear diagnostic event
/// </summary>
/// <param name="listener">listener to unsubscribe</param>
public static void UnSubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
{
DiagnosticList.RemoveAll(p => p == listener);
SendDiagnosticEvent(EventDiagnosticType.RemoveListenerDiagnostic, null, null, listener.Method);
}
/// <summary>
/// Clear all diagnostic events
/// </summary>
public static void ClearDiagnosticEvents()
{
DiagnosticList.Clear();
SendDiagnosticEvent(EventDiagnosticType.RemoveListenerDiagnostic, null, null, null);
}
/// <summary>
/// Sends a diagnostic event
/// </summary>
/// <param name="diagnosticEventType"></param>
/// <param name="eventType"></param>
/// <param name="eventData"></param>
/// <param name="listenerMethod"></param>
private static void SendDiagnosticEvent(EventDiagnosticType diagnosticEventType, Type eventType, object eventData, MemberInfo listenerMethod)
{
foreach (var diagnosticEvent in DiagnosticList)
{
string listener = null;
if (listenerMethod != null && listenerMethod.DeclaringType != null)
{
listener = string.Format("{0}.{1} , {2}", listenerMethod.DeclaringType.FullName, listenerMethod.Name, listenerMethod.DeclaringType.Assembly.FullName);
}
diagnosticEvent(diagnosticEventType, eventType, eventData, listener);
}
}
}
public enum EventDiagnosticType
{
AddListener = 0,
AddListenerDiagnostic = 1,
PublishEvent = 2,
RemoveListenerDiagnostic = 3,
RemoveListener = 4
}
class EventMetaData<T> where T : class
{
public Predicate<T> EventFilter { get; set; }
public SubscriberCallbackDelegate<T> Callback { get; set; }
}
}

View File

@@ -0,0 +1,241 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace DataPro.Core.Settings
{
/// <summary>
/// Implements a dictionary with events when an item is changed
/// </summary>
/// <typeparam name="TKey">key type</typeparam>
/// <typeparam name="TItem">value type</typeparam>
/// <history>
/// <list type="number">
/// <item>{01/22/2014}. {RCD}. {Initial Version}</item>
/// </list>
/// </history>
public class SettingsCollection<TKey, TItem> : IDictionary<TKey, TItem>
{
/// <summary>
/// Event fired when an item changes in dictionary
/// </summary>
public event EventHandler<SettingsChangedEventArgs<TKey, TItem>> CollectionItemPropertyChanged;
/// <summary>
/// List of stored items
/// </summary>
private readonly Dictionary<TKey, TItem> _items = new Dictionary<TKey, TItem>();
#region IDictionary
/// <summary>
/// Add item
/// </summary>
/// <param name="key">key</param>
/// <param name="value">value</param>
public void Add(TKey key, TItem value)
{
_items.Add(key, value);
FireItemChangedEvent(ChangeSettingType.Add, key, value);
}
/// <summary>
/// Returns true if item contains key
/// </summary>
/// <param name="key">key</param>
/// <returns>true if key exists</returns>
public bool ContainsKey(TKey key)
{
return _items.ContainsKey(key);
}
/// <summary>
/// Returns all keys in collection
/// </summary>
public ICollection<TKey> Keys
{
get { return _items.Keys; }
}
/// <summary>
/// Removes key
/// </summary>
/// <param name="key">key</param>
/// <returns>true if key removed</returns>
public bool Remove(TKey key)
{
var res = _items.Remove(key);
if (res) FireItemChangedEvent(ChangeSettingType.Remove, key);
return res;
}
/// <summary>
/// Trys to get specified value
/// </summary>
/// <param name="key">key</param>
/// <param name="value">value if key exists</param>
/// <returns>true if key exists; false if it doesn't exist</returns>
public bool TryGetValue(TKey key, out TItem value)
{
return _items.TryGetValue(key, out value);
}
/// <summary>
/// List of values in collection
/// </summary>
public ICollection<TItem> Values
{
get { return _items.Values; }
}
/// <summary>
/// Gets/sets item in collection (overloads [] operator)
/// </summary>
/// <param name="key">key</param>
/// <returns>item in collection</returns>
public TItem this[TKey key]
{
get
{
return _items[key];
}
set
{
_items[key] = value;
FireItemChangedEvent(ChangeSettingType.Add, key, value);
}
}
/// <summary>
/// Adds new item
/// </summary>
/// <param name="item">new item to add</param>
public void Add(KeyValuePair<TKey, TItem> item)
{
_items.Add(item.Key, item.Value);
FireItemChangedEvent(ChangeSettingType.Add, item.Key, item.Value);
}
/// <summary>
/// Clears entire collection
/// </summary>
public void Clear()
{
_items.Clear();
FireItemChangedEvent(ChangeSettingType.ClearAll);
}
/// <summary>
/// Returns true if item is in collection
/// </summary>
/// <param name="item">item to check</param>
/// <returns>true if item exists</returns>
public bool Contains(KeyValuePair<TKey, TItem> item)
{
return _items.ContainsKey(item.Key) && _items.ContainsValue(item.Value);
}
/// <summary>
/// Copys items to array
/// </summary>
/// <param name="array"></param>
/// <param name="arrayIndex"></param>
public void CopyTo(KeyValuePair<TKey, TItem>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
/// <summary>
/// Returns count of items
/// </summary>
public int Count
{
get { return _items.Count; }
}
/// <summary>
/// Returns true if readonly collection
/// </summary>
public bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Removes specified item
/// </summary>
/// <param name="item">item to remove</param>
/// <returns>true if item removed</returns>
public bool Remove(KeyValuePair<TKey, TItem> item)
{
var res = _items.Remove(item.Key);
if (res) FireItemChangedEvent(ChangeSettingType.Remove, item.Key);
return res;
}
/// <summary>
/// Return enumerator for collection
/// </summary>
/// <returns>enumerator</returns>
public IEnumerator<KeyValuePair<TKey, TItem>> GetEnumerator()
{
return _items.GetEnumerator();
}
/// <summary>
/// Return enumerator for collection
/// </summary>
/// <returns>enumerator</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return _items.GetEnumerator();
}
#endregion
#region Private methods
/// <summary>
/// Fires collection change event
/// </summary>
/// <param name="changeType">type of change</param>
private void FireItemChangedEvent(ChangeSettingType changeType)
{
if (CollectionItemPropertyChanged != null)
{
CollectionItemPropertyChanged(this, new SettingsChangedEventArgs<TKey, TItem>(changeType));
}
}
/// <summary>
/// Fires collection change event
/// </summary>
/// <param name="changeType">type of change</param>
/// <param name="key">key</param>
private void FireItemChangedEvent(ChangeSettingType changeType, TKey key)
{
if (CollectionItemPropertyChanged != null)
{
CollectionItemPropertyChanged(this, new SettingsChangedEventArgs<TKey, TItem>(changeType, key));
}
}
/// <summary>
/// Fires collection change event
/// </summary>
/// <param name="changeType">type of change</param>
/// <param name="key">key</param>
/// <param name="item">item</param>
private void FireItemChangedEvent(ChangeSettingType changeType, TKey key, TItem item)
{
if (CollectionItemPropertyChanged != null)
{
CollectionItemPropertyChanged(this, new SettingsChangedEventArgs<TKey, TItem>(changeType, key, item));
}
}
#endregion
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>

View File

@@ -0,0 +1,14 @@
using System.Xml.Serialization;
namespace DataPro.Core.PluginLib
{
/// <summary>
/// Support class that stores data de-serialized from DatPro.Core.PluginLib.Config in App.Config configuration section
/// </summary>
[XmlRoot(ElementName = "DatPro.Core.PluginLib.Config")]
public class PluginConfigData
{
[XmlArrayItem("Folder")]
public string[] PluginFolders;
}
}

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{FAB1F470-1574-4301-B56E-D3364AA93679}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DataPro.Core</RootNamespace>
<AssemblyName>DataPro.Core</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Config\DataProConfig.cs" />
<Compile Include="DataProConstants.cs" />
<Compile Include="EventManager\EventManager.cs" />
<Compile Include="PluginLib\PluginConfig.cs" />
<Compile Include="PluginLib\PluginConfigData.cs" />
<Compile Include="PluginLib\PluginConfigSectionHandler.cs" />
<Compile Include="PluginLib\PluginManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceManager\IServicePublishedEvent.cs" />
<Compile Include="ServiceManager\ServiceManager.cs" />
<Compile Include="ServiceManager\ServicePublishedEvent.cs" />
<Compile Include="Settings\SettingsChangedEventArgs.cs" />
<Compile Include="Settings\SettingsCollection.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\DTS.Common.csproj">
<Project>{114edc77-f3b5-4576-a91b-40818d503b55}</Project>
<Name>DTS.Common</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="RegionAdapters\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataPro.Core.Config;
namespace DataPro.Core.PluginLib
{
/// <summary>
/// Static class used to store plugin configuration info
/// </summary>
public static class PluginConfig
{
/// <summary>
/// name of setting to look in config for equipment database
/// </summary>
public const string DataProPlugins = "dataProPlugins";
/// <summary>
/// concatenate plugin name from app setting with class exporter name for dataPro plugins
/// </summary>
/// <param name="setting"></param>
/// <returns></returns>
public static string GetDataProPluginsSetting(string setting)
{
return DataProConfig.GetAppSetting(DataProPlugins) + "." + setting;
}
}
}

Binary file not shown.

View File

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>

View File

@@ -0,0 +1,52 @@
using System;
using System.Configuration;
using System.Linq;
namespace DataPro.Core.Config
{
public static class DataProConfig
{
private static readonly Configuration Config;
// static constructor
static DataProConfig()
{
var dataProConfig = new ExeConfigurationFileMap
{
ExeConfigFilename = DataProConstants.CustomConfigPath
};
Config = ConfigurationManager.OpenMappedExeConfiguration(dataProConfig, ConfigurationUserLevel.None, true);
}
/// <summary>
/// Static variable to hold alternate configuration file
/// </summary>
public static Configuration AltConfig
{
get { return Config; }
}
/// <summary>
/// Static method to retrieve a setting from config file
/// </summary>
/// <param name="key">string</param>
/// <returns>string</returns>
public static string GetAppSetting(string key)
{
var appSetting = Config.AppSettings.Settings.Cast<KeyValueConfigurationElement>().FirstOrDefault(setting => setting.Key == key);
return appSetting == null ? String.Empty : appSetting.Value;
}
/// <summary>
/// Static method to get a section from config file. Used by plugin code to get plugin library section.
/// </summary>
/// <param name="sectionName">string</param>
/// <returns>object</returns>
public static object GetSection(string sectionName)
{
return Config.GetSection(sectionName);
}
}
}

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{FAB1F470-1574-4301-B56E-D3364AA93679}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DataPro.Core</RootNamespace>
<AssemblyName>DataPro.Core</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Config\DataProConfig.cs" />
<Compile Include="DataProConstants.cs" />
<Compile Include="EventManager\EventManager.cs" />
<Compile Include="PluginLib\PluginConfig.cs" />
<Compile Include="PluginLib\PluginConfigData.cs" />
<Compile Include="PluginLib\PluginConfigSectionHandler.cs" />
<Compile Include="PluginLib\PluginManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceManager\IServicePublishedEvent.cs" />
<Compile Include="ServiceManager\ServiceManager.cs" />
<Compile Include="ServiceManager\ServicePublishedEvent.cs" />
<Compile Include="Settings\SettingsChangedEventArgs.cs" />
<Compile Include="Settings\SettingsCollection.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\DTS.Common.csproj">
<Project>{114edc77-f3b5-4576-a91b-40818d503b55}</Project>
<Name>DTS.Common</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="RegionAdapters\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,8 @@
namespace DataPro.Core
{
public static class DataProConstants
{
//public const string CustomConfigPath = @"C:\Program Files\DataPro\bin\DataPro.config";
public const string CustomConfigPath = @"DataPRO.exe.config";
}
}

View File

@@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace DataPro.Core.EventManager
{
/// <summary>
/// Delegate used by event listeners
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item"></param>
public delegate void SubscriberCallbackDelegate<in T>(T item) where T : class;
public delegate void DiagnosticCallbackDelegate(EventDiagnosticType eventType, Type t, object eventData, string listener);
/// <summary>
/// Allows components to publish events without knowing who is listening
/// </summary>
public static class EventManager
{
/// <summary>
/// Tracks listeners
/// </summary>
private static readonly Dictionary<Type, List<object>> SubscriberList = new Dictionary<Type, List<object>>();
/// <summary>
/// Tracks diagnostic listeners
/// </summary>
private static readonly List<DiagnosticCallbackDelegate> DiagnosticList = new List<DiagnosticCallbackDelegate>();
/// <summary>
/// Publish an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="eventData">event listener</param>
public static void Publish<T>(T eventData) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T))) return;
var listeners = SubscriberList[typeof(T)];
foreach (var listener in listeners)
{
var metaData = listener as EventMetaData<T>;
if (metaData == null) continue;
var triggerCallback = true;
if (metaData.EventFilter != null)
{
triggerCallback = metaData.EventFilter(eventData);
}
if (triggerCallback)
{
metaData.Callback(eventData);
}
SendDiagnosticEvent(EventDiagnosticType.PublishEvent, typeof(T), eventData, metaData.EventFilter != null ? metaData.EventFilter.Method : null);
}
}
/// <summary>
/// Subscribe to an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
public static void Subscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
{
Subscribe(listener, null);
}
/// <summary>
/// Subscribe to an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
/// <param name="eventFilter">predicate to filter events sent to event listener</param>
public static void Subscribe<T>(SubscriberCallbackDelegate<T> listener, Predicate<T> eventFilter) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T)))
{
SubscriberList.Add(typeof(T), new List<object>());
}
var listeners = SubscriberList[typeof(T)];
var metaData = new EventMetaData<T> { Callback = listener, EventFilter = eventFilter };
listeners.Add(metaData);
SendDiagnosticEvent(EventDiagnosticType.AddListener, typeof(T), null, listener.Method);
}
/// <summary>
/// Allows a subscriber to unsubscribe
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
public static void UnSubscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T))) return;
var listeners = SubscriberList[typeof(T)];
listeners.RemoveAll(p =>
{
var eventMetaData = p as EventMetaData<T>;
return eventMetaData != null && eventMetaData.Callback == listener;
});
SendDiagnosticEvent(EventDiagnosticType.RemoveListener, typeof(T), null, listener.Method);
}
/// <summary>
/// Clears all listeners
/// </summary>
public static void Clear()
{
SubscriberList.Clear();
SendDiagnosticEvent(EventDiagnosticType.RemoveListener, null, null, null);
}
/// <summary>
/// Add diagnostic listener
/// </summary>
/// <param name="listener">event listener</param>
public static void SubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
{
DiagnosticList.Add(listener);
SendDiagnosticEvent(EventDiagnosticType.AddListenerDiagnostic, null, null, listener.Method);
}
/// <summary>
/// Clear diagnostic event
/// </summary>
/// <param name="listener">listener to unsubscribe</param>
public static void UnSubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
{
DiagnosticList.RemoveAll(p => p == listener);
SendDiagnosticEvent(EventDiagnosticType.RemoveListenerDiagnostic, null, null, listener.Method);
}
/// <summary>
/// Clear all diagnostic events
/// </summary>
public static void ClearDiagnosticEvents()
{
DiagnosticList.Clear();
SendDiagnosticEvent(EventDiagnosticType.RemoveListenerDiagnostic, null, null, null);
}
/// <summary>
/// Sends a diagnostic event
/// </summary>
/// <param name="diagnosticEventType"></param>
/// <param name="eventType"></param>
/// <param name="eventData"></param>
/// <param name="listenerMethod"></param>
private static void SendDiagnosticEvent(EventDiagnosticType diagnosticEventType, Type eventType, object eventData, MemberInfo listenerMethod)
{
foreach (var diagnosticEvent in DiagnosticList)
{
string listener = null;
if (listenerMethod != null && listenerMethod.DeclaringType != null)
{
listener = string.Format("{0}.{1} , {2}", listenerMethod.DeclaringType.FullName, listenerMethod.Name, listenerMethod.DeclaringType.Assembly.FullName);
}
diagnosticEvent(diagnosticEventType, eventType, eventData, listener);
}
}
}
public enum EventDiagnosticType
{
AddListener = 0,
AddListenerDiagnostic = 1,
PublishEvent = 2,
RemoveListenerDiagnostic = 3,
RemoveListener = 4
}
class EventMetaData<T> where T : class
{
public Predicate<T> EventFilter { get; set; }
public SubscriberCallbackDelegate<T> Callback { get; set; }
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataPro.Core.Config;
namespace DataPro.Core.PluginLib
{
/// <summary>
/// Static class used to store plugin configuration info
/// </summary>
public static class PluginConfig
{
/// <summary>
/// name of setting to look in config for equipment database
/// </summary>
public const string DataProPlugins = "dataProPlugins";
/// <summary>
/// concatenate plugin name from app setting with class exporter name for dataPro plugins
/// </summary>
/// <param name="setting"></param>
/// <returns></returns>
public static string GetDataProPluginsSetting(string setting)
{
return DataProConfig.GetAppSetting(DataProPlugins) + "." + setting;
}
}
}

View File

@@ -0,0 +1,14 @@
using System.Xml.Serialization;
namespace DataPro.Core.PluginLib
{
/// <summary>
/// Support class that stores data de-serialized from DatPro.Core.PluginLib.Config in App.Config configuration section
/// </summary>
[XmlRoot(ElementName = "DatPro.Core.PluginLib.Config")]
public class PluginConfigData
{
[XmlArrayItem("Folder")]
public string[] PluginFolders;
}
}

View File

@@ -0,0 +1,67 @@
using System.Configuration;
namespace DataPro.Core.PluginLib
{
/// <summary>
/// Support class that parses data from DataPro.Core.PluginLib.Config configuration section
/// </summary>
public class PluginConfigSectionHandler : ConfigurationSection
{
[ConfigurationProperty("PluginFolders")]
public FilterHashKeyCollection HashKeys
{
get { return ((FilterHashKeyCollection)(base["PluginFolders"])); }
}
}
[ConfigurationCollection(typeof(FilterHashElement))]
public class FilterHashKeyCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new FilterHashElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((FilterHashElement)(element)).Key;
}
public FilterHashElement this[int idx]
{
get
{
return (FilterHashElement)BaseGet(idx);
}
}
}
public class FilterHashElement : ConfigurationElement
{
[ConfigurationProperty("key", DefaultValue = "", IsKey = true, IsRequired = true)]
public string Key
{
get
{
return ((string)(base["key"]));
}
set
{
base["key"] = value;
}
}
[ConfigurationProperty("value", DefaultValue = "", IsKey = false, IsRequired = false)]
public string Value
{
get
{
return ((string)(base["value"]));
}
set
{
base["value"] = value;
}
}
}
}

View File

@@ -0,0 +1,216 @@
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;
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DataPro.Core")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DataPro.Core")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("bdf5ad7a-51db-4ad0-8186-d1ead7405848")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataPro.Core.ServiceManager
{
/// <summary>
/// Event fired when a service interface is published\unpublished
/// </summary>
public interface IServicePublishedEvent
{
/// <summary>
/// Returns type of service being published\unpublished
/// </summary>
Type ServiceType { get; }
/// <summary>
/// Returns true if Service is being published, false if being unpublished
/// </summary>
bool IsPublished { get; }
}
}

View File

@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataPro.Core.ServiceManager
{
/// <summary>
/// Service manager allows a component to publish an implementation of a singleton interface (service) that
/// other components can retrieve reference to without knowing who published it
/// </summary>
public static class ServiceManager
{
/// <summary>
/// Stores all published interfaces
/// </summary>
private static readonly Dictionary<Type, object> Services = new Dictionary<Type, object>();
/// <summary>
/// Publishes a service
/// </summary>
/// <typeparam name="T">interface type of service</typeparam>
/// <param name="item">implementation of service</param>
public static void Publish<T>(T item) where T : class
{
if (Services.ContainsKey(typeof(T)))
{
throw new ArgumentException(string.Format("{0}: has already been published", typeof(T).Name));
}
Services.Add(typeof(T), item);
SendServicePublishedEvent(typeof(T), true);
}
/// <summary>
/// Publishes a list of services
/// </summary>
/// <param name="item">class that will implement all the listed interfaces</param>
/// <param name="interfaceList">list of interfaces</param>
/// <param name="skipPublishedInterfaces">true to avoid errors on already published interfaces</param>
public static void Publish(object item, IEnumerable<Type> interfaceList, bool skipPublishedInterfaces)
{
foreach (var t in interfaceList)
{
if (Exists(t))
{
if (!skipPublishedInterfaces)
{
// service already published and caller indicated we should error out
throw new ArgumentException(string.Format("{0}: has already been published", t.Name));
}
}
else
{
// service doesn't exist so publish it
Services.Add(t, item);
SendServicePublishedEvent(t, true);
}
}
}
/// <summary>
/// Returns true if specifed interface has been published, false if not
/// </summary>
/// <typeparam name="T">type of interface to check</typeparam>
/// <returns>true if interface has been published; false if not published</returns>
public static bool Exists<T>() where T : class
{
return Services.ContainsKey(typeof(T));
}
/// <summary>
/// Returns true if specifed interface has been published, false if not
/// </summary>
/// <param name="t">type of interface to check</param>
/// <returns>true if interface has been published; false if not published</returns>
public static bool Exists(Type t)
{
return Services.ContainsKey(t);
}
/// <summary>
/// Returns published service
/// </summary>
/// <typeparam name="T">interface type of service</typeparam>
/// <returns>published service or exception if not currently published</returns>
public static T Get<T>() where T : class
{
if (!Services.ContainsKey(typeof(T)))
{
throw new ArgumentException(string.Format("{0}: has not been published", typeof(T).Name));
}
return Services[typeof(T)] as T;
}
/// <summary>
/// Clears specified service
/// </summary>
/// <typeparam name="T">interface type of service to clear</typeparam>
public static void Clear<T>() where T : class
{
if (Services.ContainsKey(typeof(T)))
{
SendServicePublishedEvent(typeof(T), false);
Services.Remove(typeof(T));
}
}
/// <summary>
/// Clears list of published interfaces
/// </summary>
/// <param name="interfaceList">list of interfaces to unpublish</param>
public static void Clear(IEnumerable<Type> interfaceList)
{
foreach (var t in interfaceList)
{
if (!Services.ContainsKey(t)) continue;
SendServicePublishedEvent(t, false);
Services.Remove(t);
}
}
/// <summary>
/// Sends a IServicePublishedEvent through the Event Manger to let subscribers know when
/// a service is published or unpublished
/// </summary>
/// <param name="type">type of interface</param>
/// <param name="published">true if being published, false if being unpublished</param>
private static void SendServicePublishedEvent(Type type, bool published)
{
EventManager.EventManager.Publish<IServicePublishedEvent>(new ServicePublishedEvent
{
IsPublished = published,
ServiceType = type
});
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataPro.Core.ServiceManager
{
/// <summary>
/// Event fired when a service interface is published\unpublished
/// </summary>
public class ServicePublishedEvent : IServicePublishedEvent
{
/// <summary>
/// Returns type of service being published\unpublished
/// </summary>
public Type ServiceType
{
get;
internal set;
}
/// <summary>
/// Returns true if Service is being published, false if being unpublished
/// </summary>
public bool IsPublished
{
get;
internal set;
}
}
}

View File

@@ -0,0 +1,84 @@
using System;
namespace DataPro.Core.Settings
{
/// <summary>
/// Event arguments describing change to settings collection
/// </summary>
/// <typeparam name="TKey">key type used in collection</typeparam>
/// <typeparam name="TItem">value type used in collection</typeparam>
public class SettingsChangedEventArgs<TKey, TItem> : EventArgs
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="changeType">type of scenario change</param>
public SettingsChangedEventArgs(ChangeSettingType changeType)
{
ChangeType = changeType;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="changeType">change type</param>
/// <param name="key">key type used in collection</param>
public SettingsChangedEventArgs(ChangeSettingType changeType, TKey key)
{
ChangeType = changeType;
Key = key;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="changeType">change type</param>
/// <param name="key">key type used in collection</param>
/// <param name="item">value type used in collection</param>
public SettingsChangedEventArgs(ChangeSettingType changeType, TKey key, TItem item)
{
ChangeType = changeType;
Key = key;
Item = item;
}
/// <summary>
/// Returns type of scenario change
/// </summary>
public ChangeSettingType ChangeType
{
get;
private set;
}
/// <summary>
/// key associated with changed setting
/// </summary>
public TKey Key
{
get;
private set;
}
/// <summary>
/// Value associated with changed settting
/// </summary>
public TItem Item
{
get;
private set;
}
}
/// <summary>
/// Type of settings changed
/// </summary>
public enum ChangeSettingType
{
Add = 0,
Remove = 1,
Modified = 3,
ClearAll = 4
}
}

View File

@@ -0,0 +1,241 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace DataPro.Core.Settings
{
/// <summary>
/// Implements a dictionary with events when an item is changed
/// </summary>
/// <typeparam name="TKey">key type</typeparam>
/// <typeparam name="TItem">value type</typeparam>
/// <history>
/// <list type="number">
/// <item>{01/22/2014}. {RCD}. {Initial Version}</item>
/// </list>
/// </history>
public class SettingsCollection<TKey, TItem> : IDictionary<TKey, TItem>
{
/// <summary>
/// Event fired when an item changes in dictionary
/// </summary>
public event EventHandler<SettingsChangedEventArgs<TKey, TItem>> CollectionItemPropertyChanged;
/// <summary>
/// List of stored items
/// </summary>
private readonly Dictionary<TKey, TItem> _items = new Dictionary<TKey, TItem>();
#region IDictionary
/// <summary>
/// Add item
/// </summary>
/// <param name="key">key</param>
/// <param name="value">value</param>
public void Add(TKey key, TItem value)
{
_items.Add(key, value);
FireItemChangedEvent(ChangeSettingType.Add, key, value);
}
/// <summary>
/// Returns true if item contains key
/// </summary>
/// <param name="key">key</param>
/// <returns>true if key exists</returns>
public bool ContainsKey(TKey key)
{
return _items.ContainsKey(key);
}
/// <summary>
/// Returns all keys in collection
/// </summary>
public ICollection<TKey> Keys
{
get { return _items.Keys; }
}
/// <summary>
/// Removes key
/// </summary>
/// <param name="key">key</param>
/// <returns>true if key removed</returns>
public bool Remove(TKey key)
{
var res = _items.Remove(key);
if (res) FireItemChangedEvent(ChangeSettingType.Remove, key);
return res;
}
/// <summary>
/// Trys to get specified value
/// </summary>
/// <param name="key">key</param>
/// <param name="value">value if key exists</param>
/// <returns>true if key exists; false if it doesn't exist</returns>
public bool TryGetValue(TKey key, out TItem value)
{
return _items.TryGetValue(key, out value);
}
/// <summary>
/// List of values in collection
/// </summary>
public ICollection<TItem> Values
{
get { return _items.Values; }
}
/// <summary>
/// Gets/sets item in collection (overloads [] operator)
/// </summary>
/// <param name="key">key</param>
/// <returns>item in collection</returns>
public TItem this[TKey key]
{
get
{
return _items[key];
}
set
{
_items[key] = value;
FireItemChangedEvent(ChangeSettingType.Add, key, value);
}
}
/// <summary>
/// Adds new item
/// </summary>
/// <param name="item">new item to add</param>
public void Add(KeyValuePair<TKey, TItem> item)
{
_items.Add(item.Key, item.Value);
FireItemChangedEvent(ChangeSettingType.Add, item.Key, item.Value);
}
/// <summary>
/// Clears entire collection
/// </summary>
public void Clear()
{
_items.Clear();
FireItemChangedEvent(ChangeSettingType.ClearAll);
}
/// <summary>
/// Returns true if item is in collection
/// </summary>
/// <param name="item">item to check</param>
/// <returns>true if item exists</returns>
public bool Contains(KeyValuePair<TKey, TItem> item)
{
return _items.ContainsKey(item.Key) && _items.ContainsValue(item.Value);
}
/// <summary>
/// Copys items to array
/// </summary>
/// <param name="array"></param>
/// <param name="arrayIndex"></param>
public void CopyTo(KeyValuePair<TKey, TItem>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
/// <summary>
/// Returns count of items
/// </summary>
public int Count
{
get { return _items.Count; }
}
/// <summary>
/// Returns true if readonly collection
/// </summary>
public bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Removes specified item
/// </summary>
/// <param name="item">item to remove</param>
/// <returns>true if item removed</returns>
public bool Remove(KeyValuePair<TKey, TItem> item)
{
var res = _items.Remove(item.Key);
if (res) FireItemChangedEvent(ChangeSettingType.Remove, item.Key);
return res;
}
/// <summary>
/// Return enumerator for collection
/// </summary>
/// <returns>enumerator</returns>
public IEnumerator<KeyValuePair<TKey, TItem>> GetEnumerator()
{
return _items.GetEnumerator();
}
/// <summary>
/// Return enumerator for collection
/// </summary>
/// <returns>enumerator</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return _items.GetEnumerator();
}
#endregion
#region Private methods
/// <summary>
/// Fires collection change event
/// </summary>
/// <param name="changeType">type of change</param>
private void FireItemChangedEvent(ChangeSettingType changeType)
{
if (CollectionItemPropertyChanged != null)
{
CollectionItemPropertyChanged(this, new SettingsChangedEventArgs<TKey, TItem>(changeType));
}
}
/// <summary>
/// Fires collection change event
/// </summary>
/// <param name="changeType">type of change</param>
/// <param name="key">key</param>
private void FireItemChangedEvent(ChangeSettingType changeType, TKey key)
{
if (CollectionItemPropertyChanged != null)
{
CollectionItemPropertyChanged(this, new SettingsChangedEventArgs<TKey, TItem>(changeType, key));
}
}
/// <summary>
/// Fires collection change event
/// </summary>
/// <param name="changeType">type of change</param>
/// <param name="key">key</param>
/// <param name="item">item</param>
private void FireItemChangedEvent(ChangeSettingType changeType, TKey key, TItem item)
{
if (CollectionItemPropertyChanged != null)
{
CollectionItemPropertyChanged(this, new SettingsChangedEventArgs<TKey, TItem>(changeType, key, item));
}
}
#endregion
}
}